From 7ea94c355deba1ba848279a769718a358fc00a19 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Mon, 23 May 2016 07:27:26 -0400 Subject: [PATCH 001/458] fix use item packet --- data/protocol.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index bb9cf99..8964c20 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -1416,12 +1416,12 @@ "type": "vector3" }, { - "name": "item", - "type": "slot" + "name": "slot", + "type": "i32" }, { - "name": "in_use", - "type": "i32" + "name": "item", + "type": "slot" } ] ], From 8109dbcdd8650d347bef491d2c2619018bc57e15 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Mon, 23 May 2016 07:28:36 -0400 Subject: [PATCH 002/458] update version to 2.2.3 --- HISTORY.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 29b2e26..33fcd28 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,6 @@ +## 2.2.3 +* fix the use item packet + ## 2.2.2 * fix the block update packet, for real this time diff --git a/package.json b/package.json index 2fefccb..6847f96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pocket-minecraft-protocol", - "version": "2.2.2", + "version": "2.2.3", "description": "Parse and serialize Minecraft PE packets", "main": "index.js", "scripts": { From de058638150e3fba55aa26eec3609b76bdfa1128 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Fri, 10 Jun 2016 02:26:23 +0200 Subject: [PATCH 003/458] use mcdata --- data/protocol.json | 1936 ---------------------------------- package.json | 1 + src/createClient.js | 2 +- src/createServer.js | 2 +- src/transforms/serializer.js | 2 +- 5 files changed, 4 insertions(+), 1939 deletions(-) delete mode 100644 data/protocol.json diff --git a/data/protocol.json b/data/protocol.json deleted file mode 100644 index 8964c20..0000000 --- a/data/protocol.json +++ /dev/null @@ -1,1936 +0,0 @@ -{ - "types": { - "string": [ - "pstring", - { - "countType":"i16" - } - ], - "lstring": [ - "pstring", - { - "countType":"li16" - } - ], - "shapeless_recipe": [ - "container", - [ - { - "name":"ingredientList", - "type": - [ - "array", - { - "countType":"i32", - "type":"slot" - } - ] - }, - { - "name": "result_count", - "type": "i32" - }, - { - "name": "slot", - "type": "slot" - }, - { - "name": "id", - "type": "uuid" - } - ] - ], - "shaped_recipe": [ - "container", - [ - { - "name": "width", - "type": [ - "count", { - "type": "i32", - "countFor": "shape" - } - ] - }, - { - "name": "height", - "type": [ - "count", - { - "type": "i32", - "countFor": "shape/0" - } - ] - }, - { - "name": "shape", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "slot" - } - ] - } - ] - }, - { - "name": "result_count", - "type": "i32" - }, - { - "name": "slot", - "type": "slot" - }, - { - "name": "id", - "type": "uuid" - } - ] - ], - "furnace_recipe": [ - "container", - [ - { - "name": "meta", - "type": "i16" - }, - { - "name": "id", - "type": "i16" - }, - { - "name": "result", - "type": "slot" - } - ] - ], - "furnace_recipe_data": [ - "container", - [ - { - "name": "id", - "type": "i16" - }, - { - "name": "meta", - "type": "i16" - }, - { - "name": "result", - "type": "slot" - } - ] - ], - "enchant_list": [ - "array", - { - "countType": "i8", - "type": [ - "container", - { - "name": "cost", - "type": "i32" - }, - { - "name": "enchantments", - "type": [ - "array", - { - "countType": "i8", - "type": [ - "container", - { - "name": "id", - "type": "i32" - }, - { - "name": "level", - "id": "i32" - } - ] - } - ] - }, - { - "name": "name", - "type": "string" - } - ] - } - ], - "entityMetadataItem": [ - "switch", - { - "compareTo": "$compareTo", - "fields": { - "0": "li8", - "1": "li16", - "2": "li32", - "3": "lf32", - "4": "lstring", - "5": ["container",[ - { - "name":"block_id", - "type":"li16" - }, - { - "name":"item_count", - "type":"li8" - }, - { - "name":"item_damage", - "type":"li16" - } - ]], - "6": [ - "container", - [ - { - "name": "x", - "type": "li32" - }, - { - "name": "y", - "type": "li32" - }, - { - "name": "z", - "type": "li32" - } - ] - ], - "7": [ - "container", - [ - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "roll", - "type": "lf32" - } - ] - ], - "8": "li64" - } - } - ], - "metadatadictionary": [ - "entityMetadataLoop", - { - "endVal": 127, - "type": [ - "container", - [ - { - "anon": true, - "type": [ - "bitfield", - [ - { - "name": "type", - "size": 3, - "signed": false - }, - { - "name": "key", - "size": 5, - "signed": false - } - ] - ] - }, - { - "name": "value", - "type": [ - "entityMetadataItem", - { - "compareTo": "type" - } - ] - } - ] - ] - } - ], - "slot": [ - "container", - [ - { - "name": "block_id", - "type": "i16" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "block_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "item_count", - "type": "i8" - }, - { - "name": "item_damage", - "type": "i16" - }, - { - "name": "nbt_data", - "type": ["buffer",{"countType":"li16"}] - } - ] - ] - } - ] - } - ] - ], - "itemstacks": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "slot", - "type": "slot" - } - ] - ] - } - ], - "skin": [ - "container", - [ - { - "name": "skin_type", - "type": "string" - }, - { - "name": "texture", - "type": ["buffer",{"countType":"i16"}] - } - ] - ], - "blockrecords": [ - "array", - { - "countType":"i32", - "type": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "y", - "type": "i8" - }, - { - "name": "block_id", - "type": "i8" - }, - { - "anon": true, - "type": [ - "bitfield", - [ - { - "name": "block_data", - "size": 4, - "signed": false - }, - { - "name": "flags", - "size": 4, - "signed": false - } - ] - ] - } - ] - ] - } - ], - "records": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "x", - "type": "i8" - }, - { - "name": "y", - "type": "i8" - }, - { - "name": "z", - "type": "i8" - } - ] - ] - } - ], - "playerattributes": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "min_value", - "type": "f32" - }, - { - "name": "max_value", - "type": "f32" - }, - { - "name": "id", - "type": "f32" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "entitymotions": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "eid", - "type": "i64" - }, - { - "name": "mot_x", - "type": "f32" - }, - { - "name": "mot_y", - "type": "f32" - }, - { - "name": "mot_z", - "type": "f32" - } - ] - ] - } - ], - "vector3": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - } - ] - ], - "blockcoordinates": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - } - ] - ], - "entitylocations": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "eid", - "type": "i64" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "head_yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - } - ] - ] - } - ], - "encapsulated_packet":[ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0x8e": "mcpe" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "mcpe":"mcpe_packet" - } - } - ] - } - ] - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0x04": "id_detect_lost_connections", - "0x14": "id_no_free_incoming_connections", - "0x17": "id_connection_banned", - "0x1A": "id_ip_recently_connected", - "0x8f": "game_login", - "0x90": "player_status", - "0x91": "disconnect", - "0x92": "batch", - "0x93": "text", - "0x94": "set_time", - "0x95": "start_game", - "0x96": "add_player", - "0x97": "remove_player", - "0x98": "add_entity", - "0x99": "remove_entity", - "0x9a": "add_item_entity", - "0x9b": "take_item_entity", - "0x9c": "move_entity", - "0x9d": "move_player", - "0x9e": "remove_block", - "0x9f": "update_block", - "0xa0": "add_painting", - "0xa1": "explode", - "0xa2": "level_event", - "0xa3": "tile_event", - "0xa4": "entity_event", - "0xa5": "mob_effect", - "0xa6": "update_attributes", - "0xa7": "player_equipment", - "0xa8": "player_armor_equipment", - "0xa9": "interact", - "0xaa": "use_item", - "0xab": "player_action", - "0xac": "hurt_armor", - "0xad": "set_entity_data", - "0xae": "set_entity_motion", - "0xaf": "set_entity_link", - "0xb0": "set_health", - "0xb1": "set_spawn_position", - "0xb2": "animate", - "0xb3": "respawn", - "0xb4": "drop_item", - "0xb5": "container_open", - "0xb6": "container_close", - "0xb7": "container_set_slot", - "0xb8": "container_set_data", - "0xb9": "container_set_content", - "0xba": "crafting_data", - "0xbb": "crafting_event", - "0xbc": "adventure_settings", - "0xbd": "tile_entity_data", - "0xbf": "full_chunk_data", - "0xc0": "set_difficulty", - "0xc3": "player_list", - "0xc8": "request_chunk_radius", - "0xc9": "chunk_radius_update", - "0x1b": "transfer", - "0xc5": "spawn_experience_orb" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "id_detect_lost_connections": "packet_id_detect_lost_connections", - "id_no_free_incoming_connections": "packet_id_no_free_incoming_connections", - "id_connection_banned": "packet_id_connection_banned", - "id_ip_recently_connected": "packet_id_ip_recently_connected", - "game_login": "packet_game_login", - "player_status": "packet_player_status", - "disconnect": "packet_disconnect", - "batch": "packet_batch", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "remove_player": "packet_remove_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "remove_block": "packet_remove_block", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "explode": "packet_explode", - "level_event": "packet_level_event", - "tile_event": "packet_tile_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "player_equipment": "packet_player_equipment", - "player_armor_equipment": "packet_player_armor_equipment", - "interact": "packet_interact", - "use_item": "packet_use_item", - "player_action": "packet_player_action", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "drop_item": "packet_drop_item", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "container_set_slot": "packet_container_set_slot", - "container_set_data": "packet_container_set_data", - "container_set_content": "packet_container_set_content", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "adventure_settings": "packet_adventure_settings", - "tile_entity_data": "packet_tile_entity_data", - "full_chunk_data": "packet_full_chunk_data", - "set_difficulty": "packet_set_difficulty", - "player_list": "packet_player_list", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "transfer": "packet_transfer", - "spawn_experience_orb": "packet_spawn_experience_orb" - } - } - ] - } - ] - ], - "packet_id_detect_lost_connections": [ - "container", - [] - ], - "packet_id_no_free_incoming_connections": [ - "container", - [] - ], - "packet_id_connection_banned": [ - "container", - [] - ], - "packet_id_ip_recently_connected": [ - "container", - [] - ], - "packet_game_login": [ - "container", - [ - { - "name": "username", - "type": "string" - }, - { - "name": "protocol", - "type": "i32" - }, - { - "name": "protocol2", - "type": "i32" - }, - { - "name": "client_id", - "type": "i64" - }, - { - "name": "client_uuid", - "type": "uuid" - }, - { - "name": "server_address", - "type": "string" - }, - { - "name": "client_secret", - "type": ["buffer",{"countType":"i16"}] - }, - { - "name": "skin", - "type": "skin" - } - ] - ], - "packet_player_status": [ - "container", - [ - { - "name": "status", - "type": "i32" - } - ] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "packet_batch": [ - "container", - [ - { - "name": "payload", - "type":["buffer",{"countType":"i32"}] - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": "i8" - }, - { - "name": "name", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "1": "string", - "3": "string" - }, - "default": "void" - } - ] - }, - { - "name": "message", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "0": "string", - "1": "string", - "2": "string", - "3": "string", - "4": "string", - "5": "string" - } - } - ] - }, - { - "name": "parameters", - "type": [ - "switch", - { - "compareTo": "type", - "fields":{ - "2":[ - "array", { - "countType":"i8", - "type":"string" - } - ] - }, - "default":"void" - } - ] - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "i32" - }, - { - "name": "started", - "type": "i8" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "seed", - "type": "i32" - }, - { - "name": "dimension", - "type": "i8" - }, - { - "name": "generator", - "type": "i32" - }, - { - "name": "gamemode", - "type": "i32" - }, - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "spawn_x", - "type": "i32" - }, - { - "name": "spawn_y", - "type": "i32" - }, - { - "name": "spawn_z", - "type": "i32" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "unknown1", - "type": "i8" - }, - { - "name": "unknown2", - "type": "i8" - }, - { - "name": "unknown3", - "type": "i8" - }, - { - "name": "unknown4", - "type": "string" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "speed_x", - "type": "f32" - }, - { - "name": "speed_y", - "type": "f32" - }, - { - "name": "speed_z", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "head_yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "item", - "type": "slot" - }, - { - "name": "metadata", - "type": "metadatadictionary" - } - ] - ], - "packet_remove_player": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "client_uuid", - "type": "uuid" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "entity_type", - "type": "i32" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "speed_x", - "type": "f32" - }, - { - "name": "speed_y", - "type": "f32" - }, - { - "name": "speed_z", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "metadata", - "type": "metadatadictionary" - }, - { - "name": "links", - "type": "i16" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "item", - "type": "slot" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "speed_x", - "type": "f32" - }, - { - "name": "speed_y", - "type": "f32" - }, - { - "name": "speed_z", - "type": "f32" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "target", - "type": "i64" - }, - { - "name": "entity_id", - "type": "i64" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "entities", - "type": "entitylocations" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "head_yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "mode", - "type": "i8" - }, - { - "name": "on_ground", - "type": "i8" - } - ] - ], - "packet_remove_block": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "y", - "type": "i8" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "blocks", - "type": "blockrecords" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "direction", - "type": "i32" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_explode": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "radius", - "type": "f32" - }, - { - "name": "records", - "type": "records" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event_id", - "type": "i16" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "data", - "type": "i32" - } - ] - ], - "packet_tile_event": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "case_1", - "type": "i32" - }, - { - "name": "case_2", - "type": "i32" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "event_id", - "type": "i8" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "event_id", - "type": "i8" - }, - { - "name": "effect_id", - "type": "i8" - }, - { - "name": "amplifier", - "type": "i8" - }, - { - "name": "particles", - "type": "i8" - }, - { - "name": "duration", - "type": "i32" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "attributes", - "type": "playerattributes" - } - ] - ], - "packet_player_equipment": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "item", - "type": "slot" - }, - { - "name": "slot", - "type": "i8" - }, - { - "name": "selected_slot", - "type": "i8" - } - ] - ], - "packet_player_armor_equipment": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "helmet", - "type": "slot" - }, - { - "name": "chestplate", - "type": "slot" - }, - { - "name": "leggings", - "type": "slot" - }, - { - "name": "boots", - "type": "slot" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": "i8" - }, - { - "name": "target_entity_id", - "type": "i64" - } - ] - ], - "packet_use_item": [ - "container", - [ - { - "name": "blockcoordinates", - "type": "blockcoordinates" - }, - { - "name": "face", - "type": "i8" - }, - { - "name": "facecoordinates", - "type": "vector3" - }, - { - "name": "playerposition", - "type": "vector3" - }, - { - "name": "slot", - "type": "i32" - }, - { - "name": "item", - "type": "slot" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "action_id", - "type": "i32" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "face", - "type": "i32" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "i8" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "metadata", - "type": "metadatadictionary" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "entities", - "type": "entitymotions" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "rider_id", - "type": "i64" - }, - { - "name": "ridden_id", - "type": "i64" - }, - { - "name": "link_type", - "type": "i8" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "i32" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": "i8" - }, - { - "name": "entity_id", - "type": "i64" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - } - ] - ], - "packet_drop_item": [ - "container", - [ - { - "name": "itemtype", - "type": "i8" - }, - { - "name": "item", - "type": "slot" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "i8" - }, - { - "name": "type", - "type": "i8" - }, - { - "name": "slot_count", - "type": "i16" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "i8" - } - ] - ], - "packet_container_set_slot": [ - "container", - [ - { - "name": "window_id", - "type": "i8" - }, - { - "name": "slot", - "type": "i16" - }, - { - "name": "unknown", - "type": "i16" - }, - { - "name": "item", - "type": "slot" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "i8" - }, - { - "name": "property", - "type": "i16" - }, - { - "name": "value", - "type": "i16" - } - ] - ], - "packet_container_set_content": [ - "container", - [ - { - "name": "window_id", - "type": "i8" - }, - { - "name": "slot_data", - "type": "itemstacks" - }, - { - "name": "hotbar_data", - "type": [ - "switch", - { - "compareTo": "window_id", - "fields": { - "0": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "slot", - "type": "i32" - } - ] - ] - } - ] - }, - "default": "i16" - } - ] - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": [ - "container", - [ - { - "name": "entryType", - "type": "i32" - }, - { - "name": "recipe", - "type": [ - "array", - { - "countType": "i32", - "type": [ - "switch", - { - "compareTo": "entryType", - "fields": { - "0": "shapeless_recipe", - "1": "shaped_recipe", - "2": "furnace_recipe", - "3": "furnace_recipe_data", - "4": "enchant_list" - }, - "default":"void" - } - ] - } - ] - } - ] - ] - }, - { - "name": "cleanRecipes", - "type": "i8" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "i8" - }, - { - "name": "recipe_type", - "type": "i32" - }, - { - "name": "recipe_id", - "type": "uuid" - }, - { - "name": "input", - "type": "itemstacks" - }, - { - "name": "result", - "type": "itemstacks" - } - ] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "i32" - }, - { - "name": "user_permission", - "type": "i32" - }, - { - "name": "global_permission", - "type": "i32" - } - ] - ], - "packet_tile_entity_data": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "namedtag", - "type": "restBuffer" - } - ] - ], - "packet_full_chunk_data": [ - "container", - [ - { - "name": "chunk_x", - "type": "i32" - }, - { - "name": "chunk_z", - "type": "i32" - }, - { - "name": "order", - "type": "i8" - }, - { - "name": "chunk_data", - "type":["buffer",{"countType":"i32"}] - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "i32" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "type", - "type": "i8" - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "i32", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "0": [ - "container", - [ - { - "name": "client_uuid", - "type": "uuid" - }, - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "skin", - "type": "skin" - } - ] - ], - "1": [ - "container", - [ - { - "name": "client_uuid", - "type": "uuid" - } - ] - ] - } - } - ] - } - ] - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "i32" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "i32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "endpoint", - "type": "ipAddress" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "count", - "type": "i32" - } - ] - ] - } -} diff --git a/package.json b/package.json index 6847f96..64b98ca 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ ], "license": "MIT", "dependencies": { + "minecraft-data": "^2.4.0", "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", "raknet": "^1.7.3", diff --git a/src/createClient.js b/src/createClient.js index cace13d..f1be549 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -16,7 +16,7 @@ function createClient(options) { assert.ok(options.username, 'username is required'); - options.customPackets=require('../data/protocol'); + options.customPackets=require('minecraft-data')('pe_0.14').protocol; options.customTypes=require('./datatypes/minecraft'); var client=raknet.createClient(options); diff --git a/src/createServer.js b/src/createServer.js index 943f34f..88b47f8 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -14,7 +14,7 @@ function createServer(options) { 19132; var host = options.host || '0.0.0.0'; - options.customPackets=require("../data/protocol"); + options.customPackets=require('minecraft-data')('pe_0.14').protocol; options.customTypes=require("./datatypes/minecraft"); var server = raknet.createServer(options); diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index bda77e3..1471408 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -2,7 +2,7 @@ var ProtoDef = require('protodef').ProtoDef; var Serializer = require('protodef').Serializer; var Parser = require('protodef').Parser; -var protocol = require('../../data/protocol.json').types; +var protocol = require('minecraft-data')('pe_0.14').protocol; function createProtocol() { var proto = new ProtoDef(); From 39bf3d6aba245a75a87a1ea6d40e43b997859ca3 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Tue, 14 Jun 2016 07:51:41 -0400 Subject: [PATCH 004/458] update protocol to 0.15 and start jwt decryption --- README.md | 2 +- data/protocol.json | 216 +++++++++++++++++++++++++++------------------ jwt.js | 25 ++++++ package.json | 1 + 4 files changed, 156 insertions(+), 88 deletions(-) create mode 100644 jwt.js diff --git a/README.md b/README.md index ed407ea..813b64b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Parse and serialize Minecraft PE packets. ## Features - * Supports Minecraft PE `0.14.3` + * Supports Minecraft PE `0.14.3` and `0.15.0` * Pure JavaScript * Easily send and listen for any packet * RakNet support through [node-raknet](https://github.com/mhsjlw/node-raknet) diff --git a/data/protocol.json b/data/protocol.json index 8964c20..9d4a087 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -310,7 +310,7 @@ [ { "name": "slot", - "type": "slot" + "type": "itemstacks" } ] ] @@ -567,60 +567,63 @@ "0x14": "id_no_free_incoming_connections", "0x17": "id_connection_banned", "0x1A": "id_ip_recently_connected", - "0x8f": "game_login", - "0x90": "player_status", - "0x91": "disconnect", - "0x92": "batch", - "0x93": "text", - "0x94": "set_time", - "0x95": "start_game", - "0x96": "add_player", - "0x97": "remove_player", - "0x98": "add_entity", - "0x99": "remove_entity", - "0x9a": "add_item_entity", - "0x9b": "take_item_entity", - "0x9c": "move_entity", - "0x9d": "move_player", - "0x9e": "remove_block", - "0x9f": "update_block", - "0xa0": "add_painting", - "0xa1": "explode", - "0xa2": "level_event", - "0xa3": "tile_event", - "0xa4": "entity_event", - "0xa5": "mob_effect", - "0xa6": "update_attributes", - "0xa7": "player_equipment", - "0xa8": "player_armor_equipment", - "0xa9": "interact", - "0xaa": "use_item", - "0xab": "player_action", - "0xac": "hurt_armor", - "0xad": "set_entity_data", - "0xae": "set_entity_motion", - "0xaf": "set_entity_link", - "0xb0": "set_health", - "0xb1": "set_spawn_position", - "0xb2": "animate", - "0xb3": "respawn", - "0xb4": "drop_item", - "0xb5": "container_open", - "0xb6": "container_close", - "0xb7": "container_set_slot", - "0xb8": "container_set_data", - "0xb9": "container_set_content", - "0xba": "crafting_data", - "0xbb": "crafting_event", - "0xbc": "adventure_settings", - "0xbd": "tile_entity_data", - "0xbf": "full_chunk_data", - "0xc0": "set_difficulty", - "0xc3": "player_list", - "0xc8": "request_chunk_radius", - "0xc9": "chunk_radius_update", - "0x1b": "transfer", - "0xc5": "spawn_experience_orb" + "0x03": "server_to_client_handshake", + "0x04": "client_to_server_handshake", + "0x01": "game_login", + "0x02": "player_status", + "0x05": "disconnect", + "0x06": "batch", + "0x07": "text", + "0x08": "set_time", + "0x09": "start_game", + "0x0a": "add_player", + "0x0b": "remove_player", + "0x0c": "add_entity", + "0x0d": "remove_entity", + "0x0e": "add_item_entity", + "0x0f": "take_item_entity", + "0x10": "move_entity", + "0x11": "move_player", + "0x12": "remove_block", + "0x13": "update_block", + "0x14": "add_painting", + "0x15": "explode", + "0x16": "level_event", + "0x17": "tile_event", + "0x18": "entity_event", + "0x19": "mob_effect", + "0x1a": "update_attributes", + "0x1b": "player_equipment", + "0x1c": "player_armor_equipment", + "0x1d": "interact", + "0x1e": "use_item", + "0x1f": "player_action", + "0x20": "hurt_armor", + "0x21": "set_entity_data", + "0x22": "set_entity_motion", + "0x23": "set_entity_link", + "0x24": "set_health", + "0x25": "set_spawn_position", + "0x26": "animate", + "0x27": "respawn", + "0x28": "drop_item", + "0x29": "container_open", + "0x2a": "container_close", + "0x2b": "container_set_slot", + "0x2c": "container_set_data", + "0x2d": "container_set_content", + "0x2e": "crafting_data", + "0x2f": "crafting_event", + "0x30": "adventure_settings", + "0x31": "tile_entity_data", + "0x32": "player_input", + "0x33": "full_chunk_data", + "0x34": "set_difficulty", + "0x37": "player_list", + "0x3c": "request_chunk_radius", + "0x3d": "chunk_radius_update", + "0x3a": "spawn_experience_orb", + "0x3f": "replace_selected_item" } } ] @@ -636,6 +639,8 @@ "id_no_free_incoming_connections": "packet_id_no_free_incoming_connections", "id_connection_banned": "packet_id_connection_banned", "id_ip_recently_connected": "packet_id_ip_recently_connected", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", "game_login": "packet_game_login", "player_status": "packet_player_status", "disconnect": "packet_disconnect", @@ -689,7 +694,8 @@ "request_chunk_radius": "packet_request_chunk_radius", "chunk_radius_update": "packet_chunk_radius_update", "transfer": "packet_transfer", - "spawn_experience_orb": "packet_spawn_experience_orb" + "spawn_experience_orb": "packet_spawn_experience_orb", + "replace_selected_item": "packet_replace_selected_item" } } ] @@ -712,40 +718,50 @@ "container", [] ], + "server_to_client_handshake": [ + "container", + [ + { + "name": "public_key", + "type": "string" + }, + { + "name": "server_token", + "type": "string" + } + ] + ], + "client_to_server_handshake": [ + "container", + [ + { + "name": "magic", + "type": "i64" + } + ] + ], "packet_game_login": [ "container", [ { - "name": "username", - "type": "string" + "name": "unknown", + "type": "short" }, { "name": "protocol", + "type": "long" + }, + { + "name": "body_length", "type": "i32" }, { - "name": "protocol2", - "type": "i32" + "name": "chain", + "type": ["pstring", {"countType": "li32"}] }, { - "name": "client_id", - "type": "i64" - }, - { - "name": "client_uuid", - "type": "uuid" - }, - { - "name": "server_address", - "type": "string" - }, - { - "name": "client_secret", - "type": ["buffer",{"countType":"i16"}] - }, - { - "name": "skin", - "type": "skin" + "name": "client_data", + "type": ["pstring", {"countType": "li32"}] } ] ], @@ -864,7 +880,7 @@ }, { "name": "gamemode", - "type": "i32" + "type": "i8" }, { "name": "entity_id", @@ -895,19 +911,19 @@ "type": "f32" }, { - "name": "unknown1", + "name": "is_loaded_in_creative", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", "type": "i8" }, { - "name": "unknown2", - "type": "i8" + "name": "edu_mode", + "type": "bool" }, { - "name": "unknown3", - "type": "i8" - }, - { - "name": "unknown4", + "name": "unknown", "type": "string" } ] @@ -1794,6 +1810,23 @@ } ] ], + "packet_player_input": [ + "container", + [ + { + "name": "motion_x", + "type": "f32" + }, + { + "name": "motion_z", + "type": "f32" + }, + { + "name": "flags", + "type": "short" + } + ] + ], "packet_full_chunk_data": [ "container", [ @@ -1931,6 +1964,15 @@ "type": "i32" } ] + ], + "packet_replace_selected_item": [ + "container", + [ + { + "name": "slot", + "type": "slot" + } + ] ] } } diff --git a/jwt.js b/jwt.js new file mode 100644 index 0000000..7d14499 --- /dev/null +++ b/jwt.js @@ -0,0 +1,25 @@ +var jwt = require('jwt-simple'); +var example = { + "chain": { + "chain": [ + "eyJ4NXUiOiJNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRThFTGtpeHlMY3dsWnJ5VVFjdTFUdlBPbUkyQjd2WDgzbmRuV1JVYVhtNzR3RmZhNWZcL2x3UU5UZnJMVkhhMlBtZW5wR0k2SmhJTVVKYVdacmptTWo5ME5vS05GU05CdUtkbThyWWlYc2ZhejNLMzZ4XC8xVTI2SHBHMFp4S1wvVjFWIiwiYWxnIjoiRVMzODQifQ.eyJuYmYiOjE0NjA4OTYzMzcsInJhbmRvbU5vbmNlIjo3MzI2MDA4MDM2OTAzODU5NzM0LCJpc3MiOiJSZWFsbXNBdXRob3JpemF0aW9uIiwiZXhwIjoxNDYwOTgyNzk3LCJpYXQiOjE0NjA4OTYzOTcsImNlcnRpZmljYXRlQXV0aG9yaXR5Ijp0cnVlLCJpZGVudGl0eVB1YmxpY0tleSI6Ik1IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFQlJ1MEd5VUFkYkZjd1wvUU1vNmFBTGFaZHJTeVNkZFwva1F2OXFHOHlHSWxnc0orVStNMVVpZWtjaDFPc3NHdXlFZW1oSWR1OUZWYklJanRWKzY4bXVkc0orSE1MdGYrMDJTYVk0elBtXC9iR3RURkRIUDBRK2FoUmhvVWRiNVptaFwvIn0.J9vCSKZOH6ZuO_rMv3Tlo0Z7nAnXI44rdlL4FyXcWfdTHG3HlHywos0WLWnMnlxP_Ex2co2M21CSyIhIFM6EvugemsuEZIQpz3WTAmUlaEoaNT7dgGFbqGUn9tr6S1MD", + "eyJ4NXUiOiJNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRUJSdTBHeVVBZGJGY3dcL1FNbzZhQUxhWmRyU3lTZGRcL2tRdjlxRzh5R0lsZ3NKK1UrTTFVaWVrY2gxT3NzR3V5RWVtaElkdTlGVmJJSWp0Vis2OG11ZHNKK0hNTHRmKzAyU2FZNHpQbVwvYkd0VEZESFAwUSthaFJob1VkYjVabWhcLyIsImFsZyI6IkVTMzg0In0.eyJuYmYiOjE0NjA4OTYzMzcsImV4dHJhRGF0YSI6eyJpZGVudGl0eSI6Ijk4YjBjYmNmLWU5MWUtMzAwNC05NjUyLWFlZDkyZjhlMjU2ZCIsImRpc3BsYXlOYW1lIjoieWF3a2F0IiwiWFVJRCI6IjI1MzU0Mzc2MTMzNTc1MzUifSwicmFuZG9tTm9uY2UiOi0zMzg4NzY3NzYzMDEyODY5NTg3LCJpc3MiOiJSZWFsbXNBdXRob3JpemF0aW9uIiwiZXhwIjoxNDYwOTgyNzk3LCJpYXQiOjE0NjA4OTYzOTcsImlkZW50aXR5UHVibGljS2V5IjoiTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVERUtuZXFFdmNxVXFxRk1NMUhNMUE0eldqSkMrSThZK2FLekc1ZGwrNndOT0hIUTRObUcyUEVYUkpZaHVqeW9kRkgrd08wZEVyNEdNMVdvYVdvZzh4c1lRNm1RSkFDMGVWcEJNOTZzcFVCMWVNTjU2K0J3bEo0SDNReDRUQXZBcyJ9.gmAdOsTXU68QIqWweaU9FBuSyhNHcGI2hslrP0AQtVqGHyfPIhm54aUesZSj9mLGIIJTx_I50wijDlsj_lFExb3W3UQV0BDWCsYNBoJ5Kb9AX5O11onqtGbNynCVufJB" + ] + }, + "clientData": "eyJhbGciOiJFUzM4NCIsIng1dSI6Ik1IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFREVLbmVxRXZjcVVxcUZNTTFITTFBNHpXakpDK0k4WSthS3pHNWRsKzZ3Tk9ISFE0Tm1HMlBFWFJKWWh1anlvZEZIK3dPMGRFcjRHTTFXb2FXb2c4eHNZUTZtUUpBQzBlVnBCTTk2c3BVQjFlTU41NitCd2xKNEgzUXg0VEF2QXMifQo,.eyJDbGllbnRSYW5kb21JZCI6MTM2NTg2NDYwOCwiU2VydmVyQWRkcmVzcyI6IjE5Mi4xNjguMS41NjoxOTEzMiIsIlNraW5EYXRhIjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRGxtVWYvNVpsSC8rV05QLy9sbVVmLzVabEgvK1dOUC8vbG1VZi81WTAvLzlpQU12L1lnREwvMklBeS85aUFNdi9ZZ0RMLzJJQXkvOWlBTXYvWWdETC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBNVkwLy8rV1pSLy9salQvLzVabEgvK1daUi8vY2t6ei81WmxILytpZFRQL1lnREwvMklBeS82cUpYditxaVY3L3FvbGUvNnFKWHYvWWdETC8ySUF5L3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFPV1pSLy9ja3p6LzZKMU0vK1daUi8vbGpULy8zSk04LytXTlAvL2xtVWYvMklBeS82cUpYditjZTFEL25IdFEvNXg3VVArY2UxRC9xb2xlLzlpQU12OEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURsalQvLzNKTTgvK2lkVFAvbG1VZi81WmxILytXWlIvL2xqVC8vM0pNOC85aUFNditxaVY3L25IdFEvNXg3VVArY2UxRC9uSHRRLzZxSlh2L1lnREwvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQTVZMC8vK1dOUC8vb25Vei81WTAvLytXWlIvL2xqVC8vNkoxTS85eVRQUC9meHFQL3FvbGUvNXg3VVArY2UxRC9uSHRRLzV4N1VQK3FpVjcvMklBeS93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT1daUi8vbGpULy81WmxILytXTlAvL2NrenovNVpsSC8raWRUUC9vblV6LzM4YWovNnFKWHYrY2UxRC9uSHRRLzV4N1VQK2NlMUQvcW9sZS85aUFNdjhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEY2t6ei81WTAvLytXTlAvL2xtVWYvNVpsSC8rV1pSLy9salQvLzZKMU0vOS9Hby8rcWlWNy9xb2xlLzZxSlh2K3FpVjcvcW9sZS82cUpYdi9ZZ0RML0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE2SjFNLytXWlIvL2xqVC8vNkoxTS8raWRUUC9salQvLzZKMU0vOXlUUFAvZnhxUC8zOGFqLzkvR28vL2Z4cVAvMzhhai85L0dvLy9meHFQLzM4YWovd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRGxtVWYvNVkwLy8raWRUUC9sbVVmLzZKMU0vK2lkVFAvb25Vei81WTAvLytXWlIvL2xqVC8vNVpsSC8rV05QLy9salQvLzVabEgvK1dOUC8vbG1VZi81WmxILytXTlAvL2xtVWYvNVkwLy8rV1pSLy9salQvLzZKMU0vK1daUi8vbGpULy81WmxILytXTlAvL2xtVWYvNVkwLy8rV1pSLy9vblV6LzVZMC8vd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBNVkwLy8rV1pSLy9sbVVmLzVZMC8vK1daUi8vbGpULy81WTAvLytXWlIvL2xqVC8vNVpsSC8rV05QLy9sbVVmLzNKTTgvK1daUi8vbG1VZi81WTAvLytXWlIvL29uVXovNkoxTS8raWRUUC9salQvLzVabEgvK1dOUC8vbG1VZi82SjFNLytpZFRQL2xtVWYvNVkwLy8raWRUUC9vblV6LzVZMC8vK1daUi84QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFPaWRUUC9vblV6LzVZMC8vK1daUi8vbGpULy81WmxILytpZFRQL2xtVWYvNVpsSC8rV05QLy9sbVVmLzNKTTgvK3ZUcy8vcjA3UC81WmxILytXTlAvL29uVXovNVkwLy8rV05QLy9salQvLzZKMU0vK1daUi8vbGpULy82SjFNLytpZFRQL29uVXovNVkwLy8raWRUUC9sbVVmLzZKMU0vK1dOUC8vbG1VZi9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURsbVVmLzNKTTgvK1daUi8vbG1VZi82SjFNLzl5VFBQL2NrenovNVpsSC85eVRQUC9ja3p6LzNKTTgvK3ZUcy8veTJyci81TXVwLytUTHFmL2xtVWYvNVpsSC8rV1pSLy9ja3p6LzVabEgvK1dOUC8vb25Vei82SjFNLytXWlIvL2xqVC8vNkoxTS8rV05QLy9vblV6LzVabEgvK1dOUC8vbG1VZi81WTAvL3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQTNKTTgvK1daUi8vbG1VZi81WmxILzl5VFBQL3IwN1AvNjlPei85eVRQUC9reTZuLysvdjcveU5pSlAveTJyci84dDNDL3lOaUpQLzcrL3YvNU11cC85eVRQUC9salQvLzVabEgvK1daUi8vbG1VZi81WTAvLytXWlIvL2xqVC8vNVpsSC8rV05QLy9sbVVmLzVabEgvK2lkVFAvbG1VZi81WmxILytpZFRQOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBTnlUUFAvbGpULy82SjFNLzl5VFBQL3IwN1AvOHQzQy8vTGF1di95MnJyLzd0YTIvKy9adS8veTJyci84dDNDLy9MYXV2L3kyNzMvN3RlNS8vTGF1di9yMDdQLzNKTTgvK1daUi8vbGpULy81WmxILytXWlIvL29uVXovNVkwLy8rV05QLy9vblV6LzVabEgvK1dOUC8vbGpULy82SjFNLytXWlIvL2xtVWYvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEbGpULy81WmxILytpZFRQL2xtVWYvNjlPei8vTGF1di95M2NMLzh0M0MvL0xhdXYveTNjTC84dHE2LysrN3NmL3Z1N0gvOHRxNi8vTGF1di9yMDdQLzh0M0MvK3ZUcy8vY2t6ei81WTAvLytXWlIvL2xqVC8vNVpsSC8raWRUUC9salQvLzVZMC8vK1dOUC8vbG1VZi82SjFNLytXWlIvL2xtVWYvNVkwLy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE1WmxILytXTlAvL2xtVWYvNjlPei8rdlRzLy95M2NMLzh0cTYvL0xhdXYveTJyci84dHE2Ly9MZHd2L3kycnIvOHRxNi8vTGR3di95M2NMLzh0cTYvK3ZUcy8vY2t6ei81WTAvLytXWlIvL2xtVWYvNVkwLy8rV1pSLy9salQvLzVabEgvK1dOUC8vb25Vei81WmxILytXWlIvL2NrenovNVkwLy8raWRUUDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJrUVN6L1pFRXMvMlJCTFA5a1FTei9LQ2dvL3lnb0tQOG9LQ2ovS0Nnby93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZXJWMy80YUhZZi9ZZ0RMLzJJQXkvOWlBTXYvWWdETC82SjFNLytXWlIvOW9SVEQvYUVVdy8yaEZNUDlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3L3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFlcTkzLzNxdmQvOTZyM2YvMkxxVS8rdlRzLy9ZdXBUL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVpFRXMvMlJCTFA5a1FTei9aRUVzL3lnb0tQOG9LQ2ovS0Nnby95Z29LUDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFIcTFkLytHaDJIL2hvZGgvNGFIWWYrR2gySC8ySUF5LytXWlIvL29uVXovYUVVdy8yaEZNUDlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3LzJoRk1QOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUhxdmQvOTZ0WGYvZXE5My85aTZsUC9yMDdQLzJMcVUvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBR1JCTFA5a1FTei9aRUVzLzJSQkxQOG9LQ2ovS0Nnby95Z29LUDhvS0NqL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUI2dFhmL2hvZGgvNGFIWWYvZnhxUC8zOGFqLzRhSFlmL2xtVWYvNkoxTS8yaEZNUDlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3LzJoRk1QOW9SVEQvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQjZyM2YvZXJWMy8zcXZkLy9yMDdQLzJMcVUvK3ZUcy84QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCa1FTei9aRUVzLzJSQkxQOWtRU3ovS0Nnby95Z29LUDhvS0NqL0tDZ28vd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWVyVjMvNGFIWWYvcjA3UC84dHE2Ly9MYXV2L2xtVWYvNVpsSC8rV05QLzlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3LzJoRk1QOW9SVEQvYUVVdy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZXE5My8zcXZkLzk2cjNmLzY5T3ovOWk2bFAvcjA3UC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUI2cjNmL2VyVjMvM3ExZC85NnIzZi9hRVV3LzNsVlBmK0FXa0QvYlVvei8yaEZNUDlrUVN6L2FFVXcvMlJCTFArTXZvci9qTDZLLzMyeWV2OTlzbnIvZXJWMy8zcTFkLzk2dFhmL2VxOTMvNHkraXYrR2gySC82OU96Ly9MYXV2L3kycnIvNkoxTS8raWRUUC9salQvLzZKMU0vK2lkVFAvbG1VZi82SjFNLytpZFRQL29uVXovNVpsSC8rV05QLy9sbVVmLzVabEgvNEcxZi8rTHVvai9lcTkzLzNxMWQvOTZyM2YvZXE5My80eStpditMdW9qL2ZiSjYvM3F2ZC85NnRYZi9lclYzLzNxdmQvK0x1b2ovakw2Sy80dTZpUDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVpFRXMvM3F2ZC85NnIzZi9hRVV3LzNKT052OTVWVDMvZVZVOS8yaEZNUDlrUVN6L2FFVXcvMmhGTVA5a1FTei9iMHcxLzRCYVFQK0FXa0QvY2s0Mi8zcTFkLzk2dFhmL2VxOTMvM3F2ZC8rTXZvci9pb3RtLyt2VHMvL3kycnIvOHRxNi8vTGF1di9sbVVmLzZKMU0vK1daUi8vbG1VZi9lcTkzLzNxdmQvL2xtVWYvNVkwLy8rV05QLy9sbVVmL2diVi8vNEcxZi8rTHVvai9pN3FJLzNxdmQvOTZyM2YvZXE5My8zcTFkLytMdW9qL2ZiSjYvNHkraXY5NnRYZi9lclYzLzNxdmQvOTZyM2YvaTdxSS80dTZpUCtNdm9yL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBR1JCTFA5b1JURC9aRUVzLzJoRk1QOXZURFgvZ0ZwQS8yaEZNUDl5VGpiL1pFRXMvMmhGTVA5a1FTei9hRVV3LzI5TU5mK0FXa0QvZVZVOS8zSk9Odjk2cjNmL2VyVjMvM3F2ZC85NnIzZi9qTDZLLzMyeWV2K01qV2ovNjlPei8rdlRzLy9salQvLzVabEgvK2lkVFA5NnIzZi9lcTkzLzNxdmQvOTZ0WGYvZ2JWLy80RzFmLytCdFgvL2diVi8vNHkraXYrTHVvai9pN3FJLzR1NmlQOTZyM2YvZXJWMy8zcTFkLzk2dFhmL2k3cUkvNHkraXYrTHVvai9lcTkzLzNxMWQvOTZ0WGYvZXE5My80eStpditMdW9qL2pMNksvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCa1FTei9aRUVzLzJSQkxQOW9SVEQvYUVVdy8yaEZNUDk1VlQzL2NrNDIvMlJCTFA5b1JURC9aRUVzLzJoRk1QOXZURFgvZ0ZwQS8zbFZQZjl5VGpiL2VxOTMvM3ExZC85NnIzZi9lcTkzLzNldmRmK012b3Ivakw2Sy80eU5hUCtNaldqLzVabEgvK2lkVFA5OXNuci9lclYzLzNxMWQvOTZyM2YvZXJWMy80eStpditMdW9qL2pMNksvNHU2aVArTHVvai9pN3FJLzMyeWV2K0x1b2ovZ0lKYS80ZUpZditIaVdML2dJSmEvNGFIWWYrUGtHdi9ob2RoLzRDQ1d2K0hpV0wvaDRsaS80Q0NXditHaDJIL2o1QnIvNGFIWWY4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFaRUVzLzJSQkxQOWtRU3ovWkVFcy8yOU1OZitHWGtiL2hsNUcvMjlNTmY5a1FTei9aRUVzLzJSQkxQOWtRU3ovYUVVdy8yaEZNUDlvUlREL2FFVXcvM3F2ZC85NnRYZi9lclYzLzNxMWQvOTNyM1gvakw2Sy80eStpdjk5c25yL2pMNksvK2lkVFA5OXRIci9pN3FJLzNxdmQvOTZyM2YvZXE5My8zcTFkLytNdm9yL2k3cUkvNHkraXYrTHVvai9pN3FJLzR5K2l2K012b3Ivakw2Sy8rVEpxUC9reWFqLzVNbW8vK1RKcVAvcjA3UC82OU96Lyt2VHMvL2t5YWovNU1tby8rVEpxUC9reWFqLzY5T3ovK3ZUcy8vcjA3UC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURzN08vODdPenYvT3pzNy8yUkJMUDlvUlREL2VGUTgvM2hVUFA5b1JURC9aRUVzL3pzN08vODdPenYvT3pzNy8wWkdSdjlHUmtiL1JrWkcvMFpHUnY5NnIzZi9lclYzLzNxdmQvOTZ0WGYvZmJKNi80eStpditMdW9qL2pMNksvNHU2aVArTXZvci9pN3FJLzR1NmlQOTZyM2YvZXE5My8zcXZkLzk2cjNmL2k3cUkvMzJ5ZXYrTXZvci9pN3FJLzR1NmlQK012b3IvaTdxSS80eStpdi9reWFqLzVNbW8vK3ZUcy8vcjA3UC84dHE2Ly9MYXV2L3IwN1AvNjlPei8rdlRzLy9reWFqLzY5T3ovL0xhdXYvcjA3UC84dHE2L3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkpTVW4vU1VsSi8wbEpTZjg3T3p2L1dscGEvMTFkWGY5ZFhWMy9XbHBhL3pzN08vOUpTVW4vU1VsSi8wbEpTZjlOVFUzL1YxZFgvMWRYVi85TlRVMy9lcTkzLzNxMWQvOTZyM2YvZXJWMy80eStpditNdm9yL2ZiSjYvNHkraXYrTHVvai9qTDZLLzR1NmlQK012b3IvZXE5My8zcTFkLzk2cjNmL2VxOTMvNHU2aVArTXZvci9qTDZLLzR1NmlQK012b3IvZmJKNi80eStpditNdm9yLzVNbW8vK3ZUcy8vcjA3UC82OU96Ly9MYXV2L3kycnIvNmRDdi8rdlRzLy9zMUxqLzVNdXEvK3pVdVAveTJyci84dHE2Ly9MZHd2OEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBU1VsSi8wbEpTZjlKU1VuL1NVbEovMkZoWWY5cmEydi9hMnRyLzJGaFlmOUpTVW4vU1VsSi8wbEpTZjlKU1VuL1RVMU4vMWRYVi85WFYxZi9UVTFOLzNxMWQvOTZ0WGYvZXJWMy8zcTFkLytNdm9yL2pMNksvM2V2ZGYrTXZvci9mYko2LzR5K2l2K012b3Ivakw2Sy8zcXZkLzk2dFhmL2VyVjMvM3ExZC8rTXZvci9qTDZLLzR5K2l2OTlzbnIvakw2Sy8zMnllditNdm9yL2pMNksvK3pVdVAvcjA3UC83TlM0Lyt2VHMvL3AwYlAvOHRxNi8vTGF1di92MmIzLzdOUzQvK1hMcmYvdjJyLy84dHE2Ly9MYXV2L3AwYlAvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFbEpTZjlKU1VuL096czcvMGxKU2Y5aFlXSC9hMnRyLzJ0cmEvOWhZV0gvU1VsSi96czdPLzlKU1VuL1NVbEovMDFOVGY5WFYxZi9WMWRYLzAxTlRmOFlPQmIvR2o4Wi94ZzRGdjhhUHhuL1Q0Qk0vNHkraXY5M3IzWC9qTDZLLzNldmRmK012b3Ivakw2Sy8wK0FUUDhhUHhuL0dqOFoveGc0RnY4YVB4bi9UNEJNLzR5K2l2K012b3IvZDdCMC80eStpdjkzcjNYL2pMNksvMCtBVFAvczFMai83TlM0Lyt6VXVQL3MxTGovNmRHei8vTGR3di95M2NMLzdOUzQvKy9hdi8vczFMai83TlM0Ly9MZHd2L3kzY0wvOHQzQy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJOVFUzL1RVMU4vMUpTVXY4N096di9XbHBhLzJOalkvOWpZMlAvV2xwYS96czdPLzlTVWxML1RVMU4vMDFOVGY5S1Nrci9VRkJRLzFCUVVQOUtTa3IvZXJWMy8zcXZkLzk2dFhmL2VxOTMveGc0RnY4WU9CYi9HRGdXL3hvL0dmOGFQeG4vR0RnVy94ZzRGdjhhUHhuL2VxOTMvM3F2ZC85NnRYZi9lclYzL3hvL0dmOFlPQmIvR0RnVy94by9HZjhhUHhuL0dEZ1cveG8vR2Y4YVB4bi83TlM0Lyt6VXVQL3Yyci8vNzlxLy8vTGR3di95M2NMLzh0L0kvK3pVdVAvdjJyLy83TlM0Lyt6VXVQL3kzOGovOHQzQy8rclV1UDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVRVMU4vMDFOVGY5U1VsTC9YRnhjLzJGaFlmOXJhMnYvYTJ0ci8yRmhZZjljWEZ6L1VsSlMvMDFOVGY5TlRVMy9Ta3BLLzFCUVVQOVFVRkQvU2twSy8zcTFkLzk2cjNmL2VyVjMvM3F2ZC8rTHVvai9qTDZLLzR1NmlQK012b3IvZmJKNi80dTZpUCtMdW9qL2pMNksvM3F2ZC85NnIzZi9lclYzLzNxdmQvK0x1b2ovakw2Sy80eStpdjk5c25yL2pMNksvNHU2aVArTHVvai9qTDZLLysvYXYvL3Yyci8vN05TNC8rL2F2Ly95MzhqLzh0L0kvL0xkd3YvdjJyLy83OXEvLysvYXYvL3MxTGovOHQvSS8vTGR3di95M2NML0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRDgvUC84L1B6Ly9QejgvLzF4Y1hQOWpZMlAvY0hCdy8zQndjUDlqWTJQL1hGeGMvejgvUC84L1B6Ly9QejgvLzBoSVNQOU1URXovVEV4TS8waElTUDk2cjNmL2VyVjMvM3ExZC85NnIzZi9pN3FJLzJoRk1QOTFVRGovZFZBNC8zVlFPUDkxVURqL2FFVXcvNHU2aVA5NnRYZi9lcTkzLzNxMWQvOTZyM2YvaTdxSS80eStpditNdm9yL2pMNksvNHkraXYrTXZvci9qTDZLLzR1NmlQL3MxTGovNzltOS8relV1UC92MnIvLzh0L0kvL0xkd3YveTNjTC83TlM0Lyt6VXVQL3Yyci8vN05TNC8vTGZ5UC95M2NMLzh0M0Mvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCa1FTei9aRUVzLzJSQkxQOWtRU3ovS0Nnby95Z29LUDhvS0NqL0tDZ28vd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQTZKMU0vM3ExZC85NnIzZi8yTHFVLyt2VHMvL1l1cFQvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFaRUVzLzJSQkxQOWtRU3ovWkVFcy95Z29LUDhvS0NqL0tDZ28veWdvS1A4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT1daUi8vb25Vei9lcTkzLzlpNmxQL3IwN1AvMkxxVS93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUdSQkxQOWtRU3ovWkVFcy8yUkJMUDhvS0NqL0tDZ28veWdvS1A4b0tDai9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEbG1VZi81WTAvLzNxdmQvL3IwN1AvMkxxVS8rdlRzLzhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQmtRU3ovWkVFcy8yUkJMUDlrUVN6L0tDZ28veWdvS1A4b0tDai9LQ2dvL3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE1WTAvLzNxMWQvOTZyM2YvNjlPei85aTZsUC9yMDdQL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCb1JURC9aRUVzLzJoRk1QOWtRU3ovYlVvei80QmFRUDk1VlQzL2FFVXcvMmhGTVA5a1FTei9hRVV3LzJSQkxQOXZURFgvZmJKNi80eStpditNdm9yL2VxOTMvM3ExZC85NnIzZi81WmxILytXTlAvK0x1b2ovaTdxSS8zcXZkLzk2cjNmL2VxOTMvM3F2ZC8rTHVvai9qTDZLLytXTlAvOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFaRUVzLzJoRk1QOWtRU3ovYUVVdy8yaEZNUDk1VlQzL2VWVTkvM0pPTnY5a1FTei9hRVV3LzJoRk1QOWtRU3ovYjB3MS80QmFRUCtBV2tEL2NrNDIvM3F2ZC85NnIzZi9lcTkzLytpZFRQL2xtVWYvaTdxSS80dTZpUDk2cjNmL2VyVjMvM3F2ZC85NnIzZi9pN3FJLzR1NmlQK012b3IvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUdSQkxQOW9SVEQvWkVFcy8yaEZNUDl5VGpiL2FFVXcvNEJhUVA5dlREWC9aRUVzLzJoRk1QOWtRU3ovYUVVdy8yOU1OZitBV2tEL2VWVTkvM0pPTnY5NnIzZi9lclYzLzNxMWQvOTZ0WGYvaTdxSS80eStpdjk5c25yL2VxOTMvM3ExZC85NnRYZi9lcTkzLzR5K2l2K0x1b2ovakw2Sy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQmtRU3ovWkVFcy8yUkJMUDlvUlREL2NrNDIvM2xWUGY5b1JURC9hRVV3LzJSQkxQOW9SVEQvWkVFcy8yaEZNUDl2VERYL2dGcEEvM2xWUGY5eVRqYi9nSUphLzRlSll2K0hpV0wvZ0lKYS80YUhZZitQa0d2L2hvZGgvNENDV3YrSGlXTC9oNGxpLzRDQ1d2K0doMkgvajVCci80YUhZZjhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBWkVFcy8yUkJMUDlrUVN6L1pFRXMvMjlNTmYrR1hrYi9obDVHLzI5TU5mOWtRU3ovWkVFcy8yUkJMUDlrUVN6L2FFVXcvMmhGTVA5b1JURC9hRVV3LytUSnFQL2t5YWovNU1tby8rVEpxUC9yMDdQLzY5T3ovK3ZUcy8va3lhai81TW1vLytUSnFQL2t5YWovNjlPei8rdlRzLy9yMDdQL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEczdPLzg3T3p2L096czcvMlJCTFA5b1JURC9lRlE4LzNoVVBQOW9SVEQvWkVFcy96czdPLzg3T3p2L096czcvMFpHUnY5R1JrYi9Sa1pHLzBaR1J2L2t5YWovNU1tby8rdlRzLy9yMDdQLzh0cTYvL0xhdXYvcjA3UC82OU96Lyt2VHMvL2t5YWovNjlPei8vTGF1di9yMDdQLzh0cTYvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJKU1VuL1NVbEovMGxKU2Y4N096di9XbHBhLzExZFhmOWRYVjMvV2xwYS96czdPLzlKU1VuL1NVbEovMGxKU2Y5TlRVMy9WMWRYLzFkWFYvOU5UVTMvNU1tby8rdlRzLy9yMDdQLzY5T3ovL0xhdXYveTJyci84dHE2Lyt2VHMvL3MxTGovNjlPei8relV1UC95MnJyLzh0cTYvL0xkd3Y4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVNVbEovMGxKU2Y5SlNVbi9TVWxKLzJGaFlmOXJhMnYvYTJ0ci8yRmhZZjlKU1VuL1NVbEovMGxKU2Y5SlNVbi9UVTFOLzFkWFYvOVhWMWYvVFUxTi8relV1UC9yMDdQLzdOUzQvKy9admYvcDBiUC84dHE2Ly9MYXV2L3IwN1AvN05TNC8rWExyZi9zMUxqLzh0cTYvL0xhdXYveTNjTC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRWxKU2Y5SlNVbi9PenM3LzBsSlNmOWhZV0gvYTJ0ci8ydHJhLzloWVdIL1NVbEovenM3Ty85SlNVbi9TVWxKLzAxTlRmOVhWMWYvVjFkWC8wMU5UZi9zMUxqLzdOUzQvK3pVdVAvczFMai82ZEd6Ly9MZHd2L3kzY0wvN05TNC8relV1UC9zMUxqLzdOUzQvK25Scy8veTNjTC84dDNDL3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCTlRVMy9UVTFOLzFKU1V2ODdPenYvV2xwYS8yTmpZLzlqWTJQL1dscGEvenM3Ty85U1VsTC9UVTFOLzAxTlRmOUtTa3IvVUZCUS8xQlFVUDlLU2tyLzdOUzQvK3pVdVAvdjJyLy83TlM0Ly9MZHd2L3kzY0wvNmRHei8relV1UC9zMUxqLzc5cS8vK3pVdVAveTNjTC84dDNDLy9MZHd2OEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFUVTFOLzAxTlRmOVNVbEwvWEZ4Yy8yRmhZZjlyYTJ2L2EydHIvMkZoWWY5Y1hGei9VbEpTLzAxTlRmOU5UVTMvU2twSy8xQlFVUDlRVUZEL1NrcEsvKy9hdi8vczFMai83OXEvLyt6VXVQL3kzY0wvOHQvSS8vTGR3di92MnIvLzdOUzQvK3pVdVAvdjJyLy84dDNDLy9MZnlQL3kzOGovQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUQ4L1AvOC9Qei8vUHo4Ly8xeGNYUDlqWTJQL2NIQncvM0J3Y1A5alkyUC9YRnhjL3o4L1AvOC9Qei8vUHo4Ly8waElTUDlNVEV6L1RFeE0vMGhJU1AvdjJyLy82OU96Lyt6VXVQL3MxTGovOHQvSS8vTGR3di95M2NMLzdOUzQvKy9hdi8vczFMai83TlM0Ly9MZHd2L3kzOGovOHQvSS93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBPT0iLCJTa2luSWQiOiJTdGFuZGFyZF9BbGV4In0K.gN2HJV9_WW1hvVj-gGKGJsCGEafIiGnTFgKRUKF2CqhiQk4dgB1dHFnZOglDN4VtW397jIPgs92ppMkyfZf8-09XQ87_o_eC1nvuscmBXt6Bn2UZQP_VYFqh_eCAXvCP" +} + + +var clientData = example.clientData; +var chain1 = example.chain.chain[0]; +var chain2 = example.chain.chain[1]; +var secret = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; + +var decode1 = jwt.decode(chain1, secret, 'ES384'); +var nextKey1 = decode1.identityPublicKey; + +var decode2 = jwt.decode(chain2, nextKey1, 'ES384'); +var nextKey2 = decode2.identityPublicKey; + +var clientDecode = jwt.decode(clientData, nextKey1, 'ES384'); +console.log(clientDecode); diff --git a/package.json b/package.json index 6847f96..1d4c196 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ ], "license": "MIT", "dependencies": { + "jwt-simple": "^0.5.0", "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", "raknet": "^1.7.3", From 5b9ec7a1b6b3a4b0c4eb7d417689e5416f0fdf37 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Tue, 14 Jun 2016 17:47:33 -0400 Subject: [PATCH 005/458] merge protocol with the mc-data to make fields in-sync --- data/protocol.json | 98 +++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 9d4a087..1454610 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -27,7 +27,7 @@ ] }, { - "name": "result_count", + "name": "resultCount", "type": "i32" }, { @@ -79,7 +79,7 @@ ] }, { - "name": "result_count", + "name": "resultCount", "type": "i32" }, { @@ -132,34 +132,38 @@ "countType": "i8", "type": [ "container", - { - "name": "cost", - "type": "i32" - }, - { - "name": "enchantments", - "type": [ - "array", - { - "countType": "i8", - "type": [ - "container", - { - "name": "id", - "type": "i32" - }, - { - "name": "level", - "id": "i32" - } - ] - } - ] - }, - { - "name": "name", - "type": "string" - } + [ + { + "name": "cost", + "type": "i32" + }, + { + "name": "enchantments", + "type": [ + "array", + { + "countType": "i8", + "type": [ + "container", + [ + { + "name": "id", + "type": "i32" + }, + { + "name": "level", + "type": "i32" + } + ] + ] + } + ] + }, + { + "name": "name", + "type": "string" + } + ] ] } ], @@ -175,15 +179,15 @@ "4": "lstring", "5": ["container",[ { - "name":"block_id", + "name":"blockId", "type":"li16" }, { - "name":"item_count", + "name":"itemCount", "type":"li8" }, { - "name":"item_damage", + "name":"itemDamage", "type":"li16" } ]], @@ -267,7 +271,7 @@ "container", [ { - "name": "block_id", + "name": "blockId", "type": "i16" }, { @@ -275,7 +279,7 @@ "type": [ "switch", { - "compareTo": "block_id", + "compareTo": "blockId", "fields": { "0": "void" }, @@ -283,15 +287,15 @@ "container", [ { - "name": "item_count", + "name": "itemCount", "type": "i8" }, { - "name": "item_damage", + "name": "itemDamage", "type": "i16" }, { - "name": "nbt_data", + "name": "nbtData", "type": ["buffer",{"countType":"li16"}] } ] @@ -332,7 +336,7 @@ "blockrecords": [ "array", { - "countType":"i32", + "countType":"i16", "type": [ "container", [ @@ -348,17 +352,13 @@ "name": "y", "type": "i8" }, - { - "name": "block_id", - "type": "i8" - }, { "anon": true, "type": [ "bitfield", [ { - "name": "block_data", + "name": "blockData", "size": 4, "signed": false }, @@ -405,11 +405,11 @@ "container", [ { - "name": "min_value", + "name": "minValue", "type": "f32" }, { - "name": "max_value", + "name": "maxValue", "type": "f32" }, { @@ -436,15 +436,15 @@ "type": "i64" }, { - "name": "mot_x", + "name": "motX", "type": "f32" }, { - "name": "mot_y", + "name": "motY", "type": "f32" }, { - "name": "mot_z", + "name": "motZ", "type": "f32" } ] From 712d44bcad3e3f9d4cd38a01f82e224102eb3c3c Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Tue, 14 Jun 2016 17:51:49 -0400 Subject: [PATCH 006/458] oops, fix one protocol error --- data/protocol.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/protocol.json b/data/protocol.json index 1454610..a6fcdb4 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -336,7 +336,7 @@ "blockrecords": [ "array", { - "countType":"i16", + "countType":"i32", "type": [ "container", [ From f07c69176ebde73a6ba5b1750903f38ab8b2925e Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Tue, 14 Jun 2016 18:00:29 -0400 Subject: [PATCH 007/458] remove a bunch of errors in the protocol and keep the standard --- data/protocol.json | 178 +++++++++++++++++++++++---------------------- 1 file changed, 91 insertions(+), 87 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index a6fcdb4..237d217 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -352,6 +352,10 @@ "name": "y", "type": "i8" }, + { + "name": "blockId", + "type": "i8" + }, { "anon": true, "type": [ @@ -513,7 +517,7 @@ "type": "f32" }, { - "name": "head_yaw", + "name": "headYaw", "type": "f32" }, { @@ -722,11 +726,11 @@ "container", [ { - "name": "public_key", + "name": "publicKey", "type": "string" }, { - "name": "server_token", + "name": "serverToken", "type": "string" } ] @@ -752,7 +756,7 @@ "type": "long" }, { - "name": "body_length", + "name": "bodyLength", "type": "i32" }, { @@ -760,7 +764,7 @@ "type": ["pstring", {"countType": "li32"}] }, { - "name": "client_data", + "name": "clientData", "type": ["pstring", {"countType": "li32"}] } ] @@ -883,19 +887,19 @@ "type": "i8" }, { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { - "name": "spawn_x", + "name": "spawnX", "type": "i32" }, { - "name": "spawn_y", + "name": "spawnY", "type": "i32" }, { - "name": "spawn_z", + "name": "spawnZ", "type": "i32" }, { @@ -911,15 +915,15 @@ "type": "f32" }, { - "name": "is_loaded_in_creative", + "name": "isLoadedInCreative", "type": "bool" }, { - "name": "day_cycle_stop_time", + "name": "dayCycleStopTime", "type": "i8" }, { - "name": "edu_mode", + "name": "eduMode", "type": "bool" }, { @@ -940,7 +944,7 @@ "type": "string" }, { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -956,15 +960,15 @@ "type": "f32" }, { - "name": "speed_x", + "name": "speedX", "type": "f32" }, { - "name": "speed_y", + "name": "speedY", "type": "f32" }, { - "name": "speed_z", + "name": "speedZ", "type": "f32" }, { @@ -972,7 +976,7 @@ "type": "f32" }, { - "name": "head_yaw", + "name": "headYaw", "type": "f32" }, { @@ -993,11 +997,11 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { - "name": "client_uuid", + "name": "clientUuid", "type": "uuid" } ] @@ -1006,11 +1010,11 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { - "name": "entity_type", + "name": "entityType", "type": "i32" }, { @@ -1026,15 +1030,15 @@ "type": "f32" }, { - "name": "speed_x", + "name": "speedX", "type": "f32" }, { - "name": "speed_y", + "name": "speedY", "type": "f32" }, { - "name": "speed_z", + "name": "speedZ", "type": "f32" }, { @@ -1059,7 +1063,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" } ] @@ -1068,7 +1072,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -1088,15 +1092,15 @@ "type": "f32" }, { - "name": "speed_x", + "name": "speedX", "type": "f32" }, { - "name": "speed_y", + "name": "speedY", "type": "f32" }, { - "name": "speed_z", + "name": "speedZ", "type": "f32" } ] @@ -1109,7 +1113,7 @@ "type": "i64" }, { - "name": "entity_id", + "name": "entityId", "type": "i64" } ] @@ -1127,7 +1131,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -1147,7 +1151,7 @@ "type": "f32" }, { - "name": "head_yaw", + "name": "headYaw", "type": "f32" }, { @@ -1159,7 +1163,7 @@ "type": "i8" }, { - "name": "on_ground", + "name": "onGround", "type": "i8" } ] @@ -1168,7 +1172,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -1198,7 +1202,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -1252,7 +1256,7 @@ "container", [ { - "name": "event_id", + "name": "eventId", "type": "i16" }, { @@ -1289,11 +1293,11 @@ "type": "i32" }, { - "name": "case_1", + "name": "case1", "type": "i32" }, { - "name": "case_2", + "name": "case2", "type": "i32" } ] @@ -1302,11 +1306,11 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { - "name": "event_id", + "name": "eventId", "type": "i8" } ] @@ -1315,15 +1319,15 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { - "name": "event_id", + "name": "eventId", "type": "i8" }, { - "name": "effect_id", + "name": "effectId", "type": "i8" }, { @@ -1344,7 +1348,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -1357,7 +1361,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -1369,7 +1373,7 @@ "type": "i8" }, { - "name": "selected_slot", + "name": "selectedSlot", "type": "i8" } ] @@ -1378,7 +1382,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { @@ -1403,11 +1407,11 @@ "container", [ { - "name": "action_id", + "name": "actionId", "type": "i8" }, { - "name": "target_entity_id", + "name": "targetEntityId", "type": "i64" } ] @@ -1445,11 +1449,11 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { - "name": "action_id", + "name": "actionId", "type": "i32" }, { @@ -1505,15 +1509,15 @@ "container", [ { - "name": "rider_id", + "name": "riderId", "type": "i64" }, { - "name": "ridden_id", + "name": "riddenId", "type": "i64" }, { - "name": "link_type", + "name": "linkType", "type": "i8" } ] @@ -1548,11 +1552,11 @@ "container", [ { - "name": "action_id", + "name": "actionId", "type": "i8" }, { - "name": "entity_id", + "name": "entityId", "type": "i64" } ] @@ -1591,7 +1595,7 @@ "container", [ { - "name": "window_id", + "name": "windowId", "type": "i8" }, { @@ -1599,7 +1603,7 @@ "type": "i8" }, { - "name": "slot_count", + "name": "slotCount", "type": "i16" }, { @@ -1620,7 +1624,7 @@ "container", [ { - "name": "window_id", + "name": "windowId", "type": "i8" } ] @@ -1629,7 +1633,7 @@ "container", [ { - "name": "window_id", + "name": "windowId", "type": "i8" }, { @@ -1650,7 +1654,7 @@ "container", [ { - "name": "window_id", + "name": "windowId", "type": "i8" }, { @@ -1667,19 +1671,19 @@ "container", [ { - "name": "window_id", + "name": "windowId", "type": "i8" }, { - "name": "slot_data", + "name": "slotData", "type": "itemstacks" }, { - "name": "hotbar_data", + "name": "hotbarData", "type": [ "switch", { - "compareTo": "window_id", + "compareTo": "windowId", "fields": { "0": [ "array", @@ -1726,11 +1730,11 @@ { "compareTo": "entryType", "fields": { - "0": "shapeless_recipe", - "1": "shaped_recipe", - "2": "furnace_recipe", - "3": "furnace_recipe_data", - "4": "enchant_list" + "0": "shapelessRecipe", + "1": "shapedRecipe", + "2": "furnaceRecipe", + "3": "furnaceRecipeData", + "4": "enchantList" }, "default":"void" } @@ -1751,15 +1755,15 @@ "container", [ { - "name": "window_id", + "name": "windowId", "type": "i8" }, { - "name": "recipe_type", + "name": "recipeType", "type": "i32" }, { - "name": "recipe_id", + "name": "recipeId", "type": "uuid" }, { @@ -1780,11 +1784,11 @@ "type": "i32" }, { - "name": "user_permission", + "name": "userPermission", "type": "i32" }, { - "name": "global_permission", + "name": "globalPermission", "type": "i32" } ] @@ -1814,11 +1818,11 @@ "container", [ { - "name": "motion_x", + "name": "motionX", "type": "f32" }, { - "name": "motion_z", + "name": "motionZ", "type": "f32" }, { @@ -1831,11 +1835,11 @@ "container", [ { - "name": "chunk_x", + "name": "chunkX", "type": "i32" }, { - "name": "chunk_z", + "name": "chunkZ", "type": "i32" }, { @@ -1843,7 +1847,7 @@ "type": "i8" }, { - "name": "chunk_data", + "name": "chunkData", "type":["buffer",{"countType":"i32"}] } ] @@ -1879,15 +1883,15 @@ "container", [ { - "name": "client_uuid", + "name": "clientUuid", "type": "uuid" }, { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { - "name": "display_name", + "name": "displayName", "type": "string" }, { @@ -1900,7 +1904,7 @@ "container", [ { - "name": "client_uuid", + "name": "clientUuid", "type": "uuid" } ] @@ -1917,7 +1921,7 @@ "container", [ { - "name": "chunk_radius", + "name": "chunkRadius", "type": "i32" } ] @@ -1926,7 +1930,7 @@ "container", [ { - "name": "chunk_radius", + "name": "chunkRadius", "type": "i32" } ] @@ -1944,7 +1948,7 @@ "container", [ { - "name": "entity_id", + "name": "entityId", "type": "i64" }, { From 8c30673c6c8d9f810e322b4849b50d780779a9bd Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Tue, 14 Jun 2016 18:17:54 -0400 Subject: [PATCH 008/458] update all examples --- examples/client.js | 2 +- examples/server.js | 28 ++++++++++++++-------------- src/createClient.js | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/examples/client.js b/examples/client.js index c13d3f8..d7ac65f 100644 --- a/examples/client.js +++ b/examples/client.js @@ -15,7 +15,7 @@ client.on('mcpe', packet => console.log(packet)); client.on('set_spawn_position', () => { client.writeMCPE('request_chunk_radius', { - chunk_radius:8 + chunkRadius:8 }); }); diff --git a/examples/server.js b/examples/server.js index 963098d..2cd0ae6 100644 --- a/examples/server.js +++ b/examples/server.js @@ -24,15 +24,15 @@ server.on('connection', function(client) { status:0 }); client.writeMCPE('move_player', { - entity_id: [0,0], + entityId: [0,0], x: 1, y: 64 + 1.62, z: 1, yaw: 0, - head_yaw: 0, + headYaw: 0, pitch: 0, mode: 0, - on_ground: 1 + onGround: 1 }); client.writeMCPE("start_game",{ @@ -40,17 +40,17 @@ server.on('connection', function(client) { dimension:0, generator:1, gamemode:1, - entity_id:[0,0], - spawn_x:1, - spawn_y:1, - spawn_z:1, + entityId:[0,0], + spawnX:1, + spawnY:1, + spawnZ:1, x:0, y:1+1.62, z:0, - unknown1:0, - unknown2:0, - unknown3:0, - unknown4:"" + isLoadedInCreative:false, + dayCycleStopTime:0, + eduMode:false, + unknown:"" }); client.writeMCPE('set_spawn_position', { @@ -72,14 +72,14 @@ server.on('connection', function(client) { client.on("request_chunk_radius",() => { client.writeMCPE('chunk_radius_update',{ - chunk_radius:1 + chunkRadius:1 }); for (let x = -1; x <=1; x++) { for (let z = -1; z <=1; z++) { client.writeBatch([{"name":"mcpe","params":{name:"full_chunk_data",params:{ - chunk_x: x, - chunk_z: z, + chunkX: x, + chunkZ: z, order: 1, chunk_data:fs.readFileSync(__dirname+"/chunk") }}}]); diff --git a/src/createClient.js b/src/createClient.js index cace13d..9833f33 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -35,10 +35,10 @@ function createClient(options) { username: client.username, protocol: 70, protocol2: 70, - client_id: [ -1, -697896776 ], - client_uuid: '86372ed8-d055-b23a-9171-5e3ac594d766', - server_address: client.host+":"+client.port, - client_secret: new Buffer('e8 88 db 7b 9f f2 f0 44 a3 51 08 18 4e 8c 7f 9a'.replace(/ /g,''),'hex'), + clientId: [ -1, -697896776 ], + clientUuid: '86372ed8-d055-b23a-9171-5e3ac594d766', + serverAddress: client.host+":"+client.port, + clientSecret: new Buffer('e8 88 db 7b 9f f2 f0 44 a3 51 08 18 4e 8c 7f 9a'.replace(/ /g,''),'hex'), skin: { skinType: 'Standard_Steve', From 97c8b7d0aa65b6de384ebfd1c14ce9c3f230863c Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Tue, 14 Jun 2016 18:40:20 -0400 Subject: [PATCH 009/458] change packet prefix, remove duplicate packets --- data/protocol.json | 10 +-- examples/server.js | 151 +++++++++++++++++++++++---------------------- 2 files changed, 77 insertions(+), 84 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 237d217..28140ad 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -538,7 +538,7 @@ { "type": "u8", "mappings": { - "0x8e": "mcpe" + "0xfe": "mcpe" } } ] @@ -567,10 +567,6 @@ { "type": "u8", "mappings": { - "0x04": "id_detect_lost_connections", - "0x14": "id_no_free_incoming_connections", - "0x17": "id_connection_banned", - "0x1A": "id_ip_recently_connected", "0x03": "server_to_client_handshake", "0x04": "client_to_server_handshake", "0x01": "game_login", @@ -639,10 +635,6 @@ { "compareTo": "name", "fields": { - "id_detect_lost_connections": "packet_id_detect_lost_connections", - "id_no_free_incoming_connections": "packet_id_no_free_incoming_connections", - "id_connection_banned": "packet_id_connection_banned", - "id_ip_recently_connected": "packet_id_ip_recently_connected", "server_to_client_handshake": "packet_server_to_client_handshake", "client_to_server_handshake": "packet_client_to_server_handshake", "game_login": "packet_game_login", diff --git a/examples/server.js b/examples/server.js index 2cd0ae6..0190462 100644 --- a/examples/server.js +++ b/examples/server.js @@ -17,83 +17,84 @@ var server = pmp.createServer({ server.on('connection', function(client) { - client.on("mcpe",packet => console.log(packet)); + client.on("mcpe",packet => console.log(JSON.stringify(packet))); client.on("game_login",packet => { - client.writeMCPE("player_status",{ - status:0 - }); - client.writeMCPE('move_player', { - entityId: [0,0], - x: 1, - y: 64 + 1.62, - z: 1, - yaw: 0, - headYaw: 0, - pitch: 0, - mode: 0, - onGround: 1 - }); - - client.writeMCPE("start_game",{ - seed:-1, - dimension:0, - generator:1, - gamemode:1, - entityId:[0,0], - spawnX:1, - spawnY:1, - spawnZ:1, - x:0, - y:1+1.62, - z:0, - isLoadedInCreative:false, - dayCycleStopTime:0, - eduMode:false, - unknown:"" - }); - - client.writeMCPE('set_spawn_position', { - x: 1, - y: 64, - z: 1 - }); - client.writeMCPE("set_time",{ - time:0, - started:1 - }); - - client.writeMCPE('respawn', { - x: 1, - y: 64, - z: 1 - }); - }); - - client.on("request_chunk_radius",() => { - client.writeMCPE('chunk_radius_update',{ - chunkRadius:1 - }); - - for (let x = -1; x <=1; x++) { - for (let z = -1; z <=1; z++) { - client.writeBatch([{"name":"mcpe","params":{name:"full_chunk_data",params:{ - chunkX: x, - chunkZ: z, - order: 1, - chunk_data:fs.readFileSync(__dirname+"/chunk") - }}}]); - } - } - - client.writeMCPE('player_status', { - status: 3 - }); - - client.writeMCPE('set_time', { - time: 0, - started: 1 - }); + console.log(packet); + // client.writeMCPE("player_status",{ + // status:0 + // }); + // client.writeMCPE('move_player', { + // entityId: [0,0], + // x: 1, + // y: 64 + 1.62, + // z: 1, + // yaw: 0, + // headYaw: 0, + // pitch: 0, + // mode: 0, + // onGround: 1 + // }); + // + // client.writeMCPE("start_game",{ + // seed:-1, + // dimension:0, + // generator:1, + // gamemode:1, + // entityId:[0,0], + // spawnX:1, + // spawnY:1, + // spawnZ:1, + // x:0, + // y:1+1.62, + // z:0, + // isLoadedInCreative:false, + // dayCycleStopTime:0, + // eduMode:false, + // unknown:"" + // }); + // + // client.writeMCPE('set_spawn_position', { + // x: 1, + // y: 64, + // z: 1 + // }); + // client.writeMCPE("set_time",{ + // time:0, + // started:1 + // }); + // + // client.writeMCPE('respawn', { + // x: 1, + // y: 64, + // z: 1 + // }); + // }); + // + // client.on("request_chunk_radius",() => { + // client.writeMCPE('chunk_radius_update',{ + // chunkRadius:1 + // }); + // + // for (let x = -1; x <=1; x++) { + // for (let z = -1; z <=1; z++) { + // client.writeBatch([{"name":"mcpe","params":{name:"full_chunk_data",params:{ + // chunkX: x, + // chunkZ: z, + // order: 1, + // chunk_data:fs.readFileSync(__dirname+"/chunk") + // }}}]); + // } + // } + // + // client.writeMCPE('player_status', { + // status: 3 + // }); + // + // client.writeMCPE('set_time', { + // time: 0, + // started: 1 + // }); }); From 6783fa43cfcb806fb9d6b8bfadbfcdfcdb9129c3 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Tue, 14 Jun 2016 18:41:49 -0400 Subject: [PATCH 010/458] fix datatypes, we ain't got no short/long --- data/protocol.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 28140ad..fb5e2d3 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -741,11 +741,11 @@ [ { "name": "unknown", - "type": "short" + "type": "i16" }, { "name": "protocol", - "type": "long" + "type": "i64" }, { "name": "bodyLength", @@ -1819,7 +1819,7 @@ }, { "name": "flags", - "type": "short" + "type": "i16" } ] ], From 8c06ca5a38d1a55aba4881937b3342090ed9c01d Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Wed, 15 Jun 2016 00:44:38 +0200 Subject: [PATCH 011/458] parse server bound batches --- src/createClient.js | 2 +- src/createServer.js | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/createClient.js b/src/createClient.js index 9833f33..3cd58e1 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -52,7 +52,7 @@ function createClient(options) { client.on('batch', function(packet) { var buf = zlib.inflateSync(packet.payload); var packets=batchProto.parsePacketBuffer("insideBatch",buf).data; - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0x8e]),packet]))); + packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet]))); }); return client; diff --git a/src/createServer.js b/src/createServer.js index 943f34f..557d088 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -39,7 +39,13 @@ function createServer(options) { client.writeMCPE("batch",{ payload:payload }); - } + }; + + client.on('batch', function(packet) { + var buf = zlib.inflateSync(packet.payload); + var packets=batchProto.parsePacketBuffer("insideBatch",buf).data; + packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet]))); + }); }); return server; } From 1dc00237fac986815a7aab810ab7e8b60cb09f73 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Wed, 15 Jun 2016 06:53:00 -0400 Subject: [PATCH 012/458] login event, jwt decoding --- data/protocol.json | 16 ++------- examples/server.js | 83 ++------------------------------------------- src/createServer.js | 36 ++++++++++++++++++-- 3 files changed, 39 insertions(+), 96 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index fb5e2d3..761511d 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -739,25 +739,13 @@ "packet_game_login": [ "container", [ - { - "name": "unknown", - "type": "i16" - }, { "name": "protocol", - "type": "i64" - }, - { - "name": "bodyLength", "type": "i32" }, { - "name": "chain", - "type": ["pstring", {"countType": "li32"}] - }, - { - "name": "clientData", - "type": ["pstring", {"countType": "li32"}] + "name": "body", + "type": ["buffer",{"countType":"i32"}] } ] ], diff --git a/examples/server.js b/examples/server.js index 0190462..c5172ad 100644 --- a/examples/server.js +++ b/examples/server.js @@ -15,87 +15,10 @@ var server = pmp.createServer({ }); server.on('connection', function(client) { + //client.on("mcpe", packet => console.log(packet)); - - client.on("mcpe",packet => console.log(JSON.stringify(packet))); - - client.on("game_login",packet => { - console.log(packet); - // client.writeMCPE("player_status",{ - // status:0 - // }); - // client.writeMCPE('move_player', { - // entityId: [0,0], - // x: 1, - // y: 64 + 1.62, - // z: 1, - // yaw: 0, - // headYaw: 0, - // pitch: 0, - // mode: 0, - // onGround: 1 - // }); - // - // client.writeMCPE("start_game",{ - // seed:-1, - // dimension:0, - // generator:1, - // gamemode:1, - // entityId:[0,0], - // spawnX:1, - // spawnY:1, - // spawnZ:1, - // x:0, - // y:1+1.62, - // z:0, - // isLoadedInCreative:false, - // dayCycleStopTime:0, - // eduMode:false, - // unknown:"" - // }); - // - // client.writeMCPE('set_spawn_position', { - // x: 1, - // y: 64, - // z: 1 - // }); - // client.writeMCPE("set_time",{ - // time:0, - // started:1 - // }); - // - // client.writeMCPE('respawn', { - // x: 1, - // y: 64, - // z: 1 - // }); - // }); - // - // client.on("request_chunk_radius",() => { - // client.writeMCPE('chunk_radius_update',{ - // chunkRadius:1 - // }); - // - // for (let x = -1; x <=1; x++) { - // for (let z = -1; z <=1; z++) { - // client.writeBatch([{"name":"mcpe","params":{name:"full_chunk_data",params:{ - // chunkX: x, - // chunkZ: z, - // order: 1, - // chunk_data:fs.readFileSync(__dirname+"/chunk") - // }}}]); - // } - // } - // - // client.writeMCPE('player_status', { - // status: 3 - // }); - // - // client.writeMCPE('set_time', { - // time: 0, - // started: 1 - // }); - + client.on("login", data => { + console.log(client.displayName + '(' + client.XUID + ') ' + ' joined the game'); }); client.on('error', function(err) { diff --git a/src/createServer.js b/src/createServer.js index 557d088..7fe92db 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,10 +1,16 @@ const raknet = require('raknet'); const zlib = require('zlib'); const ProtoDef = require('protodef').ProtoDef; -const batchProto=new ProtoDef(); +const jwt = require('jwt-simple'); +const batchProto = new ProtoDef(); batchProto.addTypes(require("./datatypes/minecraft")); batchProto.addType("insideBatch",["endOfArray",{"type":["buffer",{"countType":"i32"}]}]); +const dataProto = new ProtoDef(); +dataProto.addType("data_chain", [ "container", [ { "name":"chain", "type":[ "pstring", { "countType":"li32" } ] }, { "name":"clientData", "type":[ "pstring", { "countType":"li32" } ] } ] ]); + +const secret = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; + function createServer(options) { options = options || {}; var port = options.port != null ? @@ -26,7 +32,33 @@ function createServer(options) { server.on("connection", function (client) { client.on("mcpe",packet => client.emit(packet.name,packet.params)); - client.writeMCPE=(name,packet) => { + client.on("game_login", packet => { + var body = packet.body; + var body2 = zlib.inflateSync(body); + var parsed = dataProto.parsePacketBuffer("data_chain", body2); + parsed.data.chain = JSON.parse(parsed.data.chain); + + var clientData = parsed.data.clientData; + var chain1 = parsed.data.chain.chain[0]; + var chain2 = parsed.data.chain.chain[1].replace('\n', ''); + + var decode1 = jwt.decode(chain1, secret, 'ES384'); + var nextKey1 = decode1.identityPublicKey; + + var decode2 = jwt.decode(chain2, nextKey1, 'ES384'); + var nextKey2 = decode2.identityPublicKey; + + var clientDecode = jwt.decode(clientData, nextKey1, 'ES384'); + client.randomId = clientDecode.ClientRandomId; + client.skinData = clientDecode.SkinData; + client.skinId = clientDecode.SkinId + client.identity = decode2.extraData.identity; + client.displayName = decode2.extraData.displayName; + client.XUID = decode2.extraData.XUID; + client.emit('login', {displayName: client.displayName, randomId: client.randomId, skinData: client.skinData, skinId: client.skinId, identity: client.identity, XUID: client.XUID}) + }); + + client.writeMCPE = (name,packet) => { client.writeEncapsulated("mcpe",{ name:name, params:packet From 54c371dd62a36e28b2654baed895ab513d417ce7 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Wed, 15 Jun 2016 07:30:02 -0400 Subject: [PATCH 013/458] generating public keys --- data/protocol.json | 4 ++-- examples/client.js | 1 + examples/deserialize.js | 1 + examples/server.js | 6 +++--- src/createServer.js | 12 ++++++++++++ src/datatypes/minecraft.js | 1 - src/transforms/serializer.js | 1 + 7 files changed, 20 insertions(+), 6 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 761511d..41e454c 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -714,7 +714,7 @@ "container", [] ], - "server_to_client_handshake": [ + "packet_server_to_client_handshake": [ "container", [ { @@ -727,7 +727,7 @@ } ] ], - "client_to_server_handshake": [ + "packet_client_to_server_handshake": [ "container", [ { diff --git a/examples/client.js b/examples/client.js index d7ac65f..65b703f 100644 --- a/examples/client.js +++ b/examples/client.js @@ -1,3 +1,4 @@ +'use strict'; var pmp = require('../'); if(process.argv.length !=5) { diff --git a/examples/deserialize.js b/examples/deserialize.js index 97b4f96..bc9132f 100644 --- a/examples/deserialize.js +++ b/examples/deserialize.js @@ -1,3 +1,4 @@ +'use strict'; var mcpe = require('../'); var Parser = require('protodef').Parser; diff --git a/examples/server.js b/examples/server.js index c5172ad..35ed57c 100644 --- a/examples/server.js +++ b/examples/server.js @@ -15,17 +15,17 @@ var server = pmp.createServer({ }); server.on('connection', function(client) { - //client.on("mcpe", packet => console.log(packet)); + client.on("mcpe", packet => console.log(packet)); client.on("login", data => { console.log(client.displayName + '(' + client.XUID + ') ' + ' joined the game'); }); - client.on('error', function(err) { + client.on('error', err => { console.log(err.stack); }); - client.on('end',function() { + client.on('end', () => { console.log("client left"); }) }); diff --git a/src/createServer.js b/src/createServer.js index 7fe92db..6b8d5b8 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,7 +1,9 @@ +'use strict'; const raknet = require('raknet'); const zlib = require('zlib'); const ProtoDef = require('protodef').ProtoDef; const jwt = require('jwt-simple'); +const crypto = require('crypto'); const batchProto = new ProtoDef(); batchProto.addTypes(require("./datatypes/minecraft")); batchProto.addType("insideBatch",["endOfArray",{"type":["buffer",{"countType":"i32"}]}]); @@ -56,6 +58,16 @@ function createServer(options) { client.displayName = decode2.extraData.displayName; client.XUID = decode2.extraData.XUID; client.emit('login', {displayName: client.displayName, randomId: client.randomId, skinData: client.skinData, skinId: client.skinId, identity: client.identity, XUID: client.XUID}) + + client.ecdh = crypto.createECDH('secp192k1'); + // console.log(nextKey2); + // client.secret = client.ecdh.computeSecret(nextKey2, 'base64'); + // console.log(client.edch.getPublicKey('base64')); + + client.writeMCPE('server_to_client_handshake', { + publicKey: client.edch.getPublicKey('base64'), + serverToken: "SO SECRET VERY SECURE" + }); }); client.writeMCPE = (name,packet) => { diff --git a/src/datatypes/minecraft.js b/src/datatypes/minecraft.js index fb1bc48..ab9e940 100644 --- a/src/datatypes/minecraft.js +++ b/src/datatypes/minecraft.js @@ -1,5 +1,4 @@ 'use strict'; - var nbt = require('prismarine-nbt'); const UUID = require('uuid-1345'); diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index bda77e3..010e850 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,3 +1,4 @@ +'use strict'; var ProtoDef = require('protodef').ProtoDef; var Serializer = require('protodef').Serializer; var Parser = require('protodef').Parser; From 26dca46471caea7465dc4419b7728028982aac77 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Thu, 16 Jun 2016 07:11:22 -0400 Subject: [PATCH 014/458] more encryption stuff, lots of progress --- examples/server.js | 2 +- jwt.js | 25 -------- package.json | 4 +- src/createServer.js | 147 +++++++++++++++++++++++++++++++++++--------- 4 files changed, 122 insertions(+), 56 deletions(-) delete mode 100644 jwt.js diff --git a/examples/server.js b/examples/server.js index 35ed57c..9773f2c 100644 --- a/examples/server.js +++ b/examples/server.js @@ -11,7 +11,7 @@ if(process.argv.length !=4) { var server = pmp.createServer({ host: process.argv[2], port: parseInt(process.argv[3]), - name: 'MCPE;Minecraft: PE Server;70 70;0.14.3;0;20' + name: 'MCPE;Minecraft: PE Server;81 81;0.15.0;0;20' }); server.on('connection', function(client) { diff --git a/jwt.js b/jwt.js deleted file mode 100644 index 7d14499..0000000 --- a/jwt.js +++ /dev/null @@ -1,25 +0,0 @@ -var jwt = require('jwt-simple'); -var example = { - "chain": { - "chain": [ - "eyJ4NXUiOiJNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRThFTGtpeHlMY3dsWnJ5VVFjdTFUdlBPbUkyQjd2WDgzbmRuV1JVYVhtNzR3RmZhNWZcL2x3UU5UZnJMVkhhMlBtZW5wR0k2SmhJTVVKYVdacmptTWo5ME5vS05GU05CdUtkbThyWWlYc2ZhejNLMzZ4XC8xVTI2SHBHMFp4S1wvVjFWIiwiYWxnIjoiRVMzODQifQ.eyJuYmYiOjE0NjA4OTYzMzcsInJhbmRvbU5vbmNlIjo3MzI2MDA4MDM2OTAzODU5NzM0LCJpc3MiOiJSZWFsbXNBdXRob3JpemF0aW9uIiwiZXhwIjoxNDYwOTgyNzk3LCJpYXQiOjE0NjA4OTYzOTcsImNlcnRpZmljYXRlQXV0aG9yaXR5Ijp0cnVlLCJpZGVudGl0eVB1YmxpY0tleSI6Ik1IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFQlJ1MEd5VUFkYkZjd1wvUU1vNmFBTGFaZHJTeVNkZFwva1F2OXFHOHlHSWxnc0orVStNMVVpZWtjaDFPc3NHdXlFZW1oSWR1OUZWYklJanRWKzY4bXVkc0orSE1MdGYrMDJTYVk0elBtXC9iR3RURkRIUDBRK2FoUmhvVWRiNVptaFwvIn0.J9vCSKZOH6ZuO_rMv3Tlo0Z7nAnXI44rdlL4FyXcWfdTHG3HlHywos0WLWnMnlxP_Ex2co2M21CSyIhIFM6EvugemsuEZIQpz3WTAmUlaEoaNT7dgGFbqGUn9tr6S1MD", - "eyJ4NXUiOiJNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRUJSdTBHeVVBZGJGY3dcL1FNbzZhQUxhWmRyU3lTZGRcL2tRdjlxRzh5R0lsZ3NKK1UrTTFVaWVrY2gxT3NzR3V5RWVtaElkdTlGVmJJSWp0Vis2OG11ZHNKK0hNTHRmKzAyU2FZNHpQbVwvYkd0VEZESFAwUSthaFJob1VkYjVabWhcLyIsImFsZyI6IkVTMzg0In0.eyJuYmYiOjE0NjA4OTYzMzcsImV4dHJhRGF0YSI6eyJpZGVudGl0eSI6Ijk4YjBjYmNmLWU5MWUtMzAwNC05NjUyLWFlZDkyZjhlMjU2ZCIsImRpc3BsYXlOYW1lIjoieWF3a2F0IiwiWFVJRCI6IjI1MzU0Mzc2MTMzNTc1MzUifSwicmFuZG9tTm9uY2UiOi0zMzg4NzY3NzYzMDEyODY5NTg3LCJpc3MiOiJSZWFsbXNBdXRob3JpemF0aW9uIiwiZXhwIjoxNDYwOTgyNzk3LCJpYXQiOjE0NjA4OTYzOTcsImlkZW50aXR5UHVibGljS2V5IjoiTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVERUtuZXFFdmNxVXFxRk1NMUhNMUE0eldqSkMrSThZK2FLekc1ZGwrNndOT0hIUTRObUcyUEVYUkpZaHVqeW9kRkgrd08wZEVyNEdNMVdvYVdvZzh4c1lRNm1RSkFDMGVWcEJNOTZzcFVCMWVNTjU2K0J3bEo0SDNReDRUQXZBcyJ9.gmAdOsTXU68QIqWweaU9FBuSyhNHcGI2hslrP0AQtVqGHyfPIhm54aUesZSj9mLGIIJTx_I50wijDlsj_lFExb3W3UQV0BDWCsYNBoJ5Kb9AX5O11onqtGbNynCVufJB" - ] - }, - "clientData": "eyJhbGciOiJFUzM4NCIsIng1dSI6Ik1IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFREVLbmVxRXZjcVVxcUZNTTFITTFBNHpXakpDK0k4WSthS3pHNWRsKzZ3Tk9ISFE0Tm1HMlBFWFJKWWh1anlvZEZIK3dPMGRFcjRHTTFXb2FXb2c4eHNZUTZtUUpBQzBlVnBCTTk2c3BVQjFlTU41NitCd2xKNEgzUXg0VEF2QXMifQo,.eyJDbGllbnRSYW5kb21JZCI6MTM2NTg2NDYwOCwiU2VydmVyQWRkcmVzcyI6IjE5Mi4xNjguMS41NjoxOTEzMiIsIlNraW5EYXRhIjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRGxtVWYvNVpsSC8rV05QLy9sbVVmLzVabEgvK1dOUC8vbG1VZi81WTAvLzlpQU12L1lnREwvMklBeS85aUFNdi9ZZ0RMLzJJQXkvOWlBTXYvWWdETC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBNVkwLy8rV1pSLy9salQvLzVabEgvK1daUi8vY2t6ei81WmxILytpZFRQL1lnREwvMklBeS82cUpYditxaVY3L3FvbGUvNnFKWHYvWWdETC8ySUF5L3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFPV1pSLy9ja3p6LzZKMU0vK1daUi8vbGpULy8zSk04LytXTlAvL2xtVWYvMklBeS82cUpYditjZTFEL25IdFEvNXg3VVArY2UxRC9xb2xlLzlpQU12OEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURsalQvLzNKTTgvK2lkVFAvbG1VZi81WmxILytXWlIvL2xqVC8vM0pNOC85aUFNditxaVY3L25IdFEvNXg3VVArY2UxRC9uSHRRLzZxSlh2L1lnREwvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQTVZMC8vK1dOUC8vb25Vei81WTAvLytXWlIvL2xqVC8vNkoxTS85eVRQUC9meHFQL3FvbGUvNXg3VVArY2UxRC9uSHRRLzV4N1VQK3FpVjcvMklBeS93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT1daUi8vbGpULy81WmxILytXTlAvL2NrenovNVpsSC8raWRUUC9vblV6LzM4YWovNnFKWHYrY2UxRC9uSHRRLzV4N1VQK2NlMUQvcW9sZS85aUFNdjhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEY2t6ei81WTAvLytXTlAvL2xtVWYvNVpsSC8rV1pSLy9salQvLzZKMU0vOS9Hby8rcWlWNy9xb2xlLzZxSlh2K3FpVjcvcW9sZS82cUpYdi9ZZ0RML0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE2SjFNLytXWlIvL2xqVC8vNkoxTS8raWRUUC9salQvLzZKMU0vOXlUUFAvZnhxUC8zOGFqLzkvR28vL2Z4cVAvMzhhai85L0dvLy9meHFQLzM4YWovd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRGxtVWYvNVkwLy8raWRUUC9sbVVmLzZKMU0vK2lkVFAvb25Vei81WTAvLytXWlIvL2xqVC8vNVpsSC8rV05QLy9salQvLzVabEgvK1dOUC8vbG1VZi81WmxILytXTlAvL2xtVWYvNVkwLy8rV1pSLy9salQvLzZKMU0vK1daUi8vbGpULy81WmxILytXTlAvL2xtVWYvNVkwLy8rV1pSLy9vblV6LzVZMC8vd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBNVkwLy8rV1pSLy9sbVVmLzVZMC8vK1daUi8vbGpULy81WTAvLytXWlIvL2xqVC8vNVpsSC8rV05QLy9sbVVmLzNKTTgvK1daUi8vbG1VZi81WTAvLytXWlIvL29uVXovNkoxTS8raWRUUC9salQvLzVabEgvK1dOUC8vbG1VZi82SjFNLytpZFRQL2xtVWYvNVkwLy8raWRUUC9vblV6LzVZMC8vK1daUi84QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFPaWRUUC9vblV6LzVZMC8vK1daUi8vbGpULy81WmxILytpZFRQL2xtVWYvNVpsSC8rV05QLy9sbVVmLzNKTTgvK3ZUcy8vcjA3UC81WmxILytXTlAvL29uVXovNVkwLy8rV05QLy9salQvLzZKMU0vK1daUi8vbGpULy82SjFNLytpZFRQL29uVXovNVkwLy8raWRUUC9sbVVmLzZKMU0vK1dOUC8vbG1VZi9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURsbVVmLzNKTTgvK1daUi8vbG1VZi82SjFNLzl5VFBQL2NrenovNVpsSC85eVRQUC9ja3p6LzNKTTgvK3ZUcy8veTJyci81TXVwLytUTHFmL2xtVWYvNVpsSC8rV1pSLy9ja3p6LzVabEgvK1dOUC8vb25Vei82SjFNLytXWlIvL2xqVC8vNkoxTS8rV05QLy9vblV6LzVabEgvK1dOUC8vbG1VZi81WTAvL3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQTNKTTgvK1daUi8vbG1VZi81WmxILzl5VFBQL3IwN1AvNjlPei85eVRQUC9reTZuLysvdjcveU5pSlAveTJyci84dDNDL3lOaUpQLzcrL3YvNU11cC85eVRQUC9salQvLzVabEgvK1daUi8vbG1VZi81WTAvLytXWlIvL2xqVC8vNVpsSC8rV05QLy9sbVVmLzVabEgvK2lkVFAvbG1VZi81WmxILytpZFRQOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBTnlUUFAvbGpULy82SjFNLzl5VFBQL3IwN1AvOHQzQy8vTGF1di95MnJyLzd0YTIvKy9adS8veTJyci84dDNDLy9MYXV2L3kyNzMvN3RlNS8vTGF1di9yMDdQLzNKTTgvK1daUi8vbGpULy81WmxILytXWlIvL29uVXovNVkwLy8rV05QLy9vblV6LzVabEgvK1dOUC8vbGpULy82SjFNLytXWlIvL2xtVWYvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEbGpULy81WmxILytpZFRQL2xtVWYvNjlPei8vTGF1di95M2NMLzh0M0MvL0xhdXYveTNjTC84dHE2LysrN3NmL3Z1N0gvOHRxNi8vTGF1di9yMDdQLzh0M0MvK3ZUcy8vY2t6ei81WTAvLytXWlIvL2xqVC8vNVpsSC8raWRUUC9salQvLzVZMC8vK1dOUC8vbG1VZi82SjFNLytXWlIvL2xtVWYvNVkwLy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE1WmxILytXTlAvL2xtVWYvNjlPei8rdlRzLy95M2NMLzh0cTYvL0xhdXYveTJyci84dHE2Ly9MZHd2L3kycnIvOHRxNi8vTGR3di95M2NMLzh0cTYvK3ZUcy8vY2t6ei81WTAvLytXWlIvL2xtVWYvNVkwLy8rV1pSLy9salQvLzVabEgvK1dOUC8vb25Vei81WmxILytXWlIvL2NrenovNVkwLy8raWRUUDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJrUVN6L1pFRXMvMlJCTFA5a1FTei9LQ2dvL3lnb0tQOG9LQ2ovS0Nnby93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZXJWMy80YUhZZi9ZZ0RMLzJJQXkvOWlBTXYvWWdETC82SjFNLytXWlIvOW9SVEQvYUVVdy8yaEZNUDlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3L3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFlcTkzLzNxdmQvOTZyM2YvMkxxVS8rdlRzLy9ZdXBUL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVpFRXMvMlJCTFA5a1FTei9aRUVzL3lnb0tQOG9LQ2ovS0Nnby95Z29LUDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFIcTFkLytHaDJIL2hvZGgvNGFIWWYrR2gySC8ySUF5LytXWlIvL29uVXovYUVVdy8yaEZNUDlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3LzJoRk1QOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUhxdmQvOTZ0WGYvZXE5My85aTZsUC9yMDdQLzJMcVUvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBR1JCTFA5a1FTei9aRUVzLzJSQkxQOG9LQ2ovS0Nnby95Z29LUDhvS0NqL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUI2dFhmL2hvZGgvNGFIWWYvZnhxUC8zOGFqLzRhSFlmL2xtVWYvNkoxTS8yaEZNUDlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3LzJoRk1QOW9SVEQvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQjZyM2YvZXJWMy8zcXZkLy9yMDdQLzJMcVUvK3ZUcy84QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCa1FTei9aRUVzLzJSQkxQOWtRU3ovS0Nnby95Z29LUDhvS0NqL0tDZ28vd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQWVyVjMvNGFIWWYvcjA3UC84dHE2Ly9MYXV2L2xtVWYvNVpsSC8rV05QLzlvUlREL2FFVXcvMmhGTVA5b1JURC9hRVV3LzJoRk1QOW9SVEQvYUVVdy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBZXE5My8zcXZkLzk2cjNmLzY5T3ovOWk2bFAvcjA3UC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUI2cjNmL2VyVjMvM3ExZC85NnIzZi9hRVV3LzNsVlBmK0FXa0QvYlVvei8yaEZNUDlrUVN6L2FFVXcvMlJCTFArTXZvci9qTDZLLzMyeWV2OTlzbnIvZXJWMy8zcTFkLzk2dFhmL2VxOTMvNHkraXYrR2gySC82OU96Ly9MYXV2L3kycnIvNkoxTS8raWRUUC9salQvLzZKMU0vK2lkVFAvbG1VZi82SjFNLytpZFRQL29uVXovNVpsSC8rV05QLy9sbVVmLzVabEgvNEcxZi8rTHVvai9lcTkzLzNxMWQvOTZyM2YvZXE5My80eStpditMdW9qL2ZiSjYvM3F2ZC85NnRYZi9lclYzLzNxdmQvK0x1b2ovakw2Sy80dTZpUDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVpFRXMvM3F2ZC85NnIzZi9hRVV3LzNKT052OTVWVDMvZVZVOS8yaEZNUDlrUVN6L2FFVXcvMmhGTVA5a1FTei9iMHcxLzRCYVFQK0FXa0QvY2s0Mi8zcTFkLzk2dFhmL2VxOTMvM3F2ZC8rTXZvci9pb3RtLyt2VHMvL3kycnIvOHRxNi8vTGF1di9sbVVmLzZKMU0vK1daUi8vbG1VZi9lcTkzLzNxdmQvL2xtVWYvNVkwLy8rV05QLy9sbVVmL2diVi8vNEcxZi8rTHVvai9pN3FJLzNxdmQvOTZyM2YvZXE5My8zcTFkLytMdW9qL2ZiSjYvNHkraXY5NnRYZi9lclYzLzNxdmQvOTZyM2YvaTdxSS80dTZpUCtNdm9yL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBR1JCTFA5b1JURC9aRUVzLzJoRk1QOXZURFgvZ0ZwQS8yaEZNUDl5VGpiL1pFRXMvMmhGTVA5a1FTei9hRVV3LzI5TU5mK0FXa0QvZVZVOS8zSk9Odjk2cjNmL2VyVjMvM3F2ZC85NnIzZi9qTDZLLzMyeWV2K01qV2ovNjlPei8rdlRzLy9salQvLzVabEgvK2lkVFA5NnIzZi9lcTkzLzNxdmQvOTZ0WGYvZ2JWLy80RzFmLytCdFgvL2diVi8vNHkraXYrTHVvai9pN3FJLzR1NmlQOTZyM2YvZXJWMy8zcTFkLzk2dFhmL2k3cUkvNHkraXYrTHVvai9lcTkzLzNxMWQvOTZ0WGYvZXE5My80eStpditMdW9qL2pMNksvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCa1FTei9aRUVzLzJSQkxQOW9SVEQvYUVVdy8yaEZNUDk1VlQzL2NrNDIvMlJCTFA5b1JURC9aRUVzLzJoRk1QOXZURFgvZ0ZwQS8zbFZQZjl5VGpiL2VxOTMvM3ExZC85NnIzZi9lcTkzLzNldmRmK012b3Ivakw2Sy80eU5hUCtNaldqLzVabEgvK2lkVFA5OXNuci9lclYzLzNxMWQvOTZyM2YvZXJWMy80eStpditMdW9qL2pMNksvNHU2aVArTHVvai9pN3FJLzMyeWV2K0x1b2ovZ0lKYS80ZUpZditIaVdML2dJSmEvNGFIWWYrUGtHdi9ob2RoLzRDQ1d2K0hpV0wvaDRsaS80Q0NXditHaDJIL2o1QnIvNGFIWWY4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFaRUVzLzJSQkxQOWtRU3ovWkVFcy8yOU1OZitHWGtiL2hsNUcvMjlNTmY5a1FTei9aRUVzLzJSQkxQOWtRU3ovYUVVdy8yaEZNUDlvUlREL2FFVXcvM3F2ZC85NnRYZi9lclYzLzNxMWQvOTNyM1gvakw2Sy80eStpdjk5c25yL2pMNksvK2lkVFA5OXRIci9pN3FJLzNxdmQvOTZyM2YvZXE5My8zcTFkLytNdm9yL2k3cUkvNHkraXYrTHVvai9pN3FJLzR5K2l2K012b3Ivakw2Sy8rVEpxUC9reWFqLzVNbW8vK1RKcVAvcjA3UC82OU96Lyt2VHMvL2t5YWovNU1tby8rVEpxUC9reWFqLzY5T3ovK3ZUcy8vcjA3UC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQURzN08vODdPenYvT3pzNy8yUkJMUDlvUlREL2VGUTgvM2hVUFA5b1JURC9aRUVzL3pzN08vODdPenYvT3pzNy8wWkdSdjlHUmtiL1JrWkcvMFpHUnY5NnIzZi9lclYzLzNxdmQvOTZ0WGYvZmJKNi80eStpditMdW9qL2pMNksvNHU2aVArTXZvci9pN3FJLzR1NmlQOTZyM2YvZXE5My8zcXZkLzk2cjNmL2k3cUkvMzJ5ZXYrTXZvci9pN3FJLzR1NmlQK012b3IvaTdxSS80eStpdi9reWFqLzVNbW8vK3ZUcy8vcjA3UC84dHE2Ly9MYXV2L3IwN1AvNjlPei8rdlRzLy9reWFqLzY5T3ovL0xhdXYvcjA3UC84dHE2L3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkpTVW4vU1VsSi8wbEpTZjg3T3p2L1dscGEvMTFkWGY5ZFhWMy9XbHBhL3pzN08vOUpTVW4vU1VsSi8wbEpTZjlOVFUzL1YxZFgvMWRYVi85TlRVMy9lcTkzLzNxMWQvOTZyM2YvZXJWMy80eStpditNdm9yL2ZiSjYvNHkraXYrTHVvai9qTDZLLzR1NmlQK012b3IvZXE5My8zcTFkLzk2cjNmL2VxOTMvNHU2aVArTXZvci9qTDZLLzR1NmlQK012b3IvZmJKNi80eStpditNdm9yLzVNbW8vK3ZUcy8vcjA3UC82OU96Ly9MYXV2L3kycnIvNmRDdi8rdlRzLy9zMUxqLzVNdXEvK3pVdVAveTJyci84dHE2Ly9MZHd2OEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBU1VsSi8wbEpTZjlKU1VuL1NVbEovMkZoWWY5cmEydi9hMnRyLzJGaFlmOUpTVW4vU1VsSi8wbEpTZjlKU1VuL1RVMU4vMWRYVi85WFYxZi9UVTFOLzNxMWQvOTZ0WGYvZXJWMy8zcTFkLytNdm9yL2pMNksvM2V2ZGYrTXZvci9mYko2LzR5K2l2K012b3Ivakw2Sy8zcXZkLzk2dFhmL2VyVjMvM3ExZC8rTXZvci9qTDZLLzR5K2l2OTlzbnIvakw2Sy8zMnllditNdm9yL2pMNksvK3pVdVAvcjA3UC83TlM0Lyt2VHMvL3AwYlAvOHRxNi8vTGF1di92MmIzLzdOUzQvK1hMcmYvdjJyLy84dHE2Ly9MYXV2L3AwYlAvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFFbEpTZjlKU1VuL096czcvMGxKU2Y5aFlXSC9hMnRyLzJ0cmEvOWhZV0gvU1VsSi96czdPLzlKU1VuL1NVbEovMDFOVGY5WFYxZi9WMWRYLzAxTlRmOFlPQmIvR2o4Wi94ZzRGdjhhUHhuL1Q0Qk0vNHkraXY5M3IzWC9qTDZLLzNldmRmK012b3Ivakw2Sy8wK0FUUDhhUHhuL0dqOFoveGc0RnY4YVB4bi9UNEJNLzR5K2l2K012b3IvZDdCMC80eStpdjkzcjNYL2pMNksvMCtBVFAvczFMai83TlM0Lyt6VXVQL3MxTGovNmRHei8vTGR3di95M2NMLzdOUzQvKy9hdi8vczFMai83TlM0Ly9MZHd2L3kzY0wvOHQzQy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJOVFUzL1RVMU4vMUpTVXY4N096di9XbHBhLzJOalkvOWpZMlAvV2xwYS96czdPLzlTVWxML1RVMU4vMDFOVGY5S1Nrci9VRkJRLzFCUVVQOUtTa3IvZXJWMy8zcXZkLzk2dFhmL2VxOTMveGc0RnY4WU9CYi9HRGdXL3hvL0dmOGFQeG4vR0RnVy94ZzRGdjhhUHhuL2VxOTMvM3F2ZC85NnRYZi9lclYzL3hvL0dmOFlPQmIvR0RnVy94by9HZjhhUHhuL0dEZ1cveG8vR2Y4YVB4bi83TlM0Lyt6VXVQL3Yyci8vNzlxLy8vTGR3di95M2NMLzh0L0kvK3pVdVAvdjJyLy83TlM0Lyt6VXVQL3kzOGovOHQzQy8rclV1UDhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVRVMU4vMDFOVGY5U1VsTC9YRnhjLzJGaFlmOXJhMnYvYTJ0ci8yRmhZZjljWEZ6L1VsSlMvMDFOVGY5TlRVMy9Ta3BLLzFCUVVQOVFVRkQvU2twSy8zcTFkLzk2cjNmL2VyVjMvM3F2ZC8rTHVvai9qTDZLLzR1NmlQK012b3IvZmJKNi80dTZpUCtMdW9qL2pMNksvM3F2ZC85NnIzZi9lclYzLzNxdmQvK0x1b2ovakw2Sy80eStpdjk5c25yL2pMNksvNHU2aVArTHVvai9qTDZLLysvYXYvL3Yyci8vN05TNC8rL2F2Ly95MzhqLzh0L0kvL0xkd3YvdjJyLy83OXEvLysvYXYvL3MxTGovOHQvSS8vTGR3di95M2NML0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRDgvUC84L1B6Ly9QejgvLzF4Y1hQOWpZMlAvY0hCdy8zQndjUDlqWTJQL1hGeGMvejgvUC84L1B6Ly9QejgvLzBoSVNQOU1URXovVEV4TS8waElTUDk2cjNmL2VyVjMvM3ExZC85NnIzZi9pN3FJLzJoRk1QOTFVRGovZFZBNC8zVlFPUDkxVURqL2FFVXcvNHU2aVA5NnRYZi9lcTkzLzNxMWQvOTZyM2YvaTdxSS80eStpditNdm9yL2pMNksvNHkraXYrTXZvci9qTDZLLzR1NmlQL3MxTGovNzltOS8relV1UC92MnIvLzh0L0kvL0xkd3YveTNjTC83TlM0Lyt6VXVQL3Yyci8vN05TNC8vTGZ5UC95M2NMLzh0M0Mvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCa1FTei9aRUVzLzJSQkxQOWtRU3ovS0Nnby95Z29LUDhvS0NqL0tDZ28vd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQTZKMU0vM3ExZC85NnIzZi8yTHFVLyt2VHMvL1l1cFQvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFaRUVzLzJSQkxQOWtRU3ovWkVFcy95Z29LUDhvS0NqL0tDZ28veWdvS1A4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT1daUi8vb25Vei9lcTkzLzlpNmxQL3IwN1AvMkxxVS93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUdSQkxQOWtRU3ovWkVFcy8yUkJMUDhvS0NqL0tDZ28veWdvS1A4b0tDai9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEbG1VZi81WTAvLzNxdmQvL3IwN1AvMkxxVS8rdlRzLzhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQmtRU3ovWkVFcy8yUkJMUDlrUVN6L0tDZ28veWdvS1A4b0tDai9LQ2dvL3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE1WTAvLzNxMWQvOTZyM2YvNjlPei85aTZsUC9yMDdQL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCb1JURC9aRUVzLzJoRk1QOWtRU3ovYlVvei80QmFRUDk1VlQzL2FFVXcvMmhGTVA5a1FTei9hRVV3LzJSQkxQOXZURFgvZmJKNi80eStpditNdm9yL2VxOTMvM3ExZC85NnIzZi81WmxILytXTlAvK0x1b2ovaTdxSS8zcXZkLzk2cjNmL2VxOTMvM3F2ZC8rTHVvai9qTDZLLytXTlAvOEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFaRUVzLzJoRk1QOWtRU3ovYUVVdy8yaEZNUDk1VlQzL2VWVTkvM0pPTnY5a1FTei9hRVV3LzJoRk1QOWtRU3ovYjB3MS80QmFRUCtBV2tEL2NrNDIvM3F2ZC85NnIzZi9lcTkzLytpZFRQL2xtVWYvaTdxSS80dTZpUDk2cjNmL2VyVjMvM3F2ZC85NnIzZi9pN3FJLzR1NmlQK012b3IvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUdSQkxQOW9SVEQvWkVFcy8yaEZNUDl5VGpiL2FFVXcvNEJhUVA5dlREWC9aRUVzLzJoRk1QOWtRU3ovYUVVdy8yOU1OZitBV2tEL2VWVTkvM0pPTnY5NnIzZi9lclYzLzNxMWQvOTZ0WGYvaTdxSS80eStpdjk5c25yL2VxOTMvM3ExZC85NnRYZi9lcTkzLzR5K2l2K0x1b2ovakw2Sy93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQmtRU3ovWkVFcy8yUkJMUDlvUlREL2NrNDIvM2xWUGY5b1JURC9hRVV3LzJSQkxQOW9SVEQvWkVFcy8yaEZNUDl2VERYL2dGcEEvM2xWUGY5eVRqYi9nSUphLzRlSll2K0hpV0wvZ0lKYS80YUhZZitQa0d2L2hvZGgvNENDV3YrSGlXTC9oNGxpLzRDQ1d2K0doMkgvajVCci80YUhZZjhBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBWkVFcy8yUkJMUDlrUVN6L1pFRXMvMjlNTmYrR1hrYi9obDVHLzI5TU5mOWtRU3ovWkVFcy8yUkJMUDlrUVN6L2FFVXcvMmhGTVA5b1JURC9hRVV3LytUSnFQL2t5YWovNU1tby8rVEpxUC9yMDdQLzY5T3ovK3ZUcy8va3lhai81TW1vLytUSnFQL2t5YWovNjlPei8rdlRzLy9yMDdQL0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFEczdPLzg3T3p2L096czcvMlJCTFA5b1JURC9lRlE4LzNoVVBQOW9SVEQvWkVFcy96czdPLzg3T3p2L096czcvMFpHUnY5R1JrYi9Sa1pHLzBaR1J2L2t5YWovNU1tby8rdlRzLy9yMDdQLzh0cTYvL0xhdXYvcjA3UC82OU96Lyt2VHMvL2t5YWovNjlPei8vTGF1di9yMDdQLzh0cTYvd0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJKU1VuL1NVbEovMGxKU2Y4N096di9XbHBhLzExZFhmOWRYVjMvV2xwYS96czdPLzlKU1VuL1NVbEovMGxKU2Y5TlRVMy9WMWRYLzFkWFYvOU5UVTMvNU1tby8rdlRzLy9yMDdQLzY5T3ovL0xhdXYveTJyci84dHE2Lyt2VHMvL3MxTGovNjlPei8relV1UC95MnJyLzh0cTYvL0xkd3Y4QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVNVbEovMGxKU2Y5SlNVbi9TVWxKLzJGaFlmOXJhMnYvYTJ0ci8yRmhZZjlKU1VuL1NVbEovMGxKU2Y5SlNVbi9UVTFOLzFkWFYvOVhWMWYvVFUxTi8relV1UC9yMDdQLzdOUzQvKy9admYvcDBiUC84dHE2Ly9MYXV2L3IwN1AvN05TNC8rWExyZi9zMUxqLzh0cTYvL0xhdXYveTNjTC9BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRWxKU2Y5SlNVbi9PenM3LzBsSlNmOWhZV0gvYTJ0ci8ydHJhLzloWVdIL1NVbEovenM3Ty85SlNVbi9TVWxKLzAxTlRmOVhWMWYvVjFkWC8wMU5UZi9zMUxqLzdOUzQvK3pVdVAvczFMai82ZEd6Ly9MZHd2L3kzY0wvN05TNC8relV1UC9zMUxqLzdOUzQvK25Scy8veTNjTC84dDNDL3dBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCTlRVMy9UVTFOLzFKU1V2ODdPenYvV2xwYS8yTmpZLzlqWTJQL1dscGEvenM3Ty85U1VsTC9UVTFOLzAxTlRmOUtTa3IvVUZCUS8xQlFVUDlLU2tyLzdOUzQvK3pVdVAvdjJyLy83TlM0Ly9MZHd2L3kzY0wvNmRHei8relV1UC9zMUxqLzc5cS8vK3pVdVAveTNjTC84dDNDLy9MZHd2OEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFUVTFOLzAxTlRmOVNVbEwvWEZ4Yy8yRmhZZjlyYTJ2L2EydHIvMkZoWWY5Y1hGei9VbEpTLzAxTlRmOU5UVTMvU2twSy8xQlFVUDlRVUZEL1NrcEsvKy9hdi8vczFMai83OXEvLyt6VXVQL3kzY0wvOHQvSS8vTGR3di92MnIvLzdOUzQvK3pVdVAvdjJyLy84dDNDLy9MZnlQL3kzOGovQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUQ4L1AvOC9Qei8vUHo4Ly8xeGNYUDlqWTJQL2NIQncvM0J3Y1A5alkyUC9YRnhjL3o4L1AvOC9Qei8vUHo4Ly8waElTUDlNVEV6L1RFeE0vMGhJU1AvdjJyLy82OU96Lyt6VXVQL3MxTGovOHQvSS8vTGR3di95M2NMLzdOUzQvKy9hdi8vczFMai83TlM0Ly9MZHd2L3kzOGovOHQvSS93QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBPT0iLCJTa2luSWQiOiJTdGFuZGFyZF9BbGV4In0K.gN2HJV9_WW1hvVj-gGKGJsCGEafIiGnTFgKRUKF2CqhiQk4dgB1dHFnZOglDN4VtW397jIPgs92ppMkyfZf8-09XQ87_o_eC1nvuscmBXt6Bn2UZQP_VYFqh_eCAXvCP" -} - - -var clientData = example.clientData; -var chain1 = example.chain.chain[0]; -var chain2 = example.chain.chain[1]; -var secret = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; - -var decode1 = jwt.decode(chain1, secret, 'ES384'); -var nextKey1 = decode1.identityPublicKey; - -var decode2 = jwt.decode(chain2, nextKey1, 'ES384'); -var nextKey2 = decode2.identityPublicKey; - -var clientDecode = jwt.decode(clientData, nextKey1, 'ES384'); -console.log(clientDecode); diff --git a/package.json b/package.json index 1d4c196..8835beb 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,12 @@ ], "license": "MIT", "dependencies": { + "asn1": "^0.2.3", + "bn.js": "^4.11.4", "jwt-simple": "^0.5.0", "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", - "raknet": "^1.7.3", + "raknet": "^1.7.4", "uuid-1345": "^0.99.6" }, "devDependencies": {}, diff --git a/src/createServer.js b/src/createServer.js index 6b8d5b8..845da65 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -4,14 +4,33 @@ const zlib = require('zlib'); const ProtoDef = require('protodef').ProtoDef; const jwt = require('jwt-simple'); const crypto = require('crypto'); +const Ber = require('asn1').Ber; +// const BN = require('bn.js'); + const batchProto = new ProtoDef(); batchProto.addTypes(require("./datatypes/minecraft")); -batchProto.addType("insideBatch",["endOfArray",{"type":["buffer",{"countType":"i32"}]}]); +batchProto.addType("insideBatch", ["endOfArray", { + "type": ["buffer", { + "countType": "i32" + }] +}]); const dataProto = new ProtoDef(); -dataProto.addType("data_chain", [ "container", [ { "name":"chain", "type":[ "pstring", { "countType":"li32" } ] }, { "name":"clientData", "type":[ "pstring", { "countType":"li32" } ] } ] ]); +dataProto.addType("data_chain", ["container", [{ + "name": "chain", + "type": ["pstring", { + "countType": "li32" + }] +}, { + "name": "clientData", + "type": ["pstring", { + "countType": "li32" + }] +}]]); -const secret = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; +const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; +var encryptionEnabled = false; +var sendCounter = 0; function createServer(options) { options = options || {}; @@ -22,8 +41,8 @@ function createServer(options) { 19132; var host = options.host || '0.0.0.0'; - options.customPackets=require("../data/protocol"); - options.customTypes=require("./datatypes/minecraft"); + options.customPackets = require("../data/protocol"); + options.customTypes = require("./datatypes/minecraft"); var server = raknet.createServer(options); server.name = options.name || "Minecraft Server"; @@ -31,8 +50,8 @@ function createServer(options) { server.maxPlayers = options['max-players'] || 20; server.playerCount = 0; - server.on("connection", function (client) { - client.on("mcpe",packet => client.emit(packet.name,packet.params)); + server.on("connection", function(client) { + client.on("mcpe", packet => client.emit(packet.name, packet.params)); client.on("game_login", packet => { var body = packet.body; @@ -44,7 +63,7 @@ function createServer(options) { var chain1 = parsed.data.chain.chain[0]; var chain2 = parsed.data.chain.chain[1].replace('\n', ''); - var decode1 = jwt.decode(chain1, secret, 'ES384'); + var decode1 = jwt.decode(chain1, PUBLIC_KEY, 'ES384'); var nextKey1 = decode1.identityPublicKey; var decode2 = jwt.decode(chain2, nextKey1, 'ES384'); @@ -57,41 +76,111 @@ function createServer(options) { client.identity = decode2.extraData.identity; client.displayName = decode2.extraData.displayName; client.XUID = decode2.extraData.XUID; - client.emit('login', {displayName: client.displayName, randomId: client.randomId, skinData: client.skinData, skinId: client.skinId, identity: client.identity, XUID: client.XUID}) - client.ecdh = crypto.createECDH('secp192k1'); - // console.log(nextKey2); - // client.secret = client.ecdh.computeSecret(nextKey2, 'base64'); - // console.log(client.edch.getPublicKey('base64')); + var reader = new Ber.Reader(new Buffer(nextKey2, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); + reader.readOID(); + var pubKey = new Buffer(reader.readString(Ber.BitString, true)).slice(1); + var ec = crypto.createECDH('secp384r1'); + ec.generateKeys(); + client.sharedSecret = ec.computeSecret(pubKey); + + client.secretKeyBytes = crypto.createHash('sha256').update(client.sharedSecret + "SO SECRET VERY SECURE").digest('binary'); + // console.log(client.secretKeyBytes.length); => 32 client.writeMCPE('server_to_client_handshake', { - publicKey: client.edch.getPublicKey('base64'), - serverToken: "SO SECRET VERY SECURE" + publicKey: ec.getPublicKey('base64'), + serverToken: "SO SECRET VERY SECURE" // obviously, this is super secure (it's not, change it) + }); + + encryptionEnabled = true; + customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe']='restBuffer'; client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol,customPackets).types); + + client.emit('login', { + displayName: client.displayName, + randomId: client.randomId, + skinData: client.skinData, + skinId: client.skinId, + identity: client.identity, + XUID: client.XUID }); }); - client.writeMCPE = (name,packet) => { - client.writeEncapsulated("mcpe",{ - name:name, - params:packet - }); + client.writeMCPE = (name, packet) => { + if (!encryptionEnabled) { + client.writeEncapsulated("mcpe", { + name: name, + params: packet + }); + } else { + sendCounter += 1; + // sendCounter.add(1); + // client.writeEncapsulated("mcpe", { + // name: name, + // params: packet + // }); + } }; - client.writeBatch=function(packets) { - const payload=zlib.deflateSync(batchProto.createPacketBuffer("insideBatch", - packets.map(packet => - client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1)))); - client.writeMCPE("batch",{ - payload:payload - }); + + client.writeBatch = function(packets) { + if (!encryptionEnabled) { + const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch", + packets.map(packet => + client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1)))); + + client.writeMCPE("batch", { + payload: payload + }); + } else { + sendCounter += 1; + // sendCounter.add(1); + // const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch", + // packets.map(packet => + // client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1)))); + // + // client.writeMCPE("batch", { + // payload: payload + // }); + } }; client.on('batch', function(packet) { var buf = zlib.inflateSync(packet.payload); - var packets=batchProto.parsePacketBuffer("insideBatch",buf).data; - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet]))); + var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; + if (!encryptionEnabled) { + packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); + } else { + sendCounter += 1; + // sendCounter.add(1); + // packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet]))); + } }); }); return server; } module.exports = createServer; + +// http://stackoverflow.com/questions/19236327/nodejs-sha256-password-encryption +var AES = {}; + +AES.decrypt = function(cryptkey, iv, encryptdata) { + encryptdata = new Buffer(encryptdata, 'base64').toString('binary'); + + var decipher = crypto.createDecipheriv('aes-256-cbc', cryptkey, iv), + decoded = decipher.update(encryptdata, 'binary', 'utf8'); + + decoded += decipher.final('utf8'); + return decoded; +} + +AES.encrypt = function(cryptkey, iv, cleardata) { + var encipher = crypto.createCipheriv('aes-256-cbc', cryptkey, iv), + encryptdata = encipher.update(cleardata, 'utf8', 'binary'); + + encryptdata += encipher.final('binary'); + encode_encryptdata = new Buffer(encryptdata, 'binary').toString('base64'); + return encode_encryptdata; +} From 709a456ecd6201c3f74f76acf9d332ff6b503a2f Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Thu, 16 Jun 2016 08:14:33 -0400 Subject: [PATCH 015/458] decrypt our first packet --- package.json | 1 + src/createServer.js | 95 +++++++++++++++++---------------------------- 2 files changed, 37 insertions(+), 59 deletions(-) diff --git a/package.json b/package.json index 8835beb..1c2cd02 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "asn1": "^0.2.3", "bn.js": "^4.11.4", "jwt-simple": "^0.5.0", + "lodash.merge": "^4.4.0", "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", "raknet": "^1.7.4", diff --git a/src/createServer.js b/src/createServer.js index 845da65..71520c1 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -5,6 +5,7 @@ const ProtoDef = require('protodef').ProtoDef; const jwt = require('jwt-simple'); const crypto = require('crypto'); const Ber = require('asn1').Ber; +const merge=require("lodash.merge"); // const BN = require('bn.js'); const batchProto = new ProtoDef(); @@ -51,7 +52,17 @@ function createServer(options) { server.playerCount = 0; server.on("connection", function(client) { - client.on("mcpe", packet => client.emit(packet.name, packet.params)); + + + //if(encryptionEnabled) { + // client.on('mcpe', packet => { decipher.write(packet); }) + //} else { + client.on("mcpe", packet => { + client.emit(packet.name, packet.params) + }); + //} + + // decipher.on('data', data => console.log(data)) client.on("game_login", packet => { var body = packet.body; @@ -87,16 +98,31 @@ function createServer(options) { ec.generateKeys(); client.sharedSecret = ec.computeSecret(pubKey); - client.secretKeyBytes = crypto.createHash('sha256').update(client.sharedSecret + "SO SECRET VERY SECURE").digest('binary'); - // console.log(client.secretKeyBytes.length); => 32 + client.secretKeyBytes = crypto.createHash('sha256'); + client.secretKeyBytes.update("SO SECRET VERY SECURE"); + client.secretKeyBytes.update(client.sharedSecret) + client.secretKeyBytes = new Buffer(client.secretKeyBytes.digest()) client.writeMCPE('server_to_client_handshake', { publicKey: ec.getPublicKey('base64'), serverToken: "SO SECRET VERY SECURE" // obviously, this is super secure (it's not, change it) }); - + //console.log('secret', new Buffer(client.secretKeyBytes)); + var decipher = crypto.createDecipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0,16)); + let customPackets=require("../data/protocol"); + customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe'] = 'restBuffer'; + client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol, customPackets).types); encryptionEnabled = true; - customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe']='restBuffer'; client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol,customPackets).types); + + client.on("mcpe", packet => { + //console.log('THE CONSOLELOG') + //console.log(packet); + //console.log('---------------') + decipher.write(packet); + }); + decipher.on('data', data => console.log('decrypt', data)) + + //client.on('mcpe', packet => { decipher.write(packet); }) client.emit('login', { displayName: client.displayName, @@ -109,23 +135,13 @@ function createServer(options) { }); client.writeMCPE = (name, packet) => { - if (!encryptionEnabled) { - client.writeEncapsulated("mcpe", { - name: name, - params: packet - }); - } else { - sendCounter += 1; - // sendCounter.add(1); - // client.writeEncapsulated("mcpe", { - // name: name, - // params: packet - // }); - } + client.writeEncapsulated("mcpe", { + name: name, + params: packet + }); }; client.writeBatch = function(packets) { - if (!encryptionEnabled) { const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch", packets.map(packet => client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1)))); @@ -133,54 +149,15 @@ function createServer(options) { client.writeMCPE("batch", { payload: payload }); - } else { - sendCounter += 1; - // sendCounter.add(1); - // const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch", - // packets.map(packet => - // client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1)))); - // - // client.writeMCPE("batch", { - // payload: payload - // }); - } }; client.on('batch', function(packet) { var buf = zlib.inflateSync(packet.payload); var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; - if (!encryptionEnabled) { - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); - } else { - sendCounter += 1; - // sendCounter.add(1); - // packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet]))); - } + packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); }); }); return server; } module.exports = createServer; - -// http://stackoverflow.com/questions/19236327/nodejs-sha256-password-encryption -var AES = {}; - -AES.decrypt = function(cryptkey, iv, encryptdata) { - encryptdata = new Buffer(encryptdata, 'base64').toString('binary'); - - var decipher = crypto.createDecipheriv('aes-256-cbc', cryptkey, iv), - decoded = decipher.update(encryptdata, 'binary', 'utf8'); - - decoded += decipher.final('utf8'); - return decoded; -} - -AES.encrypt = function(cryptkey, iv, cleardata) { - var encipher = crypto.createCipheriv('aes-256-cbc', cryptkey, iv), - encryptdata = encipher.update(cleardata, 'utf8', 'binary'); - - encryptdata += encipher.final('binary'); - encode_encryptdata = new Buffer(encryptdata, 'binary').toString('base64'); - return encode_encryptdata; -} From d22a813a2333186a97ea5edc52324d670ec82cc4 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Fri, 17 Jun 2016 14:33:55 +0200 Subject: [PATCH 016/458] add decryption test --- package.json | 5 ++++- test/decryption.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/decryption.js diff --git a/package.json b/package.json index 1c2cd02..bb4aa44 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,10 @@ "raknet": "^1.7.4", "uuid-1345": "^0.99.6" }, - "devDependencies": {}, + "devDependencies": { + "buffer-equal": "^1.0.0", + "mocha": "^2.5.3" + }, "repository": { "type": "git", "url": "git+https://github.com/mhsjlw/pocket-minecraft-protocol.git" diff --git a/test/decryption.js b/test/decryption.js new file mode 100644 index 0000000..af898ee --- /dev/null +++ b/test/decryption.js @@ -0,0 +1,41 @@ +const crypto=require("crypto"); +const assert=require("assert"); +const bufferEqual=require("buffer-equal"); + +// based on https://s.yawk.at/8W5U and https://confluence.yawk.at/display/PEPROTOCOL/Encryption +describe("decryption",() => { + let decipher; + before(() => { + + let secretKeyBytes = new Buffer("ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=","base64"); + + ///// + + let iv = secretKeyBytes.slice(0,16); + + assert(bufferEqual(iv, new Buffer("ZOBpyzki/M8UZv5tiBih0w==","base64"))); + + + decipher = crypto.createDecipheriv('aes-256-cfb8', secretKeyBytes, iv); + }); + + + it("decrypt 1",cb => { + let packet1Encrypted = new Buffer("4B4FCA0C2A4114155D67F8092154AAA5EF","hex"); + decipher.once('data', packet1Decrypted => { + assert(bufferEqual(packet1Decrypted, new Buffer("0400000000499602D2FC2FCB233F34D5DD", "hex"))); + cb(); + }); + decipher.write(packet1Encrypted); + }); + + + it("decrypt 2",cb => { + let packet2Encrypted = new Buffer("DF53B9764DB48252FA1AE3AEE4","hex"); + decipher.once('data', packet2Decrypted => { + assert(bufferEqual(packet2Decrypted,new Buffer("3C000000085A446D11C0C7AA5A","hex"))); + cb(); + }); + decipher.write(packet2Encrypted); + }) +}); \ No newline at end of file From 7cf474a49fd473ce3c5aff06048045643cda0a4a Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Fri, 17 Jun 2016 14:55:15 +0200 Subject: [PATCH 017/458] add test for ecdh : values might not be correct --- test/ecdh_key_exchange.js | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 test/ecdh_key_exchange.js diff --git a/test/ecdh_key_exchange.js b/test/ecdh_key_exchange.js new file mode 100644 index 0000000..db3e88d --- /dev/null +++ b/test/ecdh_key_exchange.js @@ -0,0 +1,42 @@ +const crypto=require("crypto"); +var Ber = require('asn1').Ber; +const assert=require("assert"); +const bufferEqual=require("buffer-equal"); + +// based on https://s.yawk.at/VZSf and https://confluence.yawk.at/display/PEPROTOCOL/Encryption +describe("ecdh key exchange",() => { + it("generate the secret",() => { + + const pubKeyStr = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDEKneqEvcqUqqFMM1HM1A4zWjJC+I8Y+aKzG5dl+6wNOHHQ4NmG2PEXRJYhujyodFH+wO0dEr4GM1WoaWog8xsYQ6mQJAC0eVpBM96spUB1eMN56+BwlJ4H3Qx4TAvAs"; + + var reader = new Ber.Reader(new Buffer(pubKeyStr, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); // Hey, I'm an elliptic curve + reader.readOID(); // This contains the curve type, could be useful + +// The first byte is unused, it contains the "number of unused bits in last octet" +// The pubKey should start at "04" which signifies it is an "uncompressed" public key. + var pubKey = new Buffer(reader.readString(Ber.BitString, true)).slice(1); + +// It'd be better to get this from the curve type OID + var server = crypto.createECDH('secp384r1'); +//server.generateKeys(); + server.setPrivateKey("oH53xXsdMRt6VbjlUUggn/QTcUQUqOHcvHl+U1jaGAUe8TP9H3XdKeoqSAKrKBGG", "base64"); + let secret = server.computeSecret(pubKey); + assert(bufferEqual(secret, new Buffer("sM5HvG6efG0RwRe7S+Er9ingxuVzC6HIXmQ1DITVkh4GmX7pboSzbLtaTTNKE8bJ", "base64"))); + + }); + + + it("create the secret key",() => { + let secret=new Buffer("sM5HvG6efG0RwRe7S+Er9ingxuVzC6HIXmQ1DITVkh4GmX7pboSzbLtaTTNKE8bJ", "base64"); + let hash = crypto.createHash('sha256'); + hash.update("SO SECRET VERY SECURE"); + hash.update(secret); + let secretKey = hash.digest(); + + let expected=new Buffer("PN/4NCtRswMTwfpOKRecbMncwxa91Fx4QSUlad46jrc","base64"); + assert(bufferEqual(secretKey,expected),secretKey.toString("base64")+"!="+expected.toString("base64")); + }) +}); \ No newline at end of file From 3dfc5134b6141d03b32cc0777eb84cc8b1fd08a6 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Fri, 17 Jun 2016 15:06:22 +0200 Subject: [PATCH 018/458] add checksum test --- test/checksum.js | 33 +++++++++++++++++++++++++++++++++ test/ecdh_key_exchange.js | 1 + 2 files changed, 34 insertions(+) create mode 100644 test/checksum.js diff --git a/test/checksum.js b/test/checksum.js new file mode 100644 index 0000000..3a15dd4 --- /dev/null +++ b/test/checksum.js @@ -0,0 +1,33 @@ +const crypto=require("crypto"); +const assert=require("assert"); +const bufferEqual=require("buffer-equal"); + +function writeLI64(value, buffer, offset) { + buffer.writeInt32LE(value[0], offset+4); + buffer.writeInt32LE(value[1], offset); + return offset + 8; +} + +// based on https://s.yawk.at/QADm and https://confluence.yawk.at/display/PEPROTOCOL/Encryption +describe("checksum",() => { + it("generate hash and checksum",() => { + let packetPlaintext = new Buffer("3C00000008","hex"); + let sendCounter = [0,1]; + let secretKeyBytes = new Buffer("ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=","base64"); + + ///// + + let digest = crypto.createHash('sha256'); + // sendCounter to little-endian byte array + let counter=new Buffer(8); + writeLI64(sendCounter,counter,0); + digest.update(counter); + digest.update(packetPlaintext); + digest.update(secretKeyBytes); + let hash = digest.digest(); + assert(bufferEqual(hash, new Buffer("WkRtEcDHqlqesU6wdSnIz7cU3OCNKVMIsX3aXZMLRjQ=","base64")),hash.toString("base64")); + + let checksum = hash.slice(0,8); + assert(bufferEqual(checksum, new Buffer("5A446D11C0C7AA5A","hex"))); + }) +}); \ No newline at end of file diff --git a/test/ecdh_key_exchange.js b/test/ecdh_key_exchange.js index db3e88d..a0e95b7 100644 --- a/test/ecdh_key_exchange.js +++ b/test/ecdh_key_exchange.js @@ -4,6 +4,7 @@ const assert=require("assert"); const bufferEqual=require("buffer-equal"); // based on https://s.yawk.at/VZSf and https://confluence.yawk.at/display/PEPROTOCOL/Encryption +// and https://github.com/mhsjlw/pocket-minecraft-protocol/issues/15 describe("ecdh key exchange",() => { it("generate the secret",() => { From 549f8dc084c4a5b798cdfd0b1c1963db6a46db56 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Fri, 17 Jun 2016 15:07:45 +0200 Subject: [PATCH 019/458] fix secretKeyBytes a bit --- src/createServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/createServer.js b/src/createServer.js index 71520c1..9daafb5 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -101,7 +101,7 @@ function createServer(options) { client.secretKeyBytes = crypto.createHash('sha256'); client.secretKeyBytes.update("SO SECRET VERY SECURE"); client.secretKeyBytes.update(client.sharedSecret) - client.secretKeyBytes = new Buffer(client.secretKeyBytes.digest()) + client.secretKeyBytes = client.secretKeyBytes.digest(); client.writeMCPE('server_to_client_handshake', { publicKey: ec.getPublicKey('base64'), From 7bf93ae68b587052837b874ec08e9c0027c032a9 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Fri, 17 Jun 2016 15:19:29 +0200 Subject: [PATCH 020/458] formatting fixes --- src/createServer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 9daafb5..eefb3dd 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -83,7 +83,7 @@ function createServer(options) { var clientDecode = jwt.decode(clientData, nextKey1, 'ES384'); client.randomId = clientDecode.ClientRandomId; client.skinData = clientDecode.SkinData; - client.skinId = clientDecode.SkinId + client.skinId = clientDecode.SkinId; client.identity = decode2.extraData.identity; client.displayName = decode2.extraData.displayName; client.XUID = decode2.extraData.XUID; @@ -100,7 +100,7 @@ function createServer(options) { client.secretKeyBytes = crypto.createHash('sha256'); client.secretKeyBytes.update("SO SECRET VERY SECURE"); - client.secretKeyBytes.update(client.sharedSecret) + client.secretKeyBytes.update(client.sharedSecret); client.secretKeyBytes = client.secretKeyBytes.digest(); client.writeMCPE('server_to_client_handshake', { @@ -120,7 +120,7 @@ function createServer(options) { //console.log('---------------') decipher.write(packet); }); - decipher.on('data', data => console.log('decrypt', data)) + decipher.on('data', data => console.log('decrypt', data)); //client.on('mcpe', packet => { decipher.write(packet); }) From 6478e625ec01abac03e120bfafd7e95e0ebce4e0 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Fri, 17 Jun 2016 15:39:36 +0200 Subject: [PATCH 021/458] read/write X509 properly, fix decrypt --- src/createServer.js | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index eefb3dd..10fd24d 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -51,6 +51,27 @@ function createServer(options) { server.maxPlayers = options['max-players'] || 20; server.playerCount = 0; + function readX509PublicKey(key) { + var reader = new Ber.Reader(new Buffer(key, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); + reader.readOID(); + return new Buffer(reader.readString(Ber.BitString, true)).slice(1); + } + + function writeX509PublicKey(key) { + var writer = new Ber.Writer(); + writer.startSequence(); + writer.startSequence(); + writer.writeOID("1.2.840.10045.2.1"); + writer.writeOID("1.3.132.0.34"); + writer.endSequence(); + writer.writeBuffer(Buffer.concat([new Buffer([0x00]),key]),Ber.BitString); + writer.endSequence(); + return writer.buffer.toString("base64"); + } + server.on("connection", function(client) { @@ -88,23 +109,20 @@ function createServer(options) { client.displayName = decode2.extraData.displayName; client.XUID = decode2.extraData.XUID; - var reader = new Ber.Reader(new Buffer(nextKey2, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); - reader.readOID(); - var pubKey = new Buffer(reader.readString(Ber.BitString, true)).slice(1); + + var pubKeyClient = readX509PublicKey(nextKey2); var ec = crypto.createECDH('secp384r1'); ec.generateKeys(); - client.sharedSecret = ec.computeSecret(pubKey); + client.sharedSecret = ec.computeSecret(pubKeyClient); client.secretKeyBytes = crypto.createHash('sha256'); client.secretKeyBytes.update("SO SECRET VERY SECURE"); client.secretKeyBytes.update(client.sharedSecret); client.secretKeyBytes = client.secretKeyBytes.digest(); + let pubKeyServer=writeX509PublicKey(ec.getPublicKey()); client.writeMCPE('server_to_client_handshake', { - publicKey: ec.getPublicKey('base64'), + publicKey: pubKeyServer, serverToken: "SO SECRET VERY SECURE" // obviously, this is super secure (it's not, change it) }); //console.log('secret', new Buffer(client.secretKeyBytes)); From b86eb6a80f3266de769ad7fcec44ce3f1ecdd6c4 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 18 Jun 2016 13:07:13 +0200 Subject: [PATCH 022/458] add rest of the parsing pipeline. Works but the client is sending unparsable packet in a batch --- src/createServer.js | 58 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 10fd24d..38c9639 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -2,10 +2,12 @@ const raknet = require('raknet'); const zlib = require('zlib'); const ProtoDef = require('protodef').ProtoDef; +const Parser = require('protodef').Parser; const jwt = require('jwt-simple'); const crypto = require('crypto'); const Ber = require('asn1').Ber; const merge=require("lodash.merge"); +const assert=require("assert"); // const BN = require('bn.js'); const batchProto = new ProtoDef(); @@ -29,6 +31,10 @@ dataProto.addType("data_chain", ["container", [{ }] }]]); + +const Transform = require('stream').Transform; + + const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; var encryptionEnabled = false; var sendCounter = 0; @@ -74,11 +80,13 @@ function createServer(options) { server.on("connection", function(client) { + client.counter=0; //if(encryptionEnabled) { // client.on('mcpe', packet => { decipher.write(packet); }) //} else { client.on("mcpe", packet => { + console.log("actual mcpe",packet); client.emit(packet.name, packet.params) }); //} @@ -127,12 +135,13 @@ function createServer(options) { }); //console.log('secret', new Buffer(client.secretKeyBytes)); var decipher = crypto.createDecipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0,16)); - let customPackets=require("../data/protocol"); - customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe'] = 'restBuffer'; + let customPackets=JSON.parse(JSON.stringify(require("../data/protocol"))); + customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe_encrypted'] = 'restBuffer'; + customPackets['types']['encapsulated_packet'][1][0]['type'][1]['mappings']['0xfe'] = 'mcpe_encrypted'; client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol, customPackets).types); encryptionEnabled = true; - client.on("mcpe", packet => { + client.on("mcpe_encrypted", packet => { //console.log('THE CONSOLELOG') //console.log(packet); //console.log('---------------') @@ -140,6 +149,48 @@ function createServer(options) { }); decipher.on('data', data => console.log('decrypt', data)); + + function writeLI64(value, buffer, offset) { + buffer.writeInt32LE(value[0], offset+4); + buffer.writeInt32LE(value[1], offset); + return offset + 8; + } + + function computeCheckSum(packetPlaintext,sendCounter,secretKeyBytes) { + let digest = crypto.createHash('sha256'); + let counter=new Buffer(8); + writeLI64(sendCounter,counter,0); + digest.update(counter); + digest.update(packetPlaintext); + digest.update(secretKeyBytes); + let hash = digest.digest(); + + return hash.slice(0,8); + } + + + const checksumTransform = new Transform({ + transform(chunk,enc,cb) { + const packet=chunk.slice(0,chunk.length-8); + const checksum=chunk.slice(chunk.length-8); + const computedCheckSum=computeCheckSum(packet,[0,client.counter],client.secretKeyBytes); + const pass=checksum.toString("hex")==computedCheckSum.toString("hex"); + //assert.equal(checksum.toString("hex"),computedCheckSum.toString("hex")); + client.counter++; + if(pass) this.push(packet); + cb(); + } + }); + checksumTransform.on("data",data => console.log('sliced',data)); + decipher.pipe(checksumTransform); + const proto=new ProtoDef(); + proto.addTypes(require("./datatypes/minecraft")); + proto.addTypes(require("../data/protocol").types); + const mcpePacketParser=new Parser(proto,"mcpe_packet"); + checksumTransform.pipe(mcpePacketParser); + mcpePacketParser.on("data",parsed => console.log("parsed data",parsed)); + mcpePacketParser.on("data",parsed => client.emitPacket(parsed)); + //client.on('mcpe', packet => { decipher.write(packet); }) client.emit('login', { @@ -171,6 +222,7 @@ function createServer(options) { client.on('batch', function(packet) { var buf = zlib.inflateSync(packet.payload); + console.log("in batch",buf); var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); }); From 2c6ee7615263bf71eed3bdf2ef4c026ba65ae1a9 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 18 Jun 2016 14:37:23 +0200 Subject: [PATCH 023/458] client_to_server_handshake doesn't have the magic --- data/protocol.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 41e454c..2e0e36d 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -730,10 +730,6 @@ "packet_client_to_server_handshake": [ "container", [ - { - "name": "magic", - "type": "i64" - } ] ], "packet_game_login": [ From 2e1e3f8bb24b395c9170e314614baa0c05adf2ed Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 18 Jun 2016 14:37:37 +0200 Subject: [PATCH 024/458] update raknet --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb4aa44..e4d8237 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "lodash.merge": "^4.4.0", "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", - "raknet": "^1.7.4", + "raknet": "^1.8.0", "uuid-1345": "^0.99.6" }, "devDependencies": { From 66111dad542708bc029ee2f08ddbbe2abff08ef6 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 18 Jun 2016 14:58:17 +0200 Subject: [PATCH 025/458] encryption + complete example. The ideas are there, but it doesn't seems to be accepted by the client yet --- examples/server.js | 91 +++++++++++++++++-- examples/server_simple.js | 31 +++++++ src/createServer.js | 180 ++++++++++++++++++++++---------------- 3 files changed, 222 insertions(+), 80 deletions(-) create mode 100644 examples/server_simple.js diff --git a/examples/server.js b/examples/server.js index 9773f2c..42a3691 100644 --- a/examples/server.js +++ b/examples/server.js @@ -15,17 +15,96 @@ var server = pmp.createServer({ }); server.on('connection', function(client) { - client.on("mcpe", packet => console.log(packet)); - client.on("login", data => { - console.log(client.displayName + '(' + client.XUID + ') ' + ' joined the game'); + + client.on("mcpe",packet => console.log(packet)); + + client.on("login",packet => { + console.log("aaaaa"); + + client.writeMCPE("player_status",{ + status:0 + }); +/* + client.writeMCPE('move_player', { + entityId: [0,0], + x: 1, + y: 64 + 1.62, + z: 1, + yaw: 0, + headYaw: 0, + pitch: 0, + mode: 0, + onGround: 1 + }); + + client.writeMCPE("start_game",{ + seed:-1, + dimension:0, + generator:1, + gamemode:1, + entityId:[0,0], + spawnX:1, + spawnY:1, + spawnZ:1, + x:0, + y:1+1.62, + z:0, + isLoadedInCreative:0, + dayCycleStopTime:0, + eduMode:0, + unknown:"" + });*/ +/* + client.writeMCPE('set_spawn_position', { + x: 1, + y: 64, + z: 1 + }); + client.writeMCPE("set_time",{ + time:0, + started:1 + }); + + client.writeMCPE('respawn', { + x: 1, + y: 64, + z: 1 + });*/ }); - client.on('error', err => { + client.on("request_chunk_radius",() => { + client.writeMCPE('chunk_radius_update',{ + chunk_radius:1 + }); + + for (let x = -1; x <=1; x++) { + for (let z = -1; z <=1; z++) { + client.writeBatch([{"name":"mcpe","params":{name:"full_chunk_data",params:{ + chunkX: x, + chunkZ: z, + order: 1, + chunkData:fs.readFileSync(__dirname+"/chunk") + }}}]); + } + } + + client.writeMCPE('player_status', { + status: 3 + }); + + client.writeMCPE('set_time', { + time: 0, + started: 1 + }); + + }); + + client.on('error', function(err) { console.log(err.stack); }); - client.on('end', () => { + client.on('end',function() { console.log("client left"); }) -}); +}); \ No newline at end of file diff --git a/examples/server_simple.js b/examples/server_simple.js new file mode 100644 index 0000000..9773f2c --- /dev/null +++ b/examples/server_simple.js @@ -0,0 +1,31 @@ +'use strict'; + +var pmp = require('../'); +var fs = require("fs"); + +if(process.argv.length !=4) { + console.log("Usage: node server.js "); + process.exit(1); +} + +var server = pmp.createServer({ + host: process.argv[2], + port: parseInt(process.argv[3]), + name: 'MCPE;Minecraft: PE Server;81 81;0.15.0;0;20' +}); + +server.on('connection', function(client) { + client.on("mcpe", packet => console.log(packet)); + + client.on("login", data => { + console.log(client.displayName + '(' + client.XUID + ') ' + ' joined the game'); + }); + + client.on('error', err => { + console.log(err.stack); + }); + + client.on('end', () => { + console.log("client left"); + }) +}); diff --git a/src/createServer.js b/src/createServer.js index 38c9639..ade4d26 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -3,11 +3,13 @@ const raknet = require('raknet'); const zlib = require('zlib'); const ProtoDef = require('protodef').ProtoDef; const Parser = require('protodef').Parser; +const Serializer = require('protodef').Serializer; const jwt = require('jwt-simple'); const crypto = require('crypto'); const Ber = require('asn1').Ber; const merge=require("lodash.merge"); const assert=require("assert"); +var debug = require('debug')("raknet"); // const BN = require('bn.js'); const batchProto = new ProtoDef(); @@ -32,12 +34,50 @@ dataProto.addType("data_chain", ["container", [{ }]]); +function writeLI64(value, buffer, offset) { + buffer.writeInt32LE(value[0], offset+4); + buffer.writeInt32LE(value[1], offset); + return offset + 8; +} + +function computeCheckSum(packetPlaintext,sendCounter,secretKeyBytes) { + let digest = crypto.createHash('sha256'); + let counter=new Buffer(8); + writeLI64(sendCounter,counter,0); + digest.update(counter); + digest.update(packetPlaintext); + digest.update(secretKeyBytes); + let hash = digest.digest(); + + return hash.slice(0,8); +} + + +function readX509PublicKey(key) { + var reader = new Ber.Reader(new Buffer(key, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); + reader.readOID(); + return new Buffer(reader.readString(Ber.BitString, true)).slice(1); +} + +function writeX509PublicKey(key) { + var writer = new Ber.Writer(); + writer.startSequence(); + writer.startSequence(); + writer.writeOID("1.2.840.10045.2.1"); + writer.writeOID("1.3.132.0.34"); + writer.endSequence(); + writer.writeBuffer(Buffer.concat([new Buffer([0x00]),key]),Ber.BitString); + writer.endSequence(); + return writer.buffer.toString("base64"); +} + const Transform = require('stream').Transform; const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; -var encryptionEnabled = false; -var sendCounter = 0; function createServer(options) { options = options || {}; @@ -57,41 +97,19 @@ function createServer(options) { server.maxPlayers = options['max-players'] || 20; server.playerCount = 0; - function readX509PublicKey(key) { - var reader = new Ber.Reader(new Buffer(key, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); - reader.readOID(); - return new Buffer(reader.readString(Ber.BitString, true)).slice(1); - } - - function writeX509PublicKey(key) { - var writer = new Ber.Writer(); - writer.startSequence(); - writer.startSequence(); - writer.writeOID("1.2.840.10045.2.1"); - writer.writeOID("1.3.132.0.34"); - writer.endSequence(); - writer.writeBuffer(Buffer.concat([new Buffer([0x00]),key]),Ber.BitString); - writer.endSequence(); - return writer.buffer.toString("base64"); - } server.on("connection", function(client) { - client.counter=0; + client.receiveCounter=0; + client.sendCounter=0; + + client.encryptionEnabled = false; - //if(encryptionEnabled) { - // client.on('mcpe', packet => { decipher.write(packet); }) - //} else { client.on("mcpe", packet => { console.log("actual mcpe",packet); client.emit(packet.name, packet.params) }); - //} - // decipher.on('data', data => console.log(data)) client.on("game_login", packet => { var body = packet.body; @@ -133,81 +151,68 @@ function createServer(options) { publicKey: pubKeyServer, serverToken: "SO SECRET VERY SECURE" // obviously, this is super secure (it's not, change it) }); - //console.log('secret', new Buffer(client.secretKeyBytes)); var decipher = crypto.createDecipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0,16)); let customPackets=JSON.parse(JSON.stringify(require("../data/protocol"))); customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe_encrypted'] = 'restBuffer'; customPackets['types']['encapsulated_packet'][1][0]['type'][1]['mappings']['0xfe'] = 'mcpe_encrypted'; client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol, customPackets).types); - encryptionEnabled = true; + client.encryptionEnabled = true; client.on("mcpe_encrypted", packet => { - //console.log('THE CONSOLELOG') - //console.log(packet); - //console.log('---------------') + console.log("raw",packet); decipher.write(packet); }); decipher.on('data', data => console.log('decrypt', data)); - - function writeLI64(value, buffer, offset) { - buffer.writeInt32LE(value[0], offset+4); - buffer.writeInt32LE(value[1], offset); - return offset + 8; - } - - function computeCheckSum(packetPlaintext,sendCounter,secretKeyBytes) { - let digest = crypto.createHash('sha256'); - let counter=new Buffer(8); - writeLI64(sendCounter,counter,0); - digest.update(counter); - digest.update(packetPlaintext); - digest.update(secretKeyBytes); - let hash = digest.digest(); - - return hash.slice(0,8); - } + client.cipher=crypto.createCipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0,16)); const checksumTransform = new Transform({ transform(chunk,enc,cb) { const packet=chunk.slice(0,chunk.length-8); const checksum=chunk.slice(chunk.length-8); - const computedCheckSum=computeCheckSum(packet,[0,client.counter],client.secretKeyBytes); - const pass=checksum.toString("hex")==computedCheckSum.toString("hex"); + const computedCheckSum=computeCheckSum(packet,[0,client.receiveCounter],client.secretKeyBytes); //assert.equal(checksum.toString("hex"),computedCheckSum.toString("hex")); - client.counter++; - if(pass) this.push(packet); + client.receiveCounter++; + if(checksum.toString("hex")==computedCheckSum.toString("hex")) this.push(packet); cb(); } }); + client.addChecksumTransform = new Transform({ + transform(chunk,enc,cb) { + const packet=Buffer.concat([chunk,computeCheckSum(chunk,[0,client.sendCounter],client.secretKeyBytes)]); + client.sendCounter++; + this.push(packet); + cb(); + } + }); + + checksumTransform.on("data",data => console.log('sliced',data)); decipher.pipe(checksumTransform); const proto=new ProtoDef(); proto.addTypes(require("./datatypes/minecraft")); proto.addTypes(require("../data/protocol").types); - const mcpePacketParser=new Parser(proto,"mcpe_packet"); - checksumTransform.pipe(mcpePacketParser); - mcpePacketParser.on("data",parsed => console.log("parsed data",parsed)); - mcpePacketParser.on("data",parsed => client.emitPacket(parsed)); + client.mcpePacketParser=new Parser(proto,"mcpe_packet"); + client.mcpePacketSerializer=new Serializer(proto,"mcpe_packet"); + checksumTransform.pipe(client.mcpePacketParser); + client.mcpePacketParser.on("data",parsed => console.log("parsed data",parsed)); + client.mcpePacketParser.on("data",parsed => {if(parsed.data.name=="batch") parsed.data.name="batch_non_encrypted"; return client.emitPacket(parsed)}); - //client.on('mcpe', packet => { decipher.write(packet); }) - client.emit('login', { - displayName: client.displayName, - randomId: client.randomId, - skinData: client.skinData, - skinId: client.skinId, - identity: client.identity, - XUID: client.XUID - }); + client.mcpePacketSerializer.pipe(client.addChecksumTransform); + client.addChecksumTransform.pipe(client.cipher); }); - client.writeMCPE = (name, packet) => { - client.writeEncapsulated("mcpe", { - name: name, - params: packet - }); + client.writeMCPE = (name, params) => { + if(client.encryptionEnabled) { + client.mcpePacketSerializer.write({ name, params }); + client.cipher.on('data', data => console.log("crypted",data)); + client.cipher.on('data', data => client.writeEncapsulated("mcpe_encrypted", data)); + } + else { + client.writeEncapsulated("mcpe", { name, params }); + } }; client.writeBatch = function(packets) { @@ -222,10 +227,37 @@ function createServer(options) { client.on('batch', function(packet) { var buf = zlib.inflateSync(packet.payload); - console.log("in batch",buf); var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); }); + + client.on('client_to_server_handshake',() => { + console.log("plop"); + client.emit('login', { + displayName: client.displayName, + randomId: client.randomId, + skinData: client.skinData, + skinId: client.skinId, + identity: client.identity, + XUID: client.XUID + }); + }); + + + client.on('batch_non_encrypted', function(packet) { + var buf = zlib.inflateSync(packet.payload); + var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; + packets.forEach(packet => { + try { + debug("handle mcpe",packet); + var r = client.mcpePacketParser.parsePacketBuffer(packet); + client.emitPacket(r); + } + catch(err) { + client.emit("error",err); + } + }); + }); }); return server; } From d040667bc0dc97aec3214ef2b413be61756a4ad4 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 18 Jun 2016 15:51:41 +0200 Subject: [PATCH 026/458] spawns ! --- examples/server.js | 18 ++++++++---------- examples/server_simple.js | 2 +- src/createServer.js | 17 ++++++----------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/examples/server.js b/examples/server.js index 42a3691..50d4a8a 100644 --- a/examples/server.js +++ b/examples/server.js @@ -19,13 +19,11 @@ server.on('connection', function(client) { client.on("mcpe",packet => console.log(packet)); - client.on("login",packet => { - console.log("aaaaa"); - + client.on("login_mcpe",packet => { client.writeMCPE("player_status",{ status:0 }); -/* + client.writeMCPE('move_player', { entityId: [0,0], x: 1, @@ -54,8 +52,8 @@ server.on('connection', function(client) { dayCycleStopTime:0, eduMode:0, unknown:"" - });*/ -/* + }); + client.writeMCPE('set_spawn_position', { x: 1, y: 64, @@ -70,22 +68,22 @@ server.on('connection', function(client) { x: 1, y: 64, z: 1 - });*/ + }); }); - client.on("request_chunk_radius",() => { + client.on("chunk_radius_update",() => { client.writeMCPE('chunk_radius_update',{ chunk_radius:1 }); for (let x = -1; x <=1; x++) { for (let z = -1; z <=1; z++) { - client.writeBatch([{"name":"mcpe","params":{name:"full_chunk_data",params:{ + client.writeBatch([{name:"full_chunk_data",params:{ chunkX: x, chunkZ: z, order: 1, chunkData:fs.readFileSync(__dirname+"/chunk") - }}}]); + }}]); } } diff --git a/examples/server_simple.js b/examples/server_simple.js index 9773f2c..1cf2e15 100644 --- a/examples/server_simple.js +++ b/examples/server_simple.js @@ -17,7 +17,7 @@ var server = pmp.createServer({ server.on('connection', function(client) { client.on("mcpe", packet => console.log(packet)); - client.on("login", data => { + client.on("login_mcpe", data => { console.log(client.displayName + '(' + client.XUID + ') ' + ' joined the game'); }); diff --git a/src/createServer.js b/src/createServer.js index ade4d26..3a74b5c 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -106,7 +106,6 @@ function createServer(options) { client.encryptionEnabled = false; client.on("mcpe", packet => { - console.log("actual mcpe",packet); client.emit(packet.name, packet.params) }); @@ -159,10 +158,8 @@ function createServer(options) { client.encryptionEnabled = true; client.on("mcpe_encrypted", packet => { - console.log("raw",packet); decipher.write(packet); }); - decipher.on('data', data => console.log('decrypt', data)); client.cipher=crypto.createCipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0,16)); @@ -172,7 +169,7 @@ function createServer(options) { const packet=chunk.slice(0,chunk.length-8); const checksum=chunk.slice(chunk.length-8); const computedCheckSum=computeCheckSum(packet,[0,client.receiveCounter],client.secretKeyBytes); - //assert.equal(checksum.toString("hex"),computedCheckSum.toString("hex")); + assert.equal(checksum.toString("hex"),computedCheckSum.toString("hex")); client.receiveCounter++; if(checksum.toString("hex")==computedCheckSum.toString("hex")) this.push(packet); cb(); @@ -188,7 +185,6 @@ function createServer(options) { }); - checksumTransform.on("data",data => console.log('sliced',data)); decipher.pipe(checksumTransform); const proto=new ProtoDef(); proto.addTypes(require("./datatypes/minecraft")); @@ -196,19 +192,19 @@ function createServer(options) { client.mcpePacketParser=new Parser(proto,"mcpe_packet"); client.mcpePacketSerializer=new Serializer(proto,"mcpe_packet"); checksumTransform.pipe(client.mcpePacketParser); - client.mcpePacketParser.on("data",parsed => console.log("parsed data",parsed)); client.mcpePacketParser.on("data",parsed => {if(parsed.data.name=="batch") parsed.data.name="batch_non_encrypted"; return client.emitPacket(parsed)}); client.mcpePacketSerializer.pipe(client.addChecksumTransform); client.addChecksumTransform.pipe(client.cipher); + + client.cipher.on('data', data => client.writeEncapsulated("mcpe_encrypted", data)); }); client.writeMCPE = (name, params) => { if(client.encryptionEnabled) { + debug("write mcpe",name,params); client.mcpePacketSerializer.write({ name, params }); - client.cipher.on('data', data => console.log("crypted",data)); - client.cipher.on('data', data => client.writeEncapsulated("mcpe_encrypted", data)); } else { client.writeEncapsulated("mcpe", { name, params }); @@ -218,7 +214,7 @@ function createServer(options) { client.writeBatch = function(packets) { const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch", packets.map(packet => - client.encapsulatedPacketSerializer.createPacketBuffer(packet).slice(1)))); + client.mcpePacketSerializer.createPacketBuffer(packet)))); client.writeMCPE("batch", { payload: payload @@ -232,8 +228,7 @@ function createServer(options) { }); client.on('client_to_server_handshake',() => { - console.log("plop"); - client.emit('login', { + client.emit('login_mcpe', { displayName: client.displayName, randomId: client.randomId, skinData: client.skinData, From 315e32d634debe54b74de6e5df5fdf10df843235 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Tue, 21 Jun 2016 03:02:44 +0200 Subject: [PATCH 027/458] string of start_game is worldName (according to Intyre) --- data/protocol.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/protocol.json b/data/protocol.json index 2e0e36d..92a416c 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -903,7 +903,7 @@ "type": "bool" }, { - "name": "unknown", + "name": "worldName", "type": "string" } ] From d8ee61b7db471574adcdc474a841627f95577225 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Tue, 21 Jun 2016 03:03:52 +0200 Subject: [PATCH 028/458] worldName in server.js --- examples/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/server.js b/examples/server.js index 50d4a8a..7116391 100644 --- a/examples/server.js +++ b/examples/server.js @@ -51,7 +51,7 @@ server.on('connection', function(client) { isLoadedInCreative:0, dayCycleStopTime:0, eduMode:0, - unknown:"" + worldName:"" }); client.writeMCPE('set_spawn_position', { @@ -105,4 +105,4 @@ server.on('connection', function(client) { client.on('end',function() { console.log("client left"); }) -}); \ No newline at end of file +}); From 78cfd29aab4a31d6aa942aa0df2c98fda65c1b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 23 Jun 2016 04:12:09 +0200 Subject: [PATCH 029/458] Update protocol.json --- data/protocol.json | 99 ++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 47 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 92a416c..c262ca3 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -567,63 +567,68 @@ { "type": "u8", "mappings": { - "0x03": "server_to_client_handshake", - "0x04": "client_to_server_handshake", "0x01": "game_login", "0x02": "player_status", + "0x03": "server_to_client_handshake", + "0x04": "client_to_server_handshake", "0x05": "disconnect", "0x06": "batch", "0x07": "text", "0x08": "set_time", "0x09": "start_game", "0x0a": "add_player", - "0x0b": "remove_player", - "0x0c": "add_entity", - "0x0d": "remove_entity", - "0x0e": "add_item_entity", - "0x0f": "take_item_entity", - "0x10": "move_entity", - "0x11": "move_player", + "0x0b": "add_entity", + "0x0c": "remove_entity", + "0x0d": "add_item_entity", + "0x0e": "take_item_entity", + "0x0f": "move_entity", + "0x10": "move_player", + "0x11": "rider_jump", "0x12": "remove_block", "0x13": "update_block", "0x14": "add_painting", "0x15": "explode", "0x16": "level_event", - "0x17": "tile_event", + "0x17": "block_event", "0x18": "entity_event", "0x19": "mob_effect", "0x1a": "update_attributes", - "0x1b": "player_equipment", - "0x1c": "player_armor_equipment", + "0x1b": "mob_equipment", + "0x1c": "mob_armor_equipment", "0x1d": "interact", - "0x1e": "use_item", - "0x1f": "player_action", - "0x20": "hurt_armor", - "0x21": "set_entity_data", - "0x22": "set_entity_motion", - "0x23": "set_entity_link", - "0x24": "set_health", - "0x25": "set_spawn_position", - "0x26": "animate", - "0x27": "respawn", - "0x28": "drop_item", - "0x29": "container_open", - "0x2a": "container_close", - "0x2b": "container_set_slot", - "0x2c": "container_set_data", - "0x2d": "container_set_content", - "0x2e": "crafting_data", - "0x2f": "crafting_event", - "0x30": "adventure_settings", - "0x31": "tile_entity_data", - "0x32": "player_input", - "0x33": "full_chunk_data", - "0x34": "set_difficulty", - "0x37": "player_list", - "0x3c": "request_chunk_radius", - "0x3d": "chunk_radius_update", + "0x1f": "use_item", + "0x20": "player_action", + "0x21": "hurt_armor", + "0x22": "set_entity_data", + "0x23": "set_entity_motion", + "0x24": "set_entity_link", + "0x25": "set_health", + "0x26": "set_spawn_position", + "0x27": "animate", + "0x28": "respawn", + "0x29": "drop_item", + "0x2a": "container_open", + "0x2b": "container_close", + "0x2c": "container_set_slot", + "0x2d": "container_set_data", + "0x2e": "container_set_content", + "0x2f": "crafting_data", + "0x30": "crafting_event", + "0x31": "adventure_settings", + "0x32": "block_entity_data", + "0x33": "player_input", + "0x34": "full_chunk_data", + "0x35": "set_difficulty", + "0x36": "change_dimension", + "0x37": "set_player_gametype", + "0x38": "player_list", + "0x39": "telemetry_event", "0x3a": "spawn_experience_orb", - "0x3f": "replace_selected_item" + "0x3d": "request_chunk_radius", + "0x3e": "chunk_radius_update", + "0x3f": "item_frame_drop_item", + "0x40": "replace_selected_item", + "0x41": "add_item_item" } } ] @@ -657,12 +662,12 @@ "add_painting": "packet_add_painting", "explode": "packet_explode", "level_event": "packet_level_event", - "tile_event": "packet_tile_event", + "block_event": "packet_block_event", "entity_event": "packet_entity_event", "mob_effect": "packet_mob_effect", "update_attributes": "packet_update_attributes", - "player_equipment": "packet_player_equipment", - "player_armor_equipment": "packet_player_armor_equipment", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", "interact": "packet_interact", "use_item": "packet_use_item", "player_action": "packet_player_action", @@ -683,7 +688,7 @@ "crafting_data": "packet_crafting_data", "crafting_event": "packet_crafting_event", "adventure_settings": "packet_adventure_settings", - "tile_entity_data": "packet_tile_entity_data", + "block_entity_data": "packet_block_entity_data", "full_chunk_data": "packet_full_chunk_data", "set_difficulty": "packet_set_difficulty", "player_list": "packet_player_list", @@ -1253,7 +1258,7 @@ } ] ], - "packet_tile_event": [ + "packet_block_event": [ "container", [ { @@ -1333,7 +1338,7 @@ } ] ], - "packet_player_equipment": [ + "packet_mob_equipment": [ "container", [ { @@ -1354,7 +1359,7 @@ } ] ], - "packet_player_armor_equipment": [ + "packet_mob_armor_equipment": [ "container", [ { @@ -1769,7 +1774,7 @@ } ] ], - "packet_tile_entity_data": [ + "packet_block_entity_data": [ "container", [ { From 947a5e0872caabe861322df2d82d09013668b9b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 23 Jun 2016 20:53:19 +0200 Subject: [PATCH 030/458] Update createServer.js --- src/createServer.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 3a74b5c..60904e3 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -118,31 +118,21 @@ function createServer(options) { var clientData = parsed.data.clientData; var chain1 = parsed.data.chain.chain[0]; - var chain2 = parsed.data.chain.chain[1].replace('\n', ''); + var chain2 = parsed.data.chain.chain[1]; var decode1 = jwt.decode(chain1, PUBLIC_KEY, 'ES384'); var nextKey1 = decode1.identityPublicKey; - var decode2 = jwt.decode(chain2, nextKey1, 'ES384'); - var nextKey2 = decode2.identityPublicKey; - var clientDecode = jwt.decode(clientData, nextKey1, 'ES384'); client.randomId = clientDecode.ClientRandomId; client.skinData = clientDecode.SkinData; client.skinId = clientDecode.SkinId; - client.identity = decode2.extraData.identity; - client.displayName = decode2.extraData.displayName; - client.XUID = decode2.extraData.XUID; - - var pubKeyClient = readX509PublicKey(nextKey2); var ec = crypto.createECDH('secp384r1'); ec.generateKeys(); - client.sharedSecret = ec.computeSecret(pubKeyClient); client.secretKeyBytes = crypto.createHash('sha256'); - client.secretKeyBytes.update("SO SECRET VERY SECURE"); - client.secretKeyBytes.update(client.sharedSecret); + client.secretKeyBytes.update("SO SECRET VERY SECURE");; client.secretKeyBytes = client.secretKeyBytes.digest(); let pubKeyServer=writeX509PublicKey(ec.getPublicKey()); From 82fba41ae15a4869a1e70a2d3225bc436e1e2189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 23 Jun 2016 22:03:37 +0200 Subject: [PATCH 031/458] Update createServer.js --- src/createServer.js | 91 ++++----------------------------------------- 1 file changed, 7 insertions(+), 84 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 60904e3..1dec6a0 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -105,95 +105,18 @@ function createServer(options) { client.encryptionEnabled = false; + let proto = new ProtoDef(); + proto.addTypes(require("./datatypes/minecraft")); + proto.addTypes(require("../data/protocol").types); + client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); + client.on("mcpe", packet => { client.emit(packet.name, packet.params) }); - - - client.on("game_login", packet => { - var body = packet.body; - var body2 = zlib.inflateSync(body); - var parsed = dataProto.parsePacketBuffer("data_chain", body2); - parsed.data.chain = JSON.parse(parsed.data.chain); - - var clientData = parsed.data.clientData; - var chain1 = parsed.data.chain.chain[0]; - var chain2 = parsed.data.chain.chain[1]; - - var decode1 = jwt.decode(chain1, PUBLIC_KEY, 'ES384'); - var nextKey1 = decode1.identityPublicKey; - - var clientDecode = jwt.decode(clientData, nextKey1, 'ES384'); - client.randomId = clientDecode.ClientRandomId; - client.skinData = clientDecode.SkinData; - client.skinId = clientDecode.SkinId; - - var ec = crypto.createECDH('secp384r1'); - ec.generateKeys(); - - client.secretKeyBytes = crypto.createHash('sha256'); - client.secretKeyBytes.update("SO SECRET VERY SECURE");; - client.secretKeyBytes = client.secretKeyBytes.digest(); - - let pubKeyServer=writeX509PublicKey(ec.getPublicKey()); - client.writeMCPE('server_to_client_handshake', { - publicKey: pubKeyServer, - serverToken: "SO SECRET VERY SECURE" // obviously, this is super secure (it's not, change it) - }); - var decipher = crypto.createDecipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0,16)); - let customPackets=JSON.parse(JSON.stringify(require("../data/protocol"))); - customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe_encrypted'] = 'restBuffer'; - customPackets['types']['encapsulated_packet'][1][0]['type'][1]['mappings']['0xfe'] = 'mcpe_encrypted'; - client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol, customPackets).types); - client.encryptionEnabled = true; - - client.on("mcpe_encrypted", packet => { - decipher.write(packet); - }); - - client.cipher=crypto.createCipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0,16)); - - - const checksumTransform = new Transform({ - transform(chunk,enc,cb) { - const packet=chunk.slice(0,chunk.length-8); - const checksum=chunk.slice(chunk.length-8); - const computedCheckSum=computeCheckSum(packet,[0,client.receiveCounter],client.secretKeyBytes); - assert.equal(checksum.toString("hex"),computedCheckSum.toString("hex")); - client.receiveCounter++; - if(checksum.toString("hex")==computedCheckSum.toString("hex")) this.push(packet); - cb(); - } - }); - client.addChecksumTransform = new Transform({ - transform(chunk,enc,cb) { - const packet=Buffer.concat([chunk,computeCheckSum(chunk,[0,client.sendCounter],client.secretKeyBytes)]); - client.sendCounter++; - this.push(packet); - cb(); - } - }); - - - decipher.pipe(checksumTransform); - const proto=new ProtoDef(); - proto.addTypes(require("./datatypes/minecraft")); - proto.addTypes(require("../data/protocol").types); - client.mcpePacketParser=new Parser(proto,"mcpe_packet"); - client.mcpePacketSerializer=new Serializer(proto,"mcpe_packet"); - checksumTransform.pipe(client.mcpePacketParser); - client.mcpePacketParser.on("data",parsed => {if(parsed.data.name=="batch") parsed.data.name="batch_non_encrypted"; return client.emitPacket(parsed)}); - - - client.mcpePacketSerializer.pipe(client.addChecksumTransform); - client.addChecksumTransform.pipe(client.cipher); - - client.cipher.on('data', data => client.writeEncapsulated("mcpe_encrypted", data)); - }); - + client.writeMCPE = (name, params) => { if(client.encryptionEnabled) { - debug("write mcpe",name,params); + debug("write mcpe", name, params); client.mcpePacketSerializer.write({ name, params }); } else { From 5b1f1ab1627b45856d45ea4edb1945c2d0bd729e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 23 Jun 2016 22:03:52 +0200 Subject: [PATCH 032/458] Update protocol.json --- data/protocol.json | 1 + 1 file changed, 1 insertion(+) diff --git a/data/protocol.json b/data/protocol.json index c262ca3..340f0dc 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -689,6 +689,7 @@ "crafting_event": "packet_crafting_event", "adventure_settings": "packet_adventure_settings", "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", "full_chunk_data": "packet_full_chunk_data", "set_difficulty": "packet_set_difficulty", "player_list": "packet_player_list", From b4ed008d647a7f9a9c47ae3c89363f1afb1f58a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 26 Oct 2016 14:34:00 +0200 Subject: [PATCH 033/458] Update mappings to 0.16. --- data/protocol.json | 112 ++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 340f0dc..fe45c84 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -573,62 +573,62 @@ "0x04": "client_to_server_handshake", "0x05": "disconnect", "0x06": "batch", - "0x07": "text", - "0x08": "set_time", - "0x09": "start_game", - "0x0a": "add_player", - "0x0b": "add_entity", - "0x0c": "remove_entity", - "0x0d": "add_item_entity", - "0x0e": "take_item_entity", - "0x0f": "move_entity", - "0x10": "move_player", - "0x11": "rider_jump", - "0x12": "remove_block", - "0x13": "update_block", - "0x14": "add_painting", - "0x15": "explode", - "0x16": "level_event", - "0x17": "block_event", - "0x18": "entity_event", - "0x19": "mob_effect", - "0x1a": "update_attributes", - "0x1b": "mob_equipment", - "0x1c": "mob_armor_equipment", - "0x1d": "interact", - "0x1f": "use_item", - "0x20": "player_action", - "0x21": "hurt_armor", - "0x22": "set_entity_data", - "0x23": "set_entity_motion", - "0x24": "set_entity_link", - "0x25": "set_health", - "0x26": "set_spawn_position", - "0x27": "animate", - "0x28": "respawn", - "0x29": "drop_item", - "0x2a": "container_open", - "0x2b": "container_close", - "0x2c": "container_set_slot", - "0x2d": "container_set_data", - "0x2e": "container_set_content", - "0x2f": "crafting_data", - "0x30": "crafting_event", - "0x31": "adventure_settings", - "0x32": "block_entity_data", - "0x33": "player_input", - "0x34": "full_chunk_data", - "0x35": "set_difficulty", - "0x36": "change_dimension", - "0x37": "set_player_gametype", - "0x38": "player_list", - "0x39": "telemetry_event", - "0x3a": "spawn_experience_orb", - "0x3d": "request_chunk_radius", - "0x3e": "chunk_radius_update", - "0x3f": "item_frame_drop_item", - "0x40": "replace_selected_item", - "0x41": "add_item_item" + "0x0a": "text", + "0x0b": "set_time", + "0x0c": "start_game", + "0x0d": "add_player", + "0x0e": "add_entity", + "0x0f": "remove_entity", + "0x10": "add_item_entity", + "0x12": "take_item_entity", + "0x13": "move_entity", + "0x14": "move_player", + "0x15": "rider_jump", + "0x16": "remove_block", + "0x17": "update_block", + "0x18": "add_painting", + "0x19": "explode", + "0x1a": "level_event", + "0x1c": "block_event", + "0x1d": "entity_event", + "0x1e": "mob_effect", + "0x1f": "update_attributes", + "0x20": "mob_equipment", + "0x21": "mob_armor_equipment", + "0x22": "interact", + "0x23": "use_item", + "0x24": "player_action", + "0x25": "hurt_armor", + "0x26": "set_entity_data", + "0x27": "set_entity_motion", + "0x28": "set_entity_link", + "0x29": "set_health", + "0x2a": "set_spawn_position", + "0x2b": "animate", + "0x2c": "respawn", + "0x2d": "drop_item", + "0x2f": "container_open", + "0x30": "container_close", + "0x31": "container_set_slot", + "0x32": "container_set_data", + "0x33": "container_set_content", + "0x34": "crafting_data", + "0x35": "crafting_event", + "0x36": "adventure_settings", + "0x37": "block_entity_data", + "0x38": "player_input", + "0x39": "full_chunk_data", + "0x3b": "set_difficulty", + "0x3c": "change_dimension", + "0x3d": "set_player_gametype", + "0x3e": "player_list", + "0x3f": "telemetry_event", + "0x40": "spawn_experience_orb", + "0x43": "request_chunk_radius", + "0x44": "chunk_radius_update", + "0x45": "item_frame_drop_item", + "0x46": "replace_selected_item", + "0x49": "add_item_item" } } ] From 5f42967845749b92b97b4640984fa771c2344b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 26 Oct 2016 14:34:46 +0200 Subject: [PATCH 034/458] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 813b64b..d6110a5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Parse and serialize Minecraft PE packets. ## Features - * Supports Minecraft PE `0.14.3` and `0.15.0` + * Supports Minecraft Pocket Edition `0.16.0` * Pure JavaScript * Easily send and listen for any packet * RakNet support through [node-raknet](https://github.com/mhsjlw/node-raknet) @@ -23,5 +23,6 @@ Then view our `examples` for inspiration! ## Contributors This project is run by these guys: + - [Filiph Sandström](https://github.com/filfat) - [mhsjlw](https://github.com/mhsjlw) - [rom1504](https://github.com/rom1504) From c7d9191420e420c3f94967a5742fd437815f9d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 26 Oct 2016 15:05:07 +0200 Subject: [PATCH 035/458] Update to 4 tabs. --- data/protocol.json | 3914 ++++++++++++++++++++++---------------------- 1 file changed, 1976 insertions(+), 1938 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index fe45c84..5139f1e 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -1,1964 +1,2002 @@ { - "types": { - "string": [ - "pstring", - { - "countType":"i16" - } - ], - "lstring": [ - "pstring", - { - "countType":"li16" - } - ], - "shapeless_recipe": [ - "container", - [ - { - "name":"ingredientList", - "type": - [ - "array", + "types":{ + "string":[ + "pstring", { - "countType":"i32", - "type":"slot" + "countType":"i16" } - ] - }, - { - "name": "resultCount", - "type": "i32" - }, - { - "name": "slot", - "type": "slot" - }, - { - "name": "id", - "type": "uuid" - } - ] - ], - "shaped_recipe": [ - "container", - [ - { - "name": "width", - "type": [ - "count", { - "type": "i32", - "countFor": "shape" - } - ] - }, - { - "name": "height", - "type": [ - "count", + ], + "lstring":[ + "pstring", { - "type": "i32", - "countFor": "shape/0" + "countType":"li16" } - ] - }, - { - "name": "shape", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", + ], + "shapeless_recipe":[ + "container", + [ { - "count": "height", - "type": "slot" + "name":"ingredientList", + "type":[ + "array", + { + "countType":"i32", + "type":"slot" + } + ] + }, + { + "name":"resultCount", + "type":"i32" + }, + { + "name":"slot", + "type":"slot" + }, + { + "name":"id", + "type":"uuid" } - ] - } - ] - }, - { - "name": "resultCount", - "type": "i32" - }, - { - "name": "slot", - "type": "slot" - }, - { - "name": "id", - "type": "uuid" - } - ] - ], - "furnace_recipe": [ - "container", - [ - { - "name": "meta", - "type": "i16" - }, - { - "name": "id", - "type": "i16" - }, - { - "name": "result", - "type": "slot" - } - ] - ], - "furnace_recipe_data": [ - "container", - [ - { - "name": "id", - "type": "i16" - }, - { - "name": "meta", - "type": "i16" - }, - { - "name": "result", - "type": "slot" - } - ] - ], - "enchant_list": [ - "array", - { - "countType": "i8", - "type": [ - "container", - [ - { - "name": "cost", - "type": "i32" - }, - { - "name": "enchantments", - "type": [ - "array", + ] + ], + "shaped_recipe":[ + "container", + [ { - "countType": "i8", - "type": [ + "name":"width", + "type":[ + "count", + { + "type":"i32", + "countFor":"shape" + } + ] + }, + { + "name":"height", + "type":[ + "count", + { + "type":"i32", + "countFor":"shape/0" + } + ] + }, + { + "name":"shape", + "type":[ + "array", + { + "count":"width", + "type":[ + "array", + { + "count":"height", + "type":"slot" + } + ] + } + ] + }, + { + "name":"resultCount", + "type":"i32" + }, + { + "name":"slot", + "type":"slot" + }, + { + "name":"id", + "type":"uuid" + } + ] + ], + "furnace_recipe":[ + "container", + [ + { + "name":"meta", + "type":"i16" + }, + { + "name":"id", + "type":"i16" + }, + { + "name":"result", + "type":"slot" + } + ] + ], + "furnace_recipe_data":[ + "container", + [ + { + "name":"id", + "type":"i16" + }, + { + "name":"meta", + "type":"i16" + }, + { + "name":"result", + "type":"slot" + } + ] + ], + "enchant_list":[ + "array", + { + "countType":"i8", + "type":[ "container", [ - { - "name": "id", - "type": "i32" - }, - { - "name": "level", - "type": "i32" - } - ] - ] - } - ] - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "entityMetadataItem": [ - "switch", - { - "compareTo": "$compareTo", - "fields": { - "0": "li8", - "1": "li16", - "2": "li32", - "3": "lf32", - "4": "lstring", - "5": ["container",[ - { - "name":"blockId", - "type":"li16" - }, - { - "name":"itemCount", - "type":"li8" - }, - { - "name":"itemDamage", - "type":"li16" - } - ]], - "6": [ - "container", - [ - { - "name": "x", - "type": "li32" - }, - { - "name": "y", - "type": "li32" - }, - { - "name": "z", - "type": "li32" - } - ] - ], - "7": [ - "container", - [ - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "roll", - "type": "lf32" - } - ] - ], - "8": "li64" - } - } - ], - "metadatadictionary": [ - "entityMetadataLoop", - { - "endVal": 127, - "type": [ - "container", - [ - { - "anon": true, - "type": [ - "bitfield", - [ - { - "name": "type", - "size": 3, - "signed": false - }, - { - "name": "key", - "size": 5, - "signed": false - } - ] - ] - }, - { - "name": "value", - "type": [ - "entityMetadataItem", - { - "compareTo": "type" - } - ] - } - ] - ] - } - ], - "slot": [ - "container", - [ - { - "name": "blockId", - "type": "i16" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "blockId", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "itemCount", - "type": "i8" - }, - { - "name": "itemDamage", - "type": "i16" - }, - { - "name": "nbtData", - "type": ["buffer",{"countType":"li16"}] - } - ] - ] - } - ] - } - ] - ], - "itemstacks": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "slot", - "type": "itemstacks" - } - ] - ] - } - ], - "skin": [ - "container", - [ - { - "name": "skin_type", - "type": "string" - }, - { - "name": "texture", - "type": ["buffer",{"countType":"i16"}] - } - ] - ], - "blockrecords": [ - "array", - { - "countType":"i32", - "type": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "y", - "type": "i8" - }, - { - "name": "blockId", - "type": "i8" - }, - { - "anon": true, - "type": [ - "bitfield", - [ - { - "name": "blockData", - "size": 4, - "signed": false - }, - { - "name": "flags", - "size": 4, - "signed": false - } - ] - ] - } - ] - ] - } - ], - "records": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "x", - "type": "i8" - }, - { - "name": "y", - "type": "i8" - }, - { - "name": "z", - "type": "i8" - } - ] - ] - } - ], - "playerattributes": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "minValue", - "type": "f32" - }, - { - "name": "maxValue", - "type": "f32" - }, - { - "name": "id", - "type": "f32" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "entitymotions": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "eid", - "type": "i64" - }, - { - "name": "motX", - "type": "f32" - }, - { - "name": "motY", - "type": "f32" - }, - { - "name": "motZ", - "type": "f32" - } - ] - ] - } - ], - "vector3": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - } - ] - ], - "blockcoordinates": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - } - ] - ], - "entitylocations": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ - { - "name": "eid", - "type": "i64" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "headYaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - } - ] - ] - } - ], - "encapsulated_packet":[ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0xfe": "mcpe" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "mcpe":"mcpe_packet" - } - } - ] - } - ] - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0x01": "game_login", - "0x02": "player_status", - "0x03": "server_to_client_handshake", - "0x04": "client_to_server_handshake", - "0x05": "disconnect", - "0x06": "batch", - "0x0a": "text", - "0x0b": "set_time", - "0x0c": "start_game", - "0x0d": "add_player", - "0x0e": "add_entity", - "0x0f": "remove_entity", - "0x10": "add_item_entity", - "0x12": "take_item_entity", - "0x13": "move_entity", - "0x14": "move_player", - "0x15": "rider_jump", - "0x16": "remove_block", - "0x17": "update_block", - "0x18": "add_painting", - "0x19": "explode", - "0x1a": "level_event", - "0x1c": "block_event", - "0x1d": "entity_event", - "0x1e": "mob_effect", - "0x1f": "update_attributes", - "0x20": "mob_equipment", - "0x21": "mob_armor_equipment", - "0x22": "interact", - "0x23": "use_item", - "0x24": "player_action", - "0x25": "hurt_armor", - "0x26": "set_entity_data", - "0x27": "set_entity_motion", - "0x28": "set_entity_link", - "0x29": "set_health", - "0x2a": "set_spawn_position", - "0x2b": "animate", - "0x2c": "respawn", - "0x2d": "drop_item", - "0x2f": "container_open", - "0x30": "container_close", - "0x31": "container_set_slot", - "0x32": "container_set_data", - "0x33": "container_set_content", - "0x34": "crafting_data", - "0x35": "crafting_event", - "0x36": "adventure_settings", - "0x37": "block_entity_data", - "0x38": "player_input", - "0x39": "full_chunk_data", - "0x3b": "set_difficulty", - "0x3c": "change_dimension", - "0x3d": "set_player_gametype", - "0x3e": "player_list", - "0x3f": "telemetry_event", - "0x40": "spawn_experience_orb", - "0x43": "request_chunk_radius", - "0x44": "chunk_radius_update", - "0x45": "item_frame_drop_item", - "0x46": "replace_selected_item", - "0x49": "add_item_item" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "game_login": "packet_game_login", - "player_status": "packet_player_status", - "disconnect": "packet_disconnect", - "batch": "packet_batch", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "remove_player": "packet_remove_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "remove_block": "packet_remove_block", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "explode": "packet_explode", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "use_item": "packet_use_item", - "player_action": "packet_player_action", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "drop_item": "packet_drop_item", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "container_set_slot": "packet_container_set_slot", - "container_set_data": "packet_container_set_data", - "container_set_content": "packet_container_set_content", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "full_chunk_data": "packet_full_chunk_data", - "set_difficulty": "packet_set_difficulty", - "player_list": "packet_player_list", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "transfer": "packet_transfer", - "spawn_experience_orb": "packet_spawn_experience_orb", - "replace_selected_item": "packet_replace_selected_item" - } - } - ] - } - ] - ], - "packet_id_detect_lost_connections": [ - "container", - [] - ], - "packet_id_no_free_incoming_connections": [ - "container", - [] - ], - "packet_id_connection_banned": [ - "container", - [] - ], - "packet_id_ip_recently_connected": [ - "container", - [] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "publicKey", - "type": "string" - }, - { - "name": "serverToken", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [ - ] - ], - "packet_game_login": [ - "container", - [ - { - "name": "protocol", - "type": "i32" - }, - { - "name": "body", - "type": ["buffer",{"countType":"i32"}] - } - ] - ], - "packet_player_status": [ - "container", - [ - { - "name": "status", - "type": "i32" - } - ] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "packet_batch": [ - "container", - [ - { - "name": "payload", - "type":["buffer",{"countType":"i32"}] - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": "i8" - }, - { - "name": "name", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "1": "string", - "3": "string" - }, - "default": "void" - } - ] - }, - { - "name": "message", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "0": "string", - "1": "string", - "2": "string", - "3": "string", - "4": "string", - "5": "string" - } - } - ] - }, - { - "name": "parameters", - "type": [ - "switch", - { - "compareTo": "type", - "fields":{ - "2":[ - "array", { - "countType":"i8", - "type":"string" - } - ] - }, - "default":"void" - } - ] - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "i32" - }, - { - "name": "started", - "type": "i8" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "seed", - "type": "i32" - }, - { - "name": "dimension", - "type": "i8" - }, - { - "name": "generator", - "type": "i32" - }, - { - "name": "gamemode", - "type": "i8" - }, - { - "name": "entityId", - "type": "i64" - }, - { - "name": "spawnX", - "type": "i32" - }, - { - "name": "spawnY", - "type": "i32" - }, - { - "name": "spawnZ", - "type": "i32" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "isLoadedInCreative", - "type": "bool" - }, - { - "name": "dayCycleStopTime", - "type": "i8" - }, - { - "name": "eduMode", - "type": "bool" - }, - { - "name": "worldName", - "type": "string" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entityId", - "type": "i64" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "speedX", - "type": "f32" - }, - { - "name": "speedY", - "type": "f32" - }, - { - "name": "speedZ", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "headYaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "item", - "type": "slot" - }, - { - "name": "metadata", - "type": "metadatadictionary" - } - ] - ], - "packet_remove_player": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "clientUuid", - "type": "uuid" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "entityType", - "type": "i32" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "speedX", - "type": "f32" - }, - { - "name": "speedY", - "type": "f32" - }, - { - "name": "speedZ", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "metadata", - "type": "metadatadictionary" - }, - { - "name": "links", - "type": "i16" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "item", - "type": "slot" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "speedX", - "type": "f32" - }, - { - "name": "speedY", - "type": "f32" - }, - { - "name": "speedZ", - "type": "f32" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "target", - "type": "i64" - }, - { - "name": "entityId", - "type": "i64" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "entities", - "type": "entitylocations" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "headYaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "mode", - "type": "i8" - }, - { - "name": "onGround", - "type": "i8" - } - ] - ], - "packet_remove_block": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "y", - "type": "i8" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "blocks", - "type": "blockrecords" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "direction", - "type": "i32" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_explode": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "radius", - "type": "f32" - }, - { - "name": "records", - "type": "records" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "eventId", - "type": "i16" - }, - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - }, - { - "name": "data", - "type": "i32" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "case1", - "type": "i32" - }, - { - "name": "case2", - "type": "i32" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "eventId", - "type": "i8" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "eventId", - "type": "i8" - }, - { - "name": "effectId", - "type": "i8" - }, - { - "name": "amplifier", - "type": "i8" - }, - { - "name": "particles", - "type": "i8" - }, - { - "name": "duration", - "type": "i32" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "attributes", - "type": "playerattributes" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "item", - "type": "slot" - }, - { - "name": "slot", - "type": "i8" - }, - { - "name": "selectedSlot", - "type": "i8" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "helmet", - "type": "slot" - }, - { - "name": "chestplate", - "type": "slot" - }, - { - "name": "leggings", - "type": "slot" - }, - { - "name": "boots", - "type": "slot" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "actionId", - "type": "i8" - }, - { - "name": "targetEntityId", - "type": "i64" - } - ] - ], - "packet_use_item": [ - "container", - [ - { - "name": "blockcoordinates", - "type": "blockcoordinates" - }, - { - "name": "face", - "type": "i8" - }, - { - "name": "facecoordinates", - "type": "vector3" - }, - { - "name": "playerposition", - "type": "vector3" - }, - { - "name": "slot", - "type": "i32" - }, - { - "name": "item", - "type": "slot" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "actionId", - "type": "i32" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "face", - "type": "i32" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "i8" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "entity_id", - "type": "i64" - }, - { - "name": "metadata", - "type": "metadatadictionary" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "entities", - "type": "entitymotions" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "riderId", - "type": "i64" - }, - { - "name": "riddenId", - "type": "i64" - }, - { - "name": "linkType", - "type": "i8" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "i32" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "actionId", - "type": "i8" - }, - { - "name": "entityId", - "type": "i64" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - }, - { - "name": "z", - "type": "f32" - } - ] - ], - "packet_drop_item": [ - "container", - [ - { - "name": "itemtype", - "type": "i8" - }, - { - "name": "item", - "type": "slot" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "windowId", - "type": "i8" - }, - { - "name": "type", - "type": "i8" - }, - { - "name": "slotCount", - "type": "i16" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "windowId", - "type": "i8" - } - ] - ], - "packet_container_set_slot": [ - "container", - [ - { - "name": "windowId", - "type": "i8" - }, - { - "name": "slot", - "type": "i16" - }, - { - "name": "unknown", - "type": "i16" - }, - { - "name": "item", - "type": "slot" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "windowId", - "type": "i8" - }, - { - "name": "property", - "type": "i16" - }, - { - "name": "value", - "type": "i16" - } - ] - ], - "packet_container_set_content": [ - "container", - [ - { - "name": "windowId", - "type": "i8" - }, - { - "name": "slotData", - "type": "itemstacks" - }, - { - "name": "hotbarData", - "type": [ - "switch", - { - "compareTo": "windowId", - "fields": { - "0": [ - "array", - { - "countType":"i16", - "type": [ - "container", - [ { - "name": "slot", - "type": "i32" + "name":"cost", + "type":"i32" + }, + { + "name":"enchantments", + "type":[ + "array", + { + "countType":"i8", + "type":[ + "container", + [ + { + "name":"id", + "type":"i32" + }, + { + "name":"level", + "type":"i32" + } + ] + ] + } + ] + }, + { + "name":"name", + "type":"string" } - ] ] - } ] - }, - "default": "i16" } - ] - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": [ + ], + "entityMetadataItem":[ + "switch", + { + "compareTo":"$compareTo", + "fields":{ + "0":"li8", + "1":"li16", + "2":"li32", + "3":"lf32", + "4":"lstring", + "5":[ + "container", + [ + { + "name":"blockId", + "type":"li16" + }, + { + "name":"itemCount", + "type":"li8" + }, + { + "name":"itemDamage", + "type":"li16" + } + ] + ], + "6":[ + "container", + [ + { + "name":"x", + "type":"li32" + }, + { + "name":"y", + "type":"li32" + }, + { + "name":"z", + "type":"li32" + } + ] + ], + "7":[ + "container", + [ + { + "name":"pitch", + "type":"lf32" + }, + { + "name":"yaw", + "type":"lf32" + }, + { + "name":"roll", + "type":"lf32" + } + ] + ], + "8":"li64" + } + } + ], + "metadatadictionary":[ + "entityMetadataLoop", + { + "endVal":127, + "type":[ + "container", + [ + { + "anon":true, + "type":[ + "bitfield", + [ + { + "name":"type", + "size":3, + "signed":false + }, + { + "name":"key", + "size":5, + "signed":false + } + ] + ] + }, + { + "name":"value", + "type":[ + "entityMetadataItem", + { + "compareTo":"type" + } + ] + } + ] + ] + } + ], + "slot":[ "container", [ - { - "name": "entryType", - "type": "i32" - }, - { - "name": "recipe", - "type": [ - "array", - { - "countType": "i32", - "type": [ - "switch", - { - "compareTo": "entryType", - "fields": { - "0": "shapelessRecipe", - "1": "shapedRecipe", - "2": "furnaceRecipe", - "3": "furnaceRecipeData", - "4": "enchantList" - }, - "default":"void" - } + { + "name":"blockId", + "type":"i16" + }, + { + "anon":true, + "type":[ + "switch", + { + "compareTo":"blockId", + "fields":{ + "0":"void" + }, + "default":[ + "container", + [ + { + "name":"itemCount", + "type":"i8" + }, + { + "name":"itemDamage", + "type":"i16" + }, + { + "name":"nbtData", + "type":[ + "buffer", + { + "countType":"li16" + } + ] + } + ] + ] + } ] - } - ] - } + } ] - ] - }, - { - "name": "cleanRecipes", - "type": "i8" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "windowId", - "type": "i8" - }, - { - "name": "recipeType", - "type": "i32" - }, - { - "name": "recipeId", - "type": "uuid" - }, - { - "name": "input", - "type": "itemstacks" - }, - { - "name": "result", - "type": "itemstacks" - } - ] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "i32" - }, - { - "name": "userPermission", - "type": "i32" - }, - { - "name": "globalPermission", - "type": "i32" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "namedtag", - "type": "restBuffer" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motionX", - "type": "f32" - }, - { - "name": "motionZ", - "type": "f32" - }, - { - "name": "flags", - "type": "i16" - } - ] - ], - "packet_full_chunk_data": [ - "container", - [ - { - "name": "chunkX", - "type": "i32" - }, - { - "name": "chunkZ", - "type": "i32" - }, - { - "name": "order", - "type": "i8" - }, - { - "name": "chunkData", - "type":["buffer",{"countType":"i32"}] - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "i32" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "type", - "type": "i8" - }, - { - "name": "entries", - "type": [ + ], + "itemstacks":[ "array", { - "countType": "i32", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "0": [ - "container", - [ + "countType":"i16", + "type":[ + "container", + [ { - "name": "clientUuid", - "type": "uuid" - }, - { - "name": "entityId", - "type": "i64" - }, - { - "name": "displayName", - "type": "string" - }, - { - "name": "skin", - "type": "skin" + "name":"slot", + "type":"itemstacks" } - ] - ], - "1": [ - "container", - [ - { - "name": "clientUuid", - "type": "uuid" - } - ] ] - } - } - ] + ] } - ] - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunkRadius", - "type": "i32" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunkRadius", - "type": "i32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "endpoint", - "type": "ipAddress" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "entityId", - "type": "i64" - }, - { - "name": "x", - "type": "i32" - }, - { - "name": "y", - "type": "i32" - }, - { - "name": "z", - "type": "i32" - }, - { - "name": "count", - "type": "i32" - } - ] - ], - "packet_replace_selected_item": [ - "container", - [ - { - "name": "slot", - "type": "slot" - } - ] - ] - } + ], + "skin":[ + "container", + [ + { + "name":"skin_type", + "type":"string" + }, + { + "name":"texture", + "type":[ + "buffer", + { + "countType":"i16" + } + ] + } + ] + ], + "blockrecords":[ + "array", + { + "countType":"i32", + "type":[ + "container", + [ + { + "name":"x", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"y", + "type":"i8" + }, + { + "name":"blockId", + "type":"i8" + }, + { + "anon":true, + "type":[ + "bitfield", + [ + { + "name":"blockData", + "size":4, + "signed":false + }, + { + "name":"flags", + "size":4, + "signed":false + } + ] + ] + } + ] + ] + } + ], + "records":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"x", + "type":"i8" + }, + { + "name":"y", + "type":"i8" + }, + { + "name":"z", + "type":"i8" + } + ] + ] + } + ], + "playerattributes":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"minValue", + "type":"f32" + }, + { + "name":"maxValue", + "type":"f32" + }, + { + "name":"id", + "type":"f32" + }, + { + "name":"name", + "type":"string" + } + ] + ] + } + ], + "entitymotions":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"eid", + "type":"i64" + }, + { + "name":"motX", + "type":"f32" + }, + { + "name":"motY", + "type":"f32" + }, + { + "name":"motZ", + "type":"f32" + } + ] + ] + } + ], + "vector3":[ + "container", + [ + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + } + ] + ], + "blockcoordinates":[ + "container", + [ + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + } + ] + ], + "entitylocations":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"eid", + "type":"i64" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"yaw", + "type":"f32" + }, + { + "name":"headYaw", + "type":"f32" + }, + { + "name":"pitch", + "type":"f32" + } + ] + ] + } + ], + "encapsulated_packet":[ + "container", + [ + { + "name":"name", + "type":[ + "mapper", + { + "type":"u8", + "mappings":{ + "0xfe":"mcpe" + } + } + ] + }, + { + "name":"params", + "type":[ + "switch", + { + "compareTo":"name", + "fields":{ + "mcpe":"mcpe_packet" + } + } + ] + } + ] + ], + "mcpe_packet":[ + "container", + [ + { + "name":"name", + "type":[ + "mapper", + { + "type":"u8", + "mappings":{ + "0x01":"game_login", + "0x02":"player_status", + "0x03":"server_to_client_handshake", + "0x04":"client_to_server_handshake", + "0x05":"disconnect", + "0x06":"batch", + "0x0a":"text", + "0x0b":"set_time", + "0x0c":"start_game", + "0x0d":"add_player", + "0x0e":"add_entity", + "0x0f":"remove_entity", + "0x10":"add_item_entity", + "0x12":"take_item_entity", + "0x13":"move_entity", + "0x14":"move_player", + "0x15":"rider_jump", + "0x16":"remove_block", + "0x17":"update_block", + "0x18":"add_painting", + "0x19":"explode", + "0x1a":"level_event", + "0x1c":"block_event", + "0x1d":"entity_event", + "0x1e":"mob_effect", + "0x1f":"update_attributes", + "0x20":"mob_equipment", + "0x21":"mob_armor_equipment", + "0x22":"interact", + "0x23":"use_item", + "0x24":"player_action", + "0x25":"hurt_armor", + "0x26":"set_entity_data", + "0x27":"set_entity_motion", + "0x28":"set_entity_link", + "0x29":"set_health", + "0x2a":"set_spawn_position", + "0x2b":"animate", + "0x2c":"respawn", + "0x2d":"drop_item", + "0x2f":"container_open", + "0x30":"container_close", + "0x31":"container_set_slot", + "0x32":"container_set_data", + "0x33":"container_set_content", + "0x34":"crafting_data", + "0x35":"crafting_event", + "0x36":"adventure_settings", + "0x37":"block_entity_data", + "0x38":"player_input", + "0x39":"full_chunk_data", + "0x3b":"set_difficulty", + "0x3c":"change_dimension", + "0x3d":"set_player_gametype", + "0x3e":"player_list", + "0x3f":"telemetry_event", + "0x40":"spawn_experience_orb", + "0x43":"request_chunk_radius", + "0x44":"chunk_radius_update", + "0x45":"item_frame_drop_item", + "0x46":"replace_selected_item", + "0x49":"add_item_item" + } + } + ] + }, + { + "name":"params", + "type":[ + "switch", + { + "compareTo":"name", + "fields":{ + "server_to_client_handshake":"packet_server_to_client_handshake", + "client_to_server_handshake":"packet_client_to_server_handshake", + "game_login":"packet_game_login", + "player_status":"packet_player_status", + "disconnect":"packet_disconnect", + "batch":"packet_batch", + "text":"packet_text", + "set_time":"packet_set_time", + "start_game":"packet_start_game", + "add_player":"packet_add_player", + "remove_player":"packet_remove_player", + "add_entity":"packet_add_entity", + "remove_entity":"packet_remove_entity", + "add_item_entity":"packet_add_item_entity", + "take_item_entity":"packet_take_item_entity", + "move_entity":"packet_move_entity", + "move_player":"packet_move_player", + "remove_block":"packet_remove_block", + "update_block":"packet_update_block", + "add_painting":"packet_add_painting", + "explode":"packet_explode", + "level_event":"packet_level_event", + "block_event":"packet_block_event", + "entity_event":"packet_entity_event", + "mob_effect":"packet_mob_effect", + "update_attributes":"packet_update_attributes", + "mob_equipment":"packet_mob_equipment", + "mob_armor_equipment":"packet_mob_armor_equipment", + "interact":"packet_interact", + "use_item":"packet_use_item", + "player_action":"packet_player_action", + "hurt_armor":"packet_hurt_armor", + "set_entity_data":"packet_set_entity_data", + "set_entity_motion":"packet_set_entity_motion", + "set_entity_link":"packet_set_entity_link", + "set_health":"packet_set_health", + "set_spawn_position":"packet_set_spawn_position", + "animate":"packet_animate", + "respawn":"packet_respawn", + "drop_item":"packet_drop_item", + "container_open":"packet_container_open", + "container_close":"packet_container_close", + "container_set_slot":"packet_container_set_slot", + "container_set_data":"packet_container_set_data", + "container_set_content":"packet_container_set_content", + "crafting_data":"packet_crafting_data", + "crafting_event":"packet_crafting_event", + "adventure_settings":"packet_adventure_settings", + "block_entity_data":"packet_block_entity_data", + "player_input":"packet_player_input", + "full_chunk_data":"packet_full_chunk_data", + "set_difficulty":"packet_set_difficulty", + "player_list":"packet_player_list", + "request_chunk_radius":"packet_request_chunk_radius", + "chunk_radius_update":"packet_chunk_radius_update", + "transfer":"packet_transfer", + "spawn_experience_orb":"packet_spawn_experience_orb", + "replace_selected_item":"packet_replace_selected_item" + } + } + ] + } + ] + ], + "packet_id_detect_lost_connections":[ + "container", + [ + + ] + ], + "packet_id_no_free_incoming_connections":[ + "container", + [ + + ] + ], + "packet_id_connection_banned":[ + "container", + [ + + ] + ], + "packet_id_ip_recently_connected":[ + "container", + [ + + ] + ], + "packet_server_to_client_handshake":[ + "container", + [ + { + "name":"publicKey", + "type":"string" + }, + { + "name":"serverToken", + "type":"string" + } + ] + ], + "packet_client_to_server_handshake":[ + "container", + [ + + ] + ], + "packet_game_login":[ + "container", + [ + { + "name":"protocol", + "type":"i32" + }, + { + "name":"body", + "type":[ + "buffer", + { + "countType":"i32" + } + ] + } + ] + ], + "packet_player_status":[ + "container", + [ + { + "name":"status", + "type":"i32" + } + ] + ], + "packet_disconnect":[ + "container", + [ + { + "name":"message", + "type":"string" + } + ] + ], + "packet_batch":[ + "container", + [ + { + "name":"payload", + "type":[ + "buffer", + { + "countType":"i32" + } + ] + } + ] + ], + "packet_text":[ + "container", + [ + { + "name":"type", + "type":"i8" + }, + { + "name":"name", + "type":[ + "switch", + { + "compareTo":"type", + "fields":{ + "1":"string", + "3":"string" + }, + "default":"void" + } + ] + }, + { + "name":"message", + "type":[ + "switch", + { + "compareTo":"type", + "fields":{ + "0":"string", + "1":"string", + "2":"string", + "3":"string", + "4":"string", + "5":"string" + } + } + ] + }, + { + "name":"parameters", + "type":[ + "switch", + { + "compareTo":"type", + "fields":{ + "2":[ + "array", + { + "countType":"i8", + "type":"string" + } + ] + }, + "default":"void" + } + ] + } + ] + ], + "packet_set_time":[ + "container", + [ + { + "name":"time", + "type":"i32" + }, + { + "name":"started", + "type":"i8" + } + ] + ], + "packet_start_game":[ + "container", + [ + { + "name":"seed", + "type":"i32" + }, + { + "name":"dimension", + "type":"i8" + }, + { + "name":"generator", + "type":"i32" + }, + { + "name":"gamemode", + "type":"i8" + }, + { + "name":"entityId", + "type":"i64" + }, + { + "name":"spawnX", + "type":"i32" + }, + { + "name":"spawnY", + "type":"i32" + }, + { + "name":"spawnZ", + "type":"i32" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"isLoadedInCreative", + "type":"bool" + }, + { + "name":"dayCycleStopTime", + "type":"i8" + }, + { + "name":"eduMode", + "type":"bool" + }, + { + "name":"worldName", + "type":"string" + } + ] + ], + "packet_add_player":[ + "container", + [ + { + "name":"uuid", + "type":"uuid" + }, + { + "name":"username", + "type":"string" + }, + { + "name":"entityId", + "type":"i64" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"speedX", + "type":"f32" + }, + { + "name":"speedY", + "type":"f32" + }, + { + "name":"speedZ", + "type":"f32" + }, + { + "name":"yaw", + "type":"f32" + }, + { + "name":"headYaw", + "type":"f32" + }, + { + "name":"pitch", + "type":"f32" + }, + { + "name":"item", + "type":"slot" + }, + { + "name":"metadata", + "type":"metadatadictionary" + } + ] + ], + "packet_remove_player":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"clientUuid", + "type":"uuid" + } + ] + ], + "packet_add_entity":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"entityType", + "type":"i32" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"speedX", + "type":"f32" + }, + { + "name":"speedY", + "type":"f32" + }, + { + "name":"speedZ", + "type":"f32" + }, + { + "name":"yaw", + "type":"f32" + }, + { + "name":"pitch", + "type":"f32" + }, + { + "name":"metadata", + "type":"metadatadictionary" + }, + { + "name":"links", + "type":"i16" + } + ] + ], + "packet_remove_entity":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + } + ] + ], + "packet_add_item_entity":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"item", + "type":"slot" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"speedX", + "type":"f32" + }, + { + "name":"speedY", + "type":"f32" + }, + { + "name":"speedZ", + "type":"f32" + } + ] + ], + "packet_take_item_entity":[ + "container", + [ + { + "name":"target", + "type":"i64" + }, + { + "name":"entityId", + "type":"i64" + } + ] + ], + "packet_move_entity":[ + "container", + [ + { + "name":"entities", + "type":"entitylocations" + } + ] + ], + "packet_move_player":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"yaw", + "type":"f32" + }, + { + "name":"headYaw", + "type":"f32" + }, + { + "name":"pitch", + "type":"f32" + }, + { + "name":"mode", + "type":"i8" + }, + { + "name":"onGround", + "type":"i8" + } + ] + ], + "packet_remove_block":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"x", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"y", + "type":"i8" + } + ] + ], + "packet_update_block":[ + "container", + [ + { + "name":"blocks", + "type":"blockrecords" + } + ] + ], + "packet_add_painting":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"direction", + "type":"i32" + }, + { + "name":"title", + "type":"string" + } + ] + ], + "packet_explode":[ + "container", + [ + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"radius", + "type":"f32" + }, + { + "name":"records", + "type":"records" + } + ] + ], + "packet_level_event":[ + "container", + [ + { + "name":"eventId", + "type":"i16" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, + { + "name":"data", + "type":"i32" + } + ] + ], + "packet_block_event":[ + "container", + [ + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"case1", + "type":"i32" + }, + { + "name":"case2", + "type":"i32" + } + ] + ], + "packet_entity_event":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"eventId", + "type":"i8" + } + ] + ], + "packet_mob_effect":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"eventId", + "type":"i8" + }, + { + "name":"effectId", + "type":"i8" + }, + { + "name":"amplifier", + "type":"i8" + }, + { + "name":"particles", + "type":"i8" + }, + { + "name":"duration", + "type":"i32" + } + ] + ], + "packet_update_attributes":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"attributes", + "type":"playerattributes" + } + ] + ], + "packet_mob_equipment":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"item", + "type":"slot" + }, + { + "name":"slot", + "type":"i8" + }, + { + "name":"selectedSlot", + "type":"i8" + } + ] + ], + "packet_mob_armor_equipment":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"helmet", + "type":"slot" + }, + { + "name":"chestplate", + "type":"slot" + }, + { + "name":"leggings", + "type":"slot" + }, + { + "name":"boots", + "type":"slot" + } + ] + ], + "packet_interact":[ + "container", + [ + { + "name":"actionId", + "type":"i8" + }, + { + "name":"targetEntityId", + "type":"i64" + } + ] + ], + "packet_use_item":[ + "container", + [ + { + "name":"blockcoordinates", + "type":"blockcoordinates" + }, + { + "name":"face", + "type":"i8" + }, + { + "name":"facecoordinates", + "type":"vector3" + }, + { + "name":"playerposition", + "type":"vector3" + }, + { + "name":"slot", + "type":"i32" + }, + { + "name":"item", + "type":"slot" + } + ] + ], + "packet_player_action":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"actionId", + "type":"i32" + }, + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"face", + "type":"i32" + } + ] + ], + "packet_hurt_armor":[ + "container", + [ + { + "name":"health", + "type":"i8" + } + ] + ], + "packet_set_entity_data":[ + "container", + [ + { + "name":"entity_id", + "type":"i64" + }, + { + "name":"metadata", + "type":"metadatadictionary" + } + ] + ], + "packet_set_entity_motion":[ + "container", + [ + { + "name":"entities", + "type":"entitymotions" + } + ] + ], + "packet_set_entity_link":[ + "container", + [ + { + "name":"riderId", + "type":"i64" + }, + { + "name":"riddenId", + "type":"i64" + }, + { + "name":"linkType", + "type":"i8" + } + ] + ], + "packet_set_health":[ + "container", + [ + { + "name":"health", + "type":"i32" + } + ] + ], + "packet_set_spawn_position":[ + "container", + [ + { + "name":"x", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + } + ] + ], + "packet_animate":[ + "container", + [ + { + "name":"actionId", + "type":"i8" + }, + { + "name":"entityId", + "type":"i64" + } + ] + ], + "packet_respawn":[ + "container", + [ + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + } + ] + ], + "packet_drop_item":[ + "container", + [ + { + "name":"itemtype", + "type":"i8" + }, + { + "name":"item", + "type":"slot" + } + ] + ], + "packet_container_open":[ + "container", + [ + { + "name":"windowId", + "type":"i8" + }, + { + "name":"type", + "type":"i8" + }, + { + "name":"slotCount", + "type":"i16" + }, + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + } + ] + ], + "packet_container_close":[ + "container", + [ + { + "name":"windowId", + "type":"i8" + } + ] + ], + "packet_container_set_slot":[ + "container", + [ + { + "name":"windowId", + "type":"i8" + }, + { + "name":"slot", + "type":"i16" + }, + { + "name":"unknown", + "type":"i16" + }, + { + "name":"item", + "type":"slot" + } + ] + ], + "packet_container_set_data":[ + "container", + [ + { + "name":"windowId", + "type":"i8" + }, + { + "name":"property", + "type":"i16" + }, + { + "name":"value", + "type":"i16" + } + ] + ], + "packet_container_set_content":[ + "container", + [ + { + "name":"windowId", + "type":"i8" + }, + { + "name":"slotData", + "type":"itemstacks" + }, + { + "name":"hotbarData", + "type":[ + "switch", + { + "compareTo":"windowId", + "fields":{ + "0":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"slot", + "type":"i32" + } + ] + ] + } + ] + }, + "default":"i16" + } + ] + } + ] + ], + "packet_crafting_data":[ + "container", + [ + { + "name":"recipes", + "type":[ + "container", + [ + { + "name":"entryType", + "type":"i32" + }, + { + "name":"recipe", + "type":[ + "array", + { + "countType":"i32", + "type":[ + "switch", + { + "compareTo":"entryType", + "fields":{ + "0":"shapelessRecipe", + "1":"shapedRecipe", + "2":"furnaceRecipe", + "3":"furnaceRecipeData", + "4":"enchantList" + }, + "default":"void" + } + ] + } + ] + } + ] + ] + }, + { + "name":"cleanRecipes", + "type":"i8" + } + ] + ], + "packet_crafting_event":[ + "container", + [ + { + "name":"windowId", + "type":"i8" + }, + { + "name":"recipeType", + "type":"i32" + }, + { + "name":"recipeId", + "type":"uuid" + }, + { + "name":"input", + "type":"itemstacks" + }, + { + "name":"result", + "type":"itemstacks" + } + ] + ], + "packet_adventure_settings":[ + "container", + [ + { + "name":"flags", + "type":"i32" + }, + { + "name":"userPermission", + "type":"i32" + }, + { + "name":"globalPermission", + "type":"i32" + } + ] + ], + "packet_block_entity_data":[ + "container", + [ + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"namedtag", + "type":"restBuffer" + } + ] + ], + "packet_player_input":[ + "container", + [ + { + "name":"motionX", + "type":"f32" + }, + { + "name":"motionZ", + "type":"f32" + }, + { + "name":"flags", + "type":"i16" + } + ] + ], + "packet_full_chunk_data":[ + "container", + [ + { + "name":"chunkX", + "type":"i32" + }, + { + "name":"chunkZ", + "type":"i32" + }, + { + "name":"order", + "type":"i8" + }, + { + "name":"chunkData", + "type":[ + "buffer", + { + "countType":"i32" + } + ] + } + ] + ], + "packet_set_difficulty":[ + "container", + [ + { + "name":"difficulty", + "type":"i32" + } + ] + ], + "packet_player_list":[ + "container", + [ + { + "name":"type", + "type":"i8" + }, + { + "name":"entries", + "type":[ + "array", + { + "countType":"i32", + "type":[ + "switch", + { + "compareTo":"type", + "fields":{ + "0":[ + "container", + [ + { + "name":"clientUuid", + "type":"uuid" + }, + { + "name":"entityId", + "type":"i64" + }, + { + "name":"displayName", + "type":"string" + }, + { + "name":"skin", + "type":"skin" + } + ] + ], + "1":[ + "container", + [ + { + "name":"clientUuid", + "type":"uuid" + } + ] + ] + } + } + ] + } + ] + } + ] + ], + "packet_request_chunk_radius":[ + "container", + [ + { + "name":"chunkRadius", + "type":"i32" + } + ] + ], + "packet_chunk_radius_update":[ + "container", + [ + { + "name":"chunkRadius", + "type":"i32" + } + ] + ], + "packet_transfer":[ + "container", + [ + { + "name":"endpoint", + "type":"ipAddress" + } + ] + ], + "packet_spawn_experience_orb":[ + "container", + [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + }, + { + "name":"count", + "type":"i32" + } + ] + ], + "packet_replace_selected_item":[ + "container", + [ + { + "name":"slot", + "type":"slot" + } + ] + ] + } } From d910a96ee37799d19959eaa41bd83240c44fcb52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 26 Oct 2016 15:05:42 +0200 Subject: [PATCH 036/458] Bump version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e4d8237..bb932c8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pocket-minecraft-protocol", - "version": "2.2.3", - "description": "Parse and serialize Minecraft PE packets", + "version": "2.3.0", + "description": "Parse and serialize Minecraft Pocket Edition packets", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" From 44b262294de984538f60207302a61999bfa0cd9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 26 Oct 2016 22:06:45 +0200 Subject: [PATCH 037/458] Add missing packets (doesn't work yet). --- data/protocol.json | 82 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 5139f1e..35c012b 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -586,6 +586,9 @@ "0x04":"client_to_server_handshake", "0x05":"disconnect", "0x06":"batch", + "0x07": "resource_pack_info", + "0x08": "resource_pack_stack", + "0x09": "resource_pack_client_response", "0x0a":"text", "0x0b":"set_time", "0x0c":"start_game", @@ -641,7 +644,10 @@ "0x44":"chunk_radius_update", "0x45":"item_frame_drop_item", "0x46":"replace_selected_item", - "0x49":"add_item_item" + "0x49":"add_item_item", + "0x4d": "resource_pack_data_info", + "0x4e": "resource_pack_chunk_data", + "0x4f": "resource_pack_chunk_request" } } ] @@ -659,6 +665,7 @@ "player_status":"packet_player_status", "disconnect":"packet_disconnect", "batch":"packet_batch", + "resource_pack_client_response": "packet_resource_pack_client_response", "text":"packet_text", "set_time":"packet_set_time", "start_game":"packet_start_game", @@ -810,6 +817,21 @@ } ] ], + + "packet_resource_pack_client_response": [ + "container", + [ + { + "name": "unknownByte", + "type": "i8" + }, + { + "name": "unknownShort", + "type": "i16" + } + ] + ], + "packet_text":[ "container", [ @@ -885,6 +907,26 @@ "packet_start_game":[ "container", [ + { + "name":"entityId", + "type":"i64" + }, + { + "name":"runtimeEntityId", + "type":"i64" + }, + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + }, + { + "name":"z", + "type":"f32" + }, { "name":"seed", "type":"i32" @@ -902,8 +944,8 @@ "type":"i8" }, { - "name":"entityId", - "type":"i64" + "name":"difficulty", + "type":"i8" }, { "name":"spawnX", @@ -918,19 +960,7 @@ "type":"i32" }, { - "name":"x", - "type":"f32" - }, - { - "name":"y", - "type":"f32" - }, - { - "name":"z", - "type":"f32" - }, - { - "name":"isLoadedInCreative", + "name":"achievementsDisabled", "type":"bool" }, { @@ -941,6 +971,26 @@ "name":"eduMode", "type":"bool" }, + { + "name":"rainLevel", + "type":"f32" + }, + { + "name":"lightningLevel", + "type":"f32" + }, + { + "name":"enableCommands", + "type":"bool" + }, + { + "name":"requireResourcePack", + "type":"bool" + }, + { + "name":"unknownString1", + "type":"string" + }, { "name":"worldName", "type":"string" From ed6870f8d5abbc505f3d5798f81495cefd7a9009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 26 Oct 2016 22:36:32 +0200 Subject: [PATCH 038/458] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb932c8..ded725a 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "lodash.merge": "^4.4.0", "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", - "raknet": "^1.8.0", + "raknet": "git+https://github.com/filfat/node-raknet.git", "uuid-1345": "^0.99.6" }, "devDependencies": { From a1b4c6b02ba6dfaa56e234c9b809ee22932f2d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 27 Oct 2016 10:38:48 +0200 Subject: [PATCH 039/458] Getting response now. --- data/protocol.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/protocol.json b/data/protocol.json index 35c012b..33322c2 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -774,6 +774,10 @@ "name":"protocol", "type":"i32" }, + { + "name": "edition", + "type": "i8" + }, { "name":"body", "type":[ From 89a63bb1371c934753afb981c8d14eca20186135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 27 Oct 2016 10:42:08 +0200 Subject: [PATCH 040/458] Apparently it's a byte array now. --- data/protocol.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/protocol.json b/data/protocol.json index 33322c2..1fb41b9 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -783,7 +783,7 @@ "type":[ "buffer", { - "countType":"i32" + "countType":"i8" } ] } From 7739d5c810cec77a1e3ed6dc0ffb356069795e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sat, 29 Oct 2016 17:05:08 +0200 Subject: [PATCH 041/458] Fix login packet. --- data/protocol.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/protocol.json b/data/protocol.json index 1fb41b9..ea3838d 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -783,7 +783,7 @@ "type":[ "buffer", { - "countType":"i8" + "countType":"varint" } ] } From 8e920e8399dbd4b1acbca5f3730132f222e2350e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sat, 29 Oct 2016 18:03:00 +0200 Subject: [PATCH 042/458] Update start game (doesn't work yet, need varlong) --- data/protocol.json | 56 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index ea3838d..16e9305 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -815,7 +815,7 @@ "type":[ "buffer", { - "countType":"i32" + "countType":"varint" } ] } @@ -900,7 +900,7 @@ [ { "name":"time", - "type":"i32" + "type":"varint" }, { "name":"started", @@ -913,43 +913,53 @@ [ { "name":"entityId", - "type":"i64" + "type":"i64", + "comment": "supposed to be varlong" }, { "name":"runtimeEntityId", - "type":"i64" + "type":"u64", + "comment": "supposed to be uvarlong" }, { "name":"x", - "type":"f32" + "type":"varint" }, { "name":"y", - "type":"f32" + "type":"varint" }, { "name":"z", - "type":"f32" + "type":"varint" + }, + { + "name":"unknownF1", + "type":"f64" + }, + { + "name":"unknownF2", + "type":"f64" }, { "name":"seed", - "type":"i32" + "type":"varint" }, { "name":"dimension", - "type":"i8" + "type":"varint" }, { "name":"generator", - "type":"i32" + "type":"varint" }, { "name":"gamemode", - "type":"i8" + "type":"varint" }, { "name":"difficulty", - "type":"i8" + "type":"varint" }, { "name":"spawnX", @@ -969,7 +979,7 @@ }, { "name":"dayCycleStopTime", - "type":"i8" + "type":"varint" }, { "name":"eduMode", @@ -977,11 +987,11 @@ }, { "name":"rainLevel", - "type":"f32" + "type":"f64" }, { "name":"lightningLevel", - "type":"f32" + "type":"f64" }, { "name":"enableCommands", @@ -992,7 +1002,7 @@ "type":"bool" }, { - "name":"unknownString1", + "name":"levelId", "type":"string" }, { @@ -1850,15 +1860,11 @@ [ { "name":"flags", - "type":"i32" + "type":"varint" }, { "name":"userPermission", - "type":"i32" - }, - { - "name":"globalPermission", - "type":"i32" + "type":"varint" } ] ], @@ -1905,11 +1911,11 @@ [ { "name":"chunkX", - "type":"i32" + "type":"varint" }, { "name":"chunkZ", - "type":"i32" + "type":"varint" }, { "name":"order", @@ -1920,7 +1926,7 @@ "type":[ "buffer", { - "countType":"i32" + "countType":"varint" } ] } From 27372031011c8d895b03ed6486db946d1883aa96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Mon, 5 Dec 2016 20:40:32 +0100 Subject: [PATCH 043/458] Update protodef --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ded725a..0c6f27e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "jwt-simple": "^0.5.0", "lodash.merge": "^4.4.0", "prismarine-nbt": "^1.0.0", - "protodef": "^1.2.0", + "protodef": "git+https://github.com/deathcap/ProtoDef.git#varlong", "raknet": "git+https://github.com/filfat/node-raknet.git", "uuid-1345": "^0.99.6" }, From 332d0a5e49ee1795b28e77338552d40bbd538eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Mon, 5 Dec 2016 20:57:48 +0100 Subject: [PATCH 044/458] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0c6f27e..f73a761 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "jwt-simple": "^0.5.0", "lodash.merge": "^4.4.0", "prismarine-nbt": "^1.0.0", - "protodef": "git+https://github.com/deathcap/ProtoDef.git#varlong", + "protodef": "^1.2.3", "raknet": "git+https://github.com/filfat/node-raknet.git", "uuid-1345": "^0.99.6" }, From 6332fe50729d1b43b49eccc3c055be85ab169777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 11 Dec 2016 00:33:24 +0100 Subject: [PATCH 045/458] Add minor fixes. --- data/protocol.json | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 16e9305..2d83570 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -355,19 +355,19 @@ [ { "name":"x", - "type":"i32" + "type":"varint" }, { "name":"z", - "type":"i32" + "type":"varint" }, { "name":"y", - "type":"i8" + "type":"varint" }, { "name":"blockId", - "type":"i8" + "type":"varint" }, { "anon":true, @@ -376,12 +376,12 @@ [ { "name":"blockData", - "size":4, + "size":8, "signed":false }, { "name":"flags", - "size":4, + "size":8, "signed":false } ] @@ -913,12 +913,12 @@ [ { "name":"entityId", - "type":"i64", + "type":"varint", "comment": "supposed to be varlong" }, { "name":"runtimeEntityId", - "type":"u64", + "type":"varint", "comment": "supposed to be uvarlong" }, { @@ -1917,10 +1917,6 @@ "name":"chunkZ", "type":"varint" }, - { - "name":"order", - "type":"i8" - }, { "name":"chunkData", "type":[ @@ -1937,7 +1933,7 @@ [ { "name":"difficulty", - "type":"i32" + "type":"varint" } ] ], @@ -2002,7 +1998,7 @@ [ { "name":"chunkRadius", - "type":"i32" + "type":"varint" } ] ], @@ -2011,7 +2007,7 @@ [ { "name":"chunkRadius", - "type":"i32" + "type":"varint" } ] ], From 559942de75c312c16926f83aba97de75ba73377d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 11 Dec 2016 19:13:32 +0100 Subject: [PATCH 046/458] Update protocol.json --- data/protocol.json | 79 +++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 2d83570..658d41d 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -640,6 +640,7 @@ "0x3e":"player_list", "0x3f":"telemetry_event", "0x40":"spawn_experience_orb", + "0x42":"map_info_request", "0x43":"request_chunk_radius", "0x44":"chunk_radius_update", "0x45":"item_frame_drop_item", @@ -665,6 +666,7 @@ "player_status":"packet_player_status", "disconnect":"packet_disconnect", "batch":"packet_batch", + "resource_pack_info": "packet_resource_pack_info", "resource_pack_client_response": "packet_resource_pack_client_response", "text":"packet_text", "set_time":"packet_set_time", @@ -713,11 +715,13 @@ "full_chunk_data":"packet_full_chunk_data", "set_difficulty":"packet_set_difficulty", "player_list":"packet_player_list", + "map_info_request": "packet_map_info_request", "request_chunk_radius":"packet_request_chunk_radius", "chunk_radius_update":"packet_chunk_radius_update", "transfer":"packet_transfer", "spawn_experience_orb":"packet_spawn_experience_orb", - "replace_selected_item":"packet_replace_selected_item" + "replace_selected_item":"packet_replace_selected_item", + "resource_pack_data_info": "packet_resource_pack_data_info" } } ] @@ -821,17 +825,37 @@ } ] ], - + "packet_resource_pack_info": [ + "container", + [ + { + "name":"mustAccept", + "type":"bool" + }, + { + "name":"behaviourPackLength", + "type":"u16" + }, + { + "name":"resourcePackLength", + "type":"u16" + } + ] + ], "packet_resource_pack_client_response": [ "container", [ { - "name": "unknownByte", + "name": "status", "type": "i8" }, { - "name": "unknownShort", - "type": "i16" + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "u32" } ] ], @@ -904,7 +928,7 @@ }, { "name":"started", - "type":"i8" + "type":"bool" } ] ], @@ -913,25 +937,23 @@ [ { "name":"entityId", - "type":"varint", - "comment": "supposed to be varlong" + "type":"varint" }, { "name":"runtimeEntityId", - "type":"varint", - "comment": "supposed to be uvarlong" + "type":"varint" }, { "name":"x", - "type":"varint" + "type":"f32" }, { "name":"y", - "type":"varint" + "type":"f32" }, { "name":"z", - "type":"varint" + "type":"f32" }, { "name":"unknownF1", @@ -963,15 +985,15 @@ }, { "name":"spawnX", - "type":"i32" + "type":"f32" }, { "name":"spawnY", - "type":"i32" + "type":"f32" }, { "name":"spawnZ", - "type":"i32" + "type":"f32" }, { "name":"achievementsDisabled", @@ -1211,7 +1233,7 @@ [ { "name":"entityId", - "type":"i64" + "type":"varint" }, { "name":"x", @@ -1226,7 +1248,7 @@ "type":"f32" }, { - "name":"yaw", + "name":"pitch", "type":"f32" }, { @@ -1234,7 +1256,7 @@ "type":"f32" }, { - "name":"pitch", + "name":"yaw", "type":"f32" }, { @@ -1243,7 +1265,7 @@ }, { "name":"onGround", - "type":"i8" + "type":"bool" } ] ], @@ -1502,9 +1524,13 @@ "name":"blockcoordinates", "type":"blockcoordinates" }, + { + "name":"unknown", + "type":"varint" + }, { "name":"face", - "type":"i8" + "type":"varint" }, { "name":"facecoordinates", @@ -1516,7 +1542,7 @@ }, { "name":"slot", - "type":"i32" + "type":"varint" }, { "name":"item", @@ -1993,6 +2019,15 @@ } ] ], + "map_info_request": [ + "container", + [ + { + "name":"mapID", + "type":"varint" + } + ] + ], "packet_request_chunk_radius":[ "container", [ From 0af8627d232382ae7245c2f27579a644d851f447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 11 Dec 2016 21:43:29 +0100 Subject: [PATCH 047/458] Update protocol.json --- data/protocol.json | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 658d41d..1bb2b80 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -867,6 +867,7 @@ "name":"type", "type":"i8" }, + { "name":"name", "type":[ @@ -1555,27 +1556,19 @@ [ { "name":"entityId", - "type":"i64" + "type":"varint" }, { "name":"actionId", - "type":"i32" + "type":"varint" }, { - "name":"x", - "type":"i32" - }, - { - "name":"y", - "type":"i32" - }, - { - "name":"z", - "type":"i32" + "name":"blockcoordinates", + "type":"blockcoordinates" }, { "name":"face", - "type":"i32" + "type":"varint" } ] ], @@ -1943,6 +1936,10 @@ "name":"chunkZ", "type":"varint" }, + { + "name":"order", + "type":"i8" + }, { "name":"chunkData", "type":[ From 0094941fd57fbf323b04e3cf2b4f2cd72690f5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Mon, 12 Dec 2016 08:44:19 +0100 Subject: [PATCH 048/458] Cleanup create server. --- src/createServer.js | 257 ++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 152 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 1dec6a0..da78b6f 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,173 +1,126 @@ 'use strict'; -const raknet = require('raknet'); -const zlib = require('zlib'); -const ProtoDef = require('protodef').ProtoDef; -const Parser = require('protodef').Parser; -const Serializer = require('protodef').Serializer; -const jwt = require('jwt-simple'); -const crypto = require('crypto'); -const Ber = require('asn1').Ber; -const merge=require("lodash.merge"); -const assert=require("assert"); -var debug = require('debug')("raknet"); -// const BN = require('bn.js'); +let raknet = require('raknet'), + zlib = require('zlib'), + ProtoDef = require('protodef').ProtoDef, + Parser = require('protodef').Parser, + Serializer = require('protodef').Serializer, + jwt = require('jwt-simple'), + crypto = require('crypto'), + Ber = require('asn1').Ber, + merge = require('lodash.merge'), + assert = require('assert'); +var debug = require('debug')('raknet'); const batchProto = new ProtoDef(); -batchProto.addTypes(require("./datatypes/minecraft")); -batchProto.addType("insideBatch", ["endOfArray", { - "type": ["buffer", { - "countType": "i32" - }] +batchProto.addTypes(require('./datatypes/minecraft')); +batchProto.addType('insideBatch', ['endOfArray', { + 'type': ['buffer', { + 'countType': 'varint' + }] }]); -const dataProto = new ProtoDef(); -dataProto.addType("data_chain", ["container", [{ - "name": "chain", - "type": ["pstring", { - "countType": "li32" - }] -}, { - "name": "clientData", - "type": ["pstring", { - "countType": "li32" - }] -}]]); - - -function writeLI64(value, buffer, offset) { - buffer.writeInt32LE(value[0], offset+4); - buffer.writeInt32LE(value[1], offset); - return offset + 8; -} - -function computeCheckSum(packetPlaintext,sendCounter,secretKeyBytes) { - let digest = crypto.createHash('sha256'); - let counter=new Buffer(8); - writeLI64(sendCounter,counter,0); - digest.update(counter); - digest.update(packetPlaintext); - digest.update(secretKeyBytes); - let hash = digest.digest(); - - return hash.slice(0,8); -} - - -function readX509PublicKey(key) { - var reader = new Ber.Reader(new Buffer(key, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); - reader.readOID(); - return new Buffer(reader.readString(Ber.BitString, true)).slice(1); -} - -function writeX509PublicKey(key) { - var writer = new Ber.Writer(); - writer.startSequence(); - writer.startSequence(); - writer.writeOID("1.2.840.10045.2.1"); - writer.writeOID("1.3.132.0.34"); - writer.endSequence(); - writer.writeBuffer(Buffer.concat([new Buffer([0x00]),key]),Ber.BitString); - writer.endSequence(); - return writer.buffer.toString("base64"); -} - -const Transform = require('stream').Transform; - - const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; - function createServer(options) { - options = options || {}; - var port = options.port != null ? - options.port : - options['server-port'] != null ? - options['server-port'] : - 19132; - var host = options.host || '0.0.0.0'; + options = options || {}; + var port = options.port != null ? + options.port : + options['server-port'] != null ? + options['server-port'] : + 19132; + var host = options.host || '0.0.0.0'; - options.customPackets = require("../data/protocol"); - options.customTypes = require("./datatypes/minecraft"); - var server = raknet.createServer(options); + options.customPackets = require('../data/protocol'); + options.customTypes = require('./datatypes/minecraft'); + var server = raknet.createServer(options); - server.name = options.name || "Minecraft Server"; - server.motd = options.motd || "A Minecraft server"; - server.maxPlayers = options['max-players'] || 20; - server.playerCount = 0; + server.name = options.name || 'Minecraft Server'; + server.motd = options.motd || 'A Minecraft server'; + server.maxPlayers = options['max-players'] || 20; + server.playerCount = 0; - server.on("connection", function(client) { + server.on('connection', function(client) { - client.receiveCounter=0; - client.sendCounter=0; + client.receiveCounter=0; + client.sendCounter=0; - client.encryptionEnabled = false; + client.encryptionEnabled = false; - let proto = new ProtoDef(); - proto.addTypes(require("./datatypes/minecraft")); - proto.addTypes(require("../data/protocol").types); - client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); + let proto = new ProtoDef(); + proto.addTypes(require('./datatypes/minecraft')); + proto.addTypes(require('../data/protocol').types); + client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); - client.on("mcpe", packet => { - client.emit(packet.name, packet.params) - }); - - client.writeMCPE = (name, params) => { - if(client.encryptionEnabled) { - debug("write mcpe", name, params); - client.mcpePacketSerializer.write({ name, params }); - } - else { - client.writeEncapsulated("mcpe", { name, params }); - } - }; - - client.writeBatch = function(packets) { - const payload = zlib.deflateSync(batchProto.createPacketBuffer("insideBatch", - packets.map(packet => - client.mcpePacketSerializer.createPacketBuffer(packet)))); - - client.writeMCPE("batch", { - payload: payload + client.on('mcpe', packet => { + client.emit(packet.name, packet.params) }); - }; + + client.writeMCPE = (name, params) => { + if (client.encryptionEnabled) { + client.mcpePacketSerializer.write({ name, params }); + } + else { + client.writeEncapsulated('mcpe', { name, params }); + } + }; - client.on('batch', function(packet) { - var buf = zlib.inflateSync(packet.payload); - var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); + client.writeBatch = function(packets) { + const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', + packets.map(packet => + client.mcpePacketSerializer.createPacketBuffer(packet)))); + + client.writeMCPE('batch', { + payload: payload + }); + }; + + client.on('batch', function(packet) { + var buf = zlib.inflateSync(packet.payload); + var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; + packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); + }); + + client.on('game_login', (packet) => { + try { + const dataProto = new ProtoDef(); + dataProto.addType('data_chain', ['container', [{ + 'name': 'chain', + 'type': ['pstring', { + 'countType': 'li32' + }] + }, { + 'name': 'clientData', + 'type': ['pstring', { + 'countType': 'li32' + }] + }]]); + + let body = dataProto.parsePacketBuffer('data_chain', zlib.inflateSync(packet.body)), + chain = null, + decode = null, + data = null; + + body.data.chain = JSON.parse(body.data.chain); + chain = body.data.chain.chain[0]; + + decode = jwt.decode(chain, 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V', 'ES384'); + data = jwt.decode(body.data.clientData, decode.identityPublicKey, 'ES384'); + + data.SkinData = null; + client.emit('mcpe_login', { + protocol: packet.protocol, + uuid: (decode.extraData != null) ? decode.extraData.identity : null, + id: (decode.extraData != null) ? decode.extraData.identityPublicKey : null, + username: (decode.extraData != null) ? decode.extraData.displayName : null, + skinData: data.SkinData, + skinId: data.SkinId + }) + } catch(err) { + console.log(err); + } + }); }); - - client.on('client_to_server_handshake',() => { - client.emit('login_mcpe', { - displayName: client.displayName, - randomId: client.randomId, - skinData: client.skinData, - skinId: client.skinId, - identity: client.identity, - XUID: client.XUID - }); - }); - - - client.on('batch_non_encrypted', function(packet) { - var buf = zlib.inflateSync(packet.payload); - var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; - packets.forEach(packet => { - try { - debug("handle mcpe",packet); - var r = client.mcpePacketParser.parsePacketBuffer(packet); - client.emitPacket(r); - } - catch(err) { - client.emit("error",err); - } - }); - }); - }); - return server; + return server; } module.exports = createServer; From 710f4372e65c54a1917fde56c4ba0901414f820f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 14 Dec 2016 18:19:16 +0100 Subject: [PATCH 049/458] Updated to automatically generated protocol. --- data/protocol.json | 2688 +++++++++++++++++++------------------------- 1 file changed, 1175 insertions(+), 1513 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 1bb2b80..ba86305 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -1,651 +1,197 @@ { - "types":{ - "string":[ + "types": { + "string": [ "pstring", { - "countType":"i16" + "countType": "i16" } ], - "lstring":[ + "lstring": [ "pstring", { - "countType":"li16" + "countType": "li16" } ], - "shapeless_recipe":[ + "vector3": [ "container", [ { - "name":"ingredientList", - "type":[ - "array", - { - "countType":"i32", - "type":"slot" - } - ] + "name": "x", + "type": "f32" }, { - "name":"resultCount", - "type":"i32" + "name": "y", + "type": "f32" }, { - "name":"slot", - "type":"slot" - }, - { - "name":"id", - "type":"uuid" + "name": "z", + "type": "f32" } ] ], - "shaped_recipe":[ + "vector2": [ "container", [ { - "name":"width", - "type":[ - "count", - { - "type":"i32", - "countFor":"shape" - } - ] + "name": "x", + "type": "f32" }, { - "name":"height", - "type":[ - "count", - { - "type":"i32", - "countFor":"shape/0" - } - ] - }, - { - "name":"shape", - "type":[ - "array", - { - "count":"width", - "type":[ - "array", - { - "count":"height", - "type":"slot" - } - ] - } - ] - }, - { - "name":"resultCount", - "type":"i32" - }, - { - "name":"slot", - "type":"slot" - }, - { - "name":"id", - "type":"uuid" + "name": "y", + "type": "f32" } ] ], - "furnace_recipe":[ - "container", - [ - { - "name":"meta", - "type":"i16" - }, - { - "name":"id", - "type":"i16" - }, - { - "name":"result", - "type":"slot" - } - ] - ], - "furnace_recipe_data":[ - "container", - [ - { - "name":"id", - "type":"i16" - }, - { - "name":"meta", - "type":"i16" - }, - { - "name":"result", - "type":"slot" - } - ] - ], - "enchant_list":[ + "playerlocation": [ "array", { - "countType":"i8", - "type":[ + "countType": "i16", + "type": [ "container", [ { - "name":"cost", - "type":"i32" + "name": "x", + "type": "f32" }, { - "name":"enchantments", - "type":[ - "array", - { - "countType":"i8", - "type":[ - "container", - [ - { - "name":"id", - "type":"i32" - }, - { - "name":"level", - "type":"i32" - } - ] - ] - } - ] + "name": "y", + "type": "f32" }, { - "name":"name", - "type":"string" + "name": "z", + "type": "f32" + }, + { + "name": "yaw", + "type": "f32" + }, + { + "name": "pitch", + "type": "f32" + }, + { + "name": "headYaw", + "type": "f32" } ] ] } ], - "entityMetadataItem":[ - "switch", - { - "compareTo":"$compareTo", - "fields":{ - "0":"li8", - "1":"li16", - "2":"li32", - "3":"lf32", - "4":"lstring", - "5":[ - "container", - [ - { - "name":"blockId", - "type":"li16" - }, - { - "name":"itemCount", - "type":"li8" - }, - { - "name":"itemDamage", - "type":"li16" - } - ] - ], - "6":[ - "container", - [ - { - "name":"x", - "type":"li32" - }, - { - "name":"y", - "type":"li32" - }, - { - "name":"z", - "type":"li32" - } - ] - ], - "7":[ - "container", - [ - { - "name":"pitch", - "type":"lf32" - }, - { - "name":"yaw", - "type":"lf32" - }, - { - "name":"roll", - "type":"lf32" - } - ] - ], - "8":"li64" - } - } - ], - "metadatadictionary":[ - "entityMetadataLoop", - { - "endVal":127, - "type":[ - "container", - [ - { - "anon":true, - "type":[ - "bitfield", - [ - { - "name":"type", - "size":3, - "signed":false - }, - { - "name":"key", - "size":5, - "signed":false - } - ] - ] - }, - { - "name":"value", - "type":[ - "entityMetadataItem", - { - "compareTo":"type" - } - ] - } - ] - ] - } - ], - "slot":[ + "encapsulated_packet": [ "container", [ { - "name":"blockId", - "type":"i16" - }, - { - "anon":true, - "type":[ - "switch", - { - "compareTo":"blockId", - "fields":{ - "0":"void" - }, - "default":[ - "container", - [ - { - "name":"itemCount", - "type":"i8" - }, - { - "name":"itemDamage", - "type":"i16" - }, - { - "name":"nbtData", - "type":[ - "buffer", - { - "countType":"li16" - } - ] - } - ] - ] - } - ] - } - ] - ], - "itemstacks":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"slot", - "type":"itemstacks" - } - ] - ] - } - ], - "skin":[ - "container", - [ - { - "name":"skin_type", - "type":"string" - }, - { - "name":"texture", - "type":[ - "buffer", - { - "countType":"i16" - } - ] - } - ] - ], - "blockrecords":[ - "array", - { - "countType":"i32", - "type":[ - "container", - [ - { - "name":"x", - "type":"varint" - }, - { - "name":"z", - "type":"varint" - }, - { - "name":"y", - "type":"varint" - }, - { - "name":"blockId", - "type":"varint" - }, - { - "anon":true, - "type":[ - "bitfield", - [ - { - "name":"blockData", - "size":8, - "signed":false - }, - { - "name":"flags", - "size":8, - "signed":false - } - ] - ] - } - ] - ] - } - ], - "records":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"x", - "type":"i8" - }, - { - "name":"y", - "type":"i8" - }, - { - "name":"z", - "type":"i8" - } - ] - ] - } - ], - "playerattributes":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"minValue", - "type":"f32" - }, - { - "name":"maxValue", - "type":"f32" - }, - { - "name":"id", - "type":"f32" - }, - { - "name":"name", - "type":"string" - } - ] - ] - } - ], - "entitymotions":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"eid", - "type":"i64" - }, - { - "name":"motX", - "type":"f32" - }, - { - "name":"motY", - "type":"f32" - }, - { - "name":"motZ", - "type":"f32" - } - ] - ] - } - ], - "vector3":[ - "container", - [ - { - "name":"x", - "type":"f32" - }, - { - "name":"y", - "type":"f32" - }, - { - "name":"z", - "type":"f32" - } - ] - ], - "blockcoordinates":[ - "container", - [ - { - "name":"x", - "type":"i32" - }, - { - "name":"y", - "type":"i32" - }, - { - "name":"z", - "type":"i32" - } - ] - ], - "entitylocations":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"eid", - "type":"i64" - }, - { - "name":"x", - "type":"f32" - }, - { - "name":"y", - "type":"f32" - }, - { - "name":"z", - "type":"f32" - }, - { - "name":"yaw", - "type":"f32" - }, - { - "name":"headYaw", - "type":"f32" - }, - { - "name":"pitch", - "type":"f32" - } - ] - ] - } - ], - "encapsulated_packet":[ - "container", - [ - { - "name":"name", - "type":[ + "name": "name", + "type": [ "mapper", { - "type":"u8", - "mappings":{ - "0xfe":"mcpe" + "type": "u8", + "mappings": { + "0xfe": "mcpe" } } ] }, { - "name":"params", - "type":[ + "name": "params", + "type": [ "switch", { - "compareTo":"name", - "fields":{ - "mcpe":"mcpe_packet" + "compareTo": "name", + "fields": { + "mcpe": "mcpe_packet" } } ] } ] ], - "mcpe_packet":[ + "mcpe_packet": [ "container", [ { - "name":"name", - "type":[ + "name": "name", + "type": [ "mapper", { - "type":"u8", - "mappings":{ - "0x01":"game_login", - "0x02":"player_status", - "0x03":"server_to_client_handshake", - "0x04":"client_to_server_handshake", - "0x05":"disconnect", - "0x06":"batch", - "0x07": "resource_pack_info", + "type": "u8", + "mappings": { + "0x01": "game_login", + "0x02": "player_status", + "0x03": "server_to_client_handshake", + "0x04": "client_to_server_handshake", + "0x05": "disconnect", + "0x06": "batch", + "0x07": "resource_packs_info", "0x08": "resource_pack_stack", "0x09": "resource_pack_client_response", - "0x0a":"text", - "0x0b":"set_time", - "0x0c":"start_game", - "0x0d":"add_player", - "0x0e":"add_entity", - "0x0f":"remove_entity", - "0x10":"add_item_entity", - "0x12":"take_item_entity", - "0x13":"move_entity", - "0x14":"move_player", - "0x15":"rider_jump", - "0x16":"remove_block", - "0x17":"update_block", - "0x18":"add_painting", - "0x19":"explode", - "0x1a":"level_event", - "0x1c":"block_event", - "0x1d":"entity_event", - "0x1e":"mob_effect", - "0x1f":"update_attributes", - "0x20":"mob_equipment", - "0x21":"mob_armor_equipment", - "0x22":"interact", - "0x23":"use_item", - "0x24":"player_action", - "0x25":"hurt_armor", - "0x26":"set_entity_data", - "0x27":"set_entity_motion", - "0x28":"set_entity_link", - "0x29":"set_health", - "0x2a":"set_spawn_position", - "0x2b":"animate", - "0x2c":"respawn", - "0x2d":"drop_item", - "0x2f":"container_open", - "0x30":"container_close", - "0x31":"container_set_slot", - "0x32":"container_set_data", - "0x33":"container_set_content", - "0x34":"crafting_data", - "0x35":"crafting_event", - "0x36":"adventure_settings", - "0x37":"block_entity_data", - "0x38":"player_input", - "0x39":"full_chunk_data", - "0x3b":"set_difficulty", - "0x3c":"change_dimension", - "0x3d":"set_player_gametype", - "0x3e":"player_list", - "0x3f":"telemetry_event", - "0x40":"spawn_experience_orb", - "0x42":"map_info_request", - "0x43":"request_chunk_radius", - "0x44":"chunk_radius_update", - "0x45":"item_frame_drop_item", - "0x46":"replace_selected_item", - "0x49":"add_item_item", + "0x0a": "text", + "0x0b": "set_time", + "0x0c": "start_game", + "0x0d": "add_player", + "0x0e": "add_entity", + "0x0f": "remove_entity", + "0x10": "add_item_entity", + "0x11": "add_hanging_entity", + "0x12": "take_item_entity", + "0x13": "move_entity", + "0x14": "move_player", + "0x15": "rider_jump", + "0x16": "remove_block", + "0x17": "update_block", + "0x18": "add_painting", + "0x19": "explode", + "0x1a": "level_sound_event", + "0x1b": "level_event", + "0x1c": "block_event", + "0x1d": "entity_event", + "0x1e": "mob_effect", + "0x1f": "update_attributes", + "0x20": "mob_equipment", + "0x21": "mob_armor_equipment", + "0x22": "interact", + "0x23": "use_item", + "0x24": "player_action", + "0x25": "hurt_armor", + "0x26": "set_entity_data", + "0x27": "set_entity_motion", + "0x28": "set_entity_link", + "0x29": "set_health", + "0x2a": "set_spawn_position", + "0x2b": "animate", + "0x2c": "respawn", + "0x2d": "drop_item", + "0x2e": "inventory_action", + "0x2f": "container_open", + "0x30": "container_close", + "0x31": "container_set_slot", + "0x32": "container_set_data", + "0x33": "container_set_content", + "0x34": "crafting_data", + "0x35": "crafting_event", + "0x36": "adventure_settings", + "0x37": "block_entity_data", + "0x38": "player_input", + "0x39": "full_chunk_data", + "0x3a": "set_commands_enabled", + "0x3b": "set_difficulty", + "0x3c": "change_dimension", + "0x3d": "set_player_game_type", + "0x3e": "player_list", + "0x3f": "event", + "0x40": "spawn_experience_orb", + "0x41": "clientbound_map_item_data_", + "0x42": "map_info_request", + "0x43": "request_chunk_radius", + "0x44": "chunk_radius_update", + "0x45": "item_fram_drop_item", + "0x46": "replace_selected_item", + "0x47": "game_rules_changed", + "0x48": "camera", + "0x49": "add_item", + "0x4a": "boss_event", + "0x4b": "available_commands", + "0x4c": "command_step", "0x4d": "resource_pack_data_info", "0x4e": "resource_pack_chunk_data", "0x4f": "resource_pack_chunk_request" @@ -654,191 +200,214 @@ ] }, { - "name":"params", - "type":[ + "name": "params", + "type": [ "switch", { - "compareTo":"name", - "fields":{ - "server_to_client_handshake":"packet_server_to_client_handshake", - "client_to_server_handshake":"packet_client_to_server_handshake", - "game_login":"packet_game_login", - "player_status":"packet_player_status", - "disconnect":"packet_disconnect", - "batch":"packet_batch", - "resource_pack_info": "packet_resource_pack_info", + "compareTo": "name", + "fields": { + "game_login": "packet_game_login", + "player_status": "packet_player_status", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", + "disconnect": "packet_disconnect", + "batch": "packet_batch", + "resource_packs_info": "packet_resource_packs_info", + "resource_pack_stack": "packet_resource_pack_stack", "resource_pack_client_response": "packet_resource_pack_client_response", - "text":"packet_text", - "set_time":"packet_set_time", - "start_game":"packet_start_game", - "add_player":"packet_add_player", - "remove_player":"packet_remove_player", - "add_entity":"packet_add_entity", - "remove_entity":"packet_remove_entity", - "add_item_entity":"packet_add_item_entity", - "take_item_entity":"packet_take_item_entity", - "move_entity":"packet_move_entity", - "move_player":"packet_move_player", - "remove_block":"packet_remove_block", - "update_block":"packet_update_block", - "add_painting":"packet_add_painting", - "explode":"packet_explode", - "level_event":"packet_level_event", - "block_event":"packet_block_event", - "entity_event":"packet_entity_event", - "mob_effect":"packet_mob_effect", - "update_attributes":"packet_update_attributes", - "mob_equipment":"packet_mob_equipment", - "mob_armor_equipment":"packet_mob_armor_equipment", - "interact":"packet_interact", - "use_item":"packet_use_item", - "player_action":"packet_player_action", - "hurt_armor":"packet_hurt_armor", - "set_entity_data":"packet_set_entity_data", - "set_entity_motion":"packet_set_entity_motion", - "set_entity_link":"packet_set_entity_link", - "set_health":"packet_set_health", - "set_spawn_position":"packet_set_spawn_position", - "animate":"packet_animate", - "respawn":"packet_respawn", - "drop_item":"packet_drop_item", - "container_open":"packet_container_open", - "container_close":"packet_container_close", - "container_set_slot":"packet_container_set_slot", - "container_set_data":"packet_container_set_data", - "container_set_content":"packet_container_set_content", - "crafting_data":"packet_crafting_data", - "crafting_event":"packet_crafting_event", - "adventure_settings":"packet_adventure_settings", - "block_entity_data":"packet_block_entity_data", - "player_input":"packet_player_input", - "full_chunk_data":"packet_full_chunk_data", - "set_difficulty":"packet_set_difficulty", - "player_list":"packet_player_list", + "text": "packet_text", + "set_time": "packet_set_time", + "start_game": "packet_start_game", + "add_player": "packet_add_player", + "add_entity": "packet_add_entity", + "remove_entity": "packet_remove_entity", + "add_item_entity": "packet_add_item_entity", + "add_hanging_entity": "packet_add_hanging_entity", + "take_item_entity": "packet_take_item_entity", + "move_entity": "packet_move_entity", + "move_player": "packet_move_player", + "rider_jump": "packet_rider_jump", + "remove_block": "packet_remove_block", + "update_block": "packet_update_block", + "add_painting": "packet_add_painting", + "explode": "packet_explode", + "level_sound_event": "packet_level_sound_event", + "level_event": "packet_level_event", + "block_event": "packet_block_event", + "entity_event": "packet_entity_event", + "mob_effect": "packet_mob_effect", + "update_attributes": "packet_update_attributes", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", + "interact": "packet_interact", + "use_item": "packet_use_item", + "player_action": "packet_player_action", + "hurt_armor": "packet_hurt_armor", + "set_entity_data": "packet_set_entity_data", + "set_entity_motion": "packet_set_entity_motion", + "set_entity_link": "packet_set_entity_link", + "set_health": "packet_set_health", + "set_spawn_position": "packet_set_spawn_position", + "animate": "packet_animate", + "respawn": "packet_respawn", + "drop_item": "packet_drop_item", + "inventory_action": "packet_inventory_action", + "container_open": "packet_container_open", + "container_close": "packet_container_close", + "container_set_slot": "packet_container_set_slot", + "container_set_data": "packet_container_set_data", + "container_set_content": "packet_container_set_content", + "crafting_data": "packet_crafting_data", + "crafting_event": "packet_crafting_event", + "adventure_settings": "packet_adventure_settings", + "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", + "full_chunk_data": "packet_full_chunk_data", + "set_commands_enabled": "packet_set_commands_enabled", + "set_difficulty": "packet_set_difficulty", + "change_dimension": "packet_change_dimension", + "set_player_game_type": "packet_set_player_game_type", + "player_list": "packet_player_list", + "event": "packet_event", + "spawn_experience_orb": "packet_spawn_experience_orb", + "clientbound_map_item_data_": "packet_clientbound_map_item_data_", "map_info_request": "packet_map_info_request", - "request_chunk_radius":"packet_request_chunk_radius", - "chunk_radius_update":"packet_chunk_radius_update", - "transfer":"packet_transfer", - "spawn_experience_orb":"packet_spawn_experience_orb", - "replace_selected_item":"packet_replace_selected_item", - "resource_pack_data_info": "packet_resource_pack_data_info" + "request_chunk_radius": "packet_request_chunk_radius", + "chunk_radius_update": "packet_chunk_radius_update", + "item_fram_drop_item": "packet_item_fram_drop_item", + "replace_selected_item": "packet_replace_selected_item", + "game_rules_changed": "packet_game_rules_changed", + "camera": "packet_camera", + "add_item": "packet_add_item", + "boss_event": "packet_boss_event", + "available_commands": "packet_available_commands", + "command_step": "packet_command_step", + "resource_pack_data_info": "packet_resource_pack_data_info", + "resource_pack_chunk_data": "packet_resource_pack_chunk_data", + "resource_pack_chunk_request": "packet_resource_pack_chunk_request" } } ] } ] ], - "packet_id_detect_lost_connections":[ - "container", - [ - - ] - ], - "packet_id_no_free_incoming_connections":[ - "container", - [ - - ] - ], - "packet_id_connection_banned":[ - "container", - [ - - ] - ], - "packet_id_ip_recently_connected":[ - "container", - [ - - ] - ], - "packet_server_to_client_handshake":[ + "packet_game_login": [ "container", [ { - "name":"publicKey", - "type":"string" - }, - { - "name":"serverToken", - "type":"string" - } - ] - ], - "packet_client_to_server_handshake":[ - "container", - [ - - ] - ], - "packet_game_login":[ - "container", - [ - { - "name":"protocol", - "type":"i32" + "name": "protocol", + "type": "i32" }, { "name": "edition", "type": "i8" }, { - "name":"body", - "type":[ + "name": "body", + "type": [ "buffer", { - "countType":"varint" + "countType": "varint" } ] } ] ], - "packet_player_status":[ + "packet_player_status": [ "container", [ { - "name":"status", - "type":"i32" + "name": "status", + "type": "i32" } ] ], - "packet_disconnect":[ + "packet_server_to_client_handshake": [ "container", [ { - "name":"message", - "type":"string" - } - ] - ], - "packet_batch":[ - "container", - [ + "name": "server_public_key", + "type": "string" + }, { - "name":"payload", - "type":[ + "name": "token_length", + "type": "length" + }, + { + "name": "token", + "type": [ "buffer", { - "countType":"varint" + "countType": "varint", + "type": "i8" } ] } ] ], - "packet_resource_pack_info": [ + "packet_client_to_server_handshake": [ + "container", + [] + ], + "packet_disconnect": [ "container", [ { - "name":"mustAccept", - "type":"bool" + "name": "hide_disconnect_reason", + "type": "bool" }, { - "name":"behaviourPackLength", - "type":"u16" + "name": "message", + "type": "string" + } + ] + ], + "packet_batch": [ + "container", + [ + { + "name": "payload", + "type": [ + "buffer", + { + "countType": "varint", + "type": "i8" + } + ] + } + ] + ], + "packet_resource_packs_info": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" }, { - "name":"resourcePackLength", - "type":"u16" + "name": "behahaviorpackinfos", + "type": "varint" + }, + { + "name": "resourcepackinfos", + "type": "varint" + } + ] + ], + "packet_resource_pack_stack": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behaviorpackidversions", + "type": "varint" + }, + { + "name": "resourcepackidversions", + "type": "varint" } ] ], @@ -846,1243 +415,1336 @@ "container", [ { - "name": "status", + "name": "response_status", + "type": "u8" + }, + { + "name": "resourcepackidversions", + "type": "varint" + } + ] + ], + "packet_text": [ + "container", + [ + { + "name": "type", "type": "i8" }, { - "name": "version", + "name": "source", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "1": "string", + "3": "string" + }, + "default": "void" + } + ] + }, + { + "name": "message", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "0": "string", + "1": "string", + "2": "string", + "3": "string", + "4": "string", + "5": "string" + }, + "default": "void" + } + ] + } + ] + ], + "packet_set_time": [ + "container", + [ + { + "name": "time", + "type": "varint" + }, + { + "name": "started", + "type": "bool" + } + ] + ], + "packet_start_game": [ + "container", + [ + { + "name": "entity_id", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "spawn", + "type": "vector3" + }, + { + "name": "unknown_1", + "type": "vector2" + }, + { + "name": "seed", + "type": "varint" + }, + { + "name": "dimension", + "type": "varint" + }, + { + "name": "generator", + "type": "varint" + }, + { + "name": "gamemode", + "type": "varint" + }, + { + "name": "difficulty", + "type": "varint" + }, + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + }, + { + "name": "has_achievements_disabled", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", + "type": "varint" + }, + { + "name": "edu_mode", + "type": "bool" + }, + { + "name": "rain_level", + "type": "f32" + }, + { + "name": "lightnig_level", + "type": "f32" + }, + { + "name": "enable_commands", + "type": "bool" + }, + { + "name": "is_texturepacks_required", + "type": "bool" + }, + { + "name": "secret", "type": "string" }, { - "name": "size", - "type": "u32" + "name": "world_name", + "type": "string" } ] ], - - "packet_text":[ + "packet_add_player": [ "container", [ { - "name":"type", - "type":"i8" - }, - - { - "name":"name", - "type":[ - "switch", - { - "compareTo":"type", - "fields":{ - "1":"string", - "3":"string" - }, - "default":"void" - } - ] + "name": "uuid", + "type": "uuid" }, { - "name":"message", - "type":[ - "switch", - { - "compareTo":"type", - "fields":{ - "0":"string", - "1":"string", - "2":"string", - "3":"string", - "4":"string", - "5":"string" - } - } - ] + "name": "username", + "type": "string" }, { - "name":"parameters", - "type":[ - "switch", - { - "compareTo":"type", - "fields":{ - "2":[ - "array", - { - "countType":"i8", - "type":"string" - } - ] - }, - "default":"void" - } - ] + "name": "entity_id", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "x", + "type": "f32" + }, + { + "name": "y", + "type": "f32" + }, + { + "name": "z", + "type": "f32" + }, + { + "name": "speed_x", + "type": "f32" + }, + { + "name": "speed_y", + "type": "f32" + }, + { + "name": "speed_z", + "type": "f32" + }, + { + "name": "pitch", + "type": "f32" + }, + { + "name": "head_yaw", + "type": "f32" + }, + { + "name": "yaw", + "type": "f32" + }, + { + "name": "item", + "type": "varint" + }, + { + "name": "metadata", + "type": "varint" } ] ], - "packet_set_time":[ + "packet_add_entity": [ "container", [ { - "name":"time", - "type":"varint" + "name": "entity_id", + "type": "varint" }, { - "name":"started", - "type":"bool" + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "entity_type", + "type": "varint" + }, + { + "name": "x", + "type": "f32" + }, + { + "name": "y", + "type": "f32" + }, + { + "name": "z", + "type": "f32" + }, + { + "name": "speed_x", + "type": "f32" + }, + { + "name": "speed_y", + "type": "f32" + }, + { + "name": "speed_z", + "type": "f32" + }, + { + "name": "yaw", + "type": "f32" + }, + { + "name": "pitch", + "type": "f32" + }, + { + "name": "attributes", + "type": "varint" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "links", + "type": "links" } ] ], - "packet_start_game":[ + "packet_remove_entity": [ "container", [ { - "name":"entityId", - "type":"varint" - }, - { - "name":"runtimeEntityId", - "type":"varint" - }, - { - "name":"x", - "type":"f32" - }, - { - "name":"y", - "type":"f32" - }, - { - "name":"z", - "type":"f32" - }, - { - "name":"unknownF1", - "type":"f64" - }, - { - "name":"unknownF2", - "type":"f64" - }, - { - "name":"seed", - "type":"varint" - }, - { - "name":"dimension", - "type":"varint" - }, - { - "name":"generator", - "type":"varint" - }, - { - "name":"gamemode", - "type":"varint" - }, - { - "name":"difficulty", - "type":"varint" - }, - { - "name":"spawnX", - "type":"f32" - }, - { - "name":"spawnY", - "type":"f32" - }, - { - "name":"spawnZ", - "type":"f32" - }, - { - "name":"achievementsDisabled", - "type":"bool" - }, - { - "name":"dayCycleStopTime", - "type":"varint" - }, - { - "name":"eduMode", - "type":"bool" - }, - { - "name":"rainLevel", - "type":"f64" - }, - { - "name":"lightningLevel", - "type":"f64" - }, - { - "name":"enableCommands", - "type":"bool" - }, - { - "name":"requireResourcePack", - "type":"bool" - }, - { - "name":"levelId", - "type":"string" - }, - { - "name":"worldName", - "type":"string" + "name": "entity_id", + "type": "varint" } ] ], - "packet_add_player":[ + "packet_add_item_entity": [ "container", [ { - "name":"uuid", - "type":"uuid" + "name": "entity_id", + "type": "varint" }, { - "name":"username", - "type":"string" + "name": "runtime_entity_id", + "type": "varint" }, { - "name":"entityId", - "type":"i64" + "name": "item", + "type": "varint" }, { - "name":"x", - "type":"f32" + "name": "x", + "type": "f32" }, { - "name":"y", - "type":"f32" + "name": "y", + "type": "f32" }, { - "name":"z", - "type":"f32" + "name": "z", + "type": "f32" }, { - "name":"speedX", - "type":"f32" + "name": "speed_x", + "type": "f32" }, { - "name":"speedY", - "type":"f32" + "name": "speed_y", + "type": "f32" }, { - "name":"speedZ", - "type":"f32" - }, - { - "name":"yaw", - "type":"f32" - }, - { - "name":"headYaw", - "type":"f32" - }, - { - "name":"pitch", - "type":"f32" - }, - { - "name":"item", - "type":"slot" - }, - { - "name":"metadata", - "type":"metadatadictionary" + "name": "speed_z", + "type": "f32" } ] ], - "packet_remove_player":[ + "packet_add_hanging_entity": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "entity_id", + "type": "varint" }, { - "name":"clientUuid", - "type":"uuid" + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "unknown", + "type": "varint" } ] ], - "packet_add_entity":[ + "packet_take_item_entity": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "target", + "type": "varint" }, { - "name":"entityType", - "type":"i32" - }, - { - "name":"x", - "type":"f32" - }, - { - "name":"y", - "type":"f32" - }, - { - "name":"z", - "type":"f32" - }, - { - "name":"speedX", - "type":"f32" - }, - { - "name":"speedY", - "type":"f32" - }, - { - "name":"speedZ", - "type":"f32" - }, - { - "name":"yaw", - "type":"f32" - }, - { - "name":"pitch", - "type":"f32" - }, - { - "name":"metadata", - "type":"metadatadictionary" - }, - { - "name":"links", - "type":"i16" + "name": "entity_id", + "type": "varint" } ] ], - "packet_remove_entity":[ + "packet_move_entity": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "entity_id", + "type": "varint" + }, + { + "name": "position", + "type": "playerlocation" } ] ], - "packet_add_item_entity":[ + "packet_move_player": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "entity_id", + "type": "varint" }, { - "name":"item", - "type":"slot" + "name": "x", + "type": "f32" }, { - "name":"x", - "type":"f32" + "name": "y", + "type": "f32" }, { - "name":"y", - "type":"f32" + "name": "z", + "type": "f32" }, { - "name":"z", - "type":"f32" + "name": "pitch", + "type": "f32" }, { - "name":"speedX", - "type":"f32" + "name": "head_yaw", + "type": "f32" }, { - "name":"speedY", - "type":"f32" + "name": "yaw", + "type": "f32" }, { - "name":"speedZ", - "type":"f32" + "name": "mode", + "type": "u8" + }, + { + "name": "on_ground", + "type": "bool" } ] ], - "packet_take_item_entity":[ + "packet_rider_jump": [ + "container", + [] + ], + "packet_remove_block": [ "container", [ { - "name":"target", - "type":"i64" - }, - { - "name":"entityId", - "type":"i64" + "name": "coordinates", + "type": "varint" } ] ], - "packet_move_entity":[ + "packet_update_block": [ "container", [ { - "name":"entities", - "type":"entitylocations" + "name": "coordinates", + "type": "varint" + }, + { + "name": "block_id", + "type": "varint" + }, + { + "name": "block_meta_and_priority", + "type": "varint" } ] ], - "packet_move_player":[ + "packet_add_painting": [ "container", [ { - "name":"entityId", - "type":"varint" + "name": "entity_id", + "type": "varint" }, { - "name":"x", - "type":"f32" + "name": "runtime_entity_id", + "type": "varint" }, { - "name":"y", - "type":"f32" + "name": "coordinates", + "type": "varint" }, { - "name":"z", - "type":"f32" + "name": "direction", + "type": "varint" }, { - "name":"pitch", - "type":"f32" - }, - { - "name":"headYaw", - "type":"f32" - }, - { - "name":"yaw", - "type":"f32" - }, - { - "name":"mode", - "type":"i8" - }, - { - "name":"onGround", - "type":"bool" + "name": "title", + "type": "string" } ] ], - "packet_remove_block":[ + "packet_explode": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "position", + "type": "vector3" }, { - "name":"x", - "type":"i32" + "name": "radius", + "type": "f32" }, { - "name":"z", - "type":"i32" - }, - { - "name":"y", - "type":"i8" + "name": "records", + "type": "varint" } ] ], - "packet_update_block":[ + "packet_level_sound_event": [ "container", [ { - "name":"blocks", - "type":"blockrecords" + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vector3" + }, + { + "name": "volume", + "type": "varint" + }, + { + "name": "pitch", + "type": "varint" + }, + { + "name": "unknown1", + "type": "bool" + }, + { + "name": "unknown2", + "type": "bool" } ] ], - "packet_add_painting":[ + "packet_level_event": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "event_id", + "type": "varint" }, { - "name":"x", - "type":"i32" + "name": "x", + "type": "f32" }, { - "name":"y", - "type":"i32" + "name": "y", + "type": "f32" }, { - "name":"z", - "type":"i32" + "name": "z", + "type": "f32" }, { - "name":"direction", - "type":"i32" - }, - { - "name":"title", - "type":"string" + "name": "data", + "type": "varint" } ] ], - "packet_explode":[ + "packet_block_event": [ "container", [ { - "name":"x", - "type":"f32" + "name": "coordinates", + "type": "varint" }, { - "name":"y", - "type":"f32" + "name": "case_1", + "type": "varint" }, { - "name":"z", - "type":"f32" - }, - { - "name":"radius", - "type":"f32" - }, - { - "name":"records", - "type":"records" + "name": "case_2", + "type": "varint" } ] ], - "packet_level_event":[ + "packet_entity_event": [ "container", [ { - "name":"eventId", - "type":"i16" + "name": "entity_id", + "type": "varint" }, { - "name":"x", - "type":"f32" + "name": "event_id", + "type": "u8" }, { - "name":"y", - "type":"f32" - }, - { - "name":"z", - "type":"f32" - }, - { - "name":"data", - "type":"i32" + "name": "unknown", + "type": "varint" } ] ], - "packet_block_event":[ + "packet_mob_effect": [ "container", [ { - "name":"x", - "type":"i32" + "name": "entity_id", + "type": "varint" }, { - "name":"y", - "type":"i32" + "name": "event_id", + "type": "u8" }, { - "name":"z", - "type":"i32" + "name": "effect_id", + "type": "varint" }, { - "name":"case1", - "type":"i32" + "name": "amplifier", + "type": "varint" }, { - "name":"case2", - "type":"i32" + "name": "particles", + "type": "bool" + }, + { + "name": "duration", + "type": "varint" } ] ], - "packet_entity_event":[ + "packet_update_attributes": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "entity_id", + "type": "varint" }, { - "name":"eventId", - "type":"i8" + "name": "attributes", + "type": "varint" } ] ], - "packet_mob_effect":[ + "packet_mob_equipment": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "entity_id", + "type": "varint" }, { - "name":"eventId", - "type":"i8" + "name": "item", + "type": "varint" }, { - "name":"effectId", - "type":"i8" + "name": "slot", + "type": "u8" }, { - "name":"amplifier", - "type":"i8" + "name": "selected_slot", + "type": "u8" }, { - "name":"particles", - "type":"i8" - }, - { - "name":"duration", - "type":"i32" + "name": "unknown", + "type": "u8" } ] ], - "packet_update_attributes":[ + "packet_mob_armor_equipment": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "entity_id", + "type": "varint" }, { - "name":"attributes", - "type":"playerattributes" + "name": "helmet", + "type": "varint" + }, + { + "name": "chestplate", + "type": "varint" + }, + { + "name": "leggings", + "type": "varint" + }, + { + "name": "boots", + "type": "varint" } ] ], - "packet_mob_equipment":[ + "packet_interact": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "action_id", + "type": "u8" }, { - "name":"item", - "type":"slot" - }, - { - "name":"slot", - "type":"i8" - }, - { - "name":"selectedSlot", - "type":"i8" + "name": "target_entity_id", + "type": "varint" } ] ], - "packet_mob_armor_equipment":[ + "packet_use_item": [ "container", [ { - "name":"entityId", - "type":"i64" + "name": "blockcoordinates", + "type": "varint" }, { - "name":"helmet", - "type":"slot" + "name": "face", + "type": "varint" }, { - "name":"chestplate", - "type":"slot" + "name": "facecoordinates", + "type": "vector3" }, { - "name":"leggings", - "type":"slot" + "name": "playerposition", + "type": "vector3" }, { - "name":"boots", - "type":"slot" + "name": "slot", + "type": "varint" + }, + { + "name": "item", + "type": "varint" } ] ], - "packet_interact":[ + "packet_player_action": [ "container", [ { - "name":"actionId", - "type":"i8" + "name": "entity_id", + "type": "varint" }, { - "name":"targetEntityId", - "type":"i64" + "name": "action_id", + "type": "varint" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "face", + "type": "varint" } ] ], - "packet_use_item":[ + "packet_hurt_armor": [ "container", [ { - "name":"blockcoordinates", - "type":"blockcoordinates" - }, - { - "name":"unknown", - "type":"varint" - }, - { - "name":"face", - "type":"varint" - }, - { - "name":"facecoordinates", - "type":"vector3" - }, - { - "name":"playerposition", - "type":"vector3" - }, - { - "name":"slot", - "type":"varint" - }, - { - "name":"item", - "type":"slot" + "name": "health", + "type": "varint" } ] ], - "packet_player_action":[ + "packet_set_entity_data": [ "container", [ { - "name":"entityId", - "type":"varint" + "name": "entity_id", + "type": "varint" }, { - "name":"actionId", - "type":"varint" - }, - { - "name":"blockcoordinates", - "type":"blockcoordinates" - }, - { - "name":"face", - "type":"varint" + "name": "metadata", + "type": "varint" } ] ], - "packet_hurt_armor":[ + "packet_set_entity_motion": [ "container", [ { - "name":"health", - "type":"i8" + "name": "entity_id", + "type": "varint" + }, + { + "name": "velocity", + "type": "vector3" } ] ], - "packet_set_entity_data":[ + "packet_set_entity_link": [ "container", [ { - "name":"entity_id", - "type":"i64" + "name": "rider_id", + "type": "varint" }, { - "name":"metadata", - "type":"metadatadictionary" + "name": "ridden_id", + "type": "varint" + }, + { + "name": "link_type", + "type": "u8" } ] ], - "packet_set_entity_motion":[ + "packet_set_health": [ "container", [ { - "name":"entities", - "type":"entitymotions" + "name": "health", + "type": "varint" } ] ], - "packet_set_entity_link":[ + "packet_set_spawn_position": [ "container", [ { - "name":"riderId", - "type":"i64" + "name": "unknown_1", + "type": "varint" }, { - "name":"riddenId", - "type":"i64" - }, - { - "name":"linkType", - "type":"i8" + "name": "coordinates", + "type": "varint" } ] ], - "packet_set_health":[ + "packet_animate": [ "container", [ { - "name":"health", - "type":"i32" + "name": "action_id", + "type": "varint" + }, + { + "name": "entity_id", + "type": "varint" } ] ], - "packet_set_spawn_position":[ + "packet_respawn": [ "container", [ { - "name":"x", - "type":"i32" + "name": "x", + "type": "f32" }, { - "name":"z", - "type":"i32" + "name": "y", + "type": "f32" }, { - "name":"y", - "type":"i32" + "name": "z", + "type": "f32" } ] ], - "packet_animate":[ + "packet_drop_item": [ "container", [ { - "name":"actionId", - "type":"i8" + "name": "itemtype", + "type": "u8" }, { - "name":"entityId", - "type":"i64" + "name": "item", + "type": "varint" } ] ], - "packet_respawn":[ + "packet_inventory_action": [ "container", [ { - "name":"x", - "type":"f32" + "name": "unknown", + "type": "varint" }, { - "name":"y", - "type":"f32" - }, - { - "name":"z", - "type":"f32" + "name": "item", + "type": "varint" } ] ], - "packet_drop_item":[ + "packet_container_open": [ "container", [ { - "name":"itemtype", - "type":"i8" + "name": "window_id", + "type": "u8" }, { - "name":"item", - "type":"slot" + "name": "type", + "type": "u8" + }, + { + "name": "slot_count", + "type": "varint" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "unown_entity_id", + "type": "varint" } ] ], - "packet_container_open":[ + "packet_container_close": [ "container", [ { - "name":"windowId", - "type":"i8" - }, - { - "name":"type", - "type":"i8" - }, - { - "name":"slotCount", - "type":"i16" - }, - { - "name":"x", - "type":"i32" - }, - { - "name":"y", - "type":"i32" - }, - { - "name":"z", - "type":"i32" + "name": "window_id", + "type": "u8" } ] ], - "packet_container_close":[ + "packet_container_set_slot": [ "container", [ { - "name":"windowId", - "type":"i8" + "name": "window_id", + "type": "u8" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "unknown", + "type": "varint" + }, + { + "name": "item", + "type": "varint" } ] ], - "packet_container_set_slot":[ + "packet_container_set_data": [ "container", [ { - "name":"windowId", - "type":"i8" + "name": "window_id", + "type": "u8" }, { - "name":"slot", - "type":"i16" + "name": "property", + "type": "varint" }, { - "name":"unknown", - "type":"i16" - }, - { - "name":"item", - "type":"slot" + "name": "value", + "type": "varint" } ] ], - "packet_container_set_data":[ + "packet_container_set_content": [ "container", [ { - "name":"windowId", - "type":"i8" + "name": "window_id", + "type": "u8" }, { - "name":"property", - "type":"i16" + "name": "slot_data", + "type": "varint" }, { - "name":"value", - "type":"i16" + "name": "hotbar_data", + "type": "varint" } ] ], - "packet_container_set_content":[ + "packet_crafting_data": [ "container", [ { - "name":"windowId", - "type":"i8" - }, - { - "name":"slotData", - "type":"itemstacks" - }, - { - "name":"hotbarData", - "type":[ - "switch", - { - "compareTo":"windowId", - "fields":{ - "0":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"slot", - "type":"i32" - } - ] - ] - } - ] - }, - "default":"i16" - } - ] + "name": "recipes", + "type": "varint" } ] ], - "packet_crafting_data":[ + "packet_crafting_event": [ "container", [ { - "name":"recipes", - "type":[ - "container", - [ - { - "name":"entryType", - "type":"i32" - }, - { - "name":"recipe", - "type":[ - "array", - { - "countType":"i32", - "type":[ - "switch", - { - "compareTo":"entryType", - "fields":{ - "0":"shapelessRecipe", - "1":"shapedRecipe", - "2":"furnaceRecipe", - "3":"furnaceRecipeData", - "4":"enchantList" - }, - "default":"void" - } - ] - } - ] - } - ] - ] + "name": "window_id", + "type": "u8" }, { - "name":"cleanRecipes", - "type":"i8" + "name": "recipe_type", + "type": "varint" + }, + { + "name": "recipe_id", + "type": "uuid" + }, + { + "name": "input", + "type": "varint" + }, + { + "name": "result", + "type": "varint" } ] ], - "packet_crafting_event":[ + "packet_adventure_settings": [ "container", [ { - "name":"windowId", - "type":"i8" + "name": "flags", + "type": "varint" }, { - "name":"recipeType", - "type":"i32" - }, - { - "name":"recipeId", - "type":"uuid" - }, - { - "name":"input", - "type":"itemstacks" - }, - { - "name":"result", - "type":"itemstacks" + "name": "user_permission", + "type": "varint" } ] ], - "packet_adventure_settings":[ + "packet_block_entity_data": [ "container", [ { - "name":"flags", - "type":"varint" + "name": "coordinates", + "type": "varint" }, { - "name":"userPermission", - "type":"varint" + "name": "namedtag", + "type": "varint" } ] ], - "packet_block_entity_data":[ + "packet_player_input": [ "container", [ { - "name":"x", - "type":"i32" + "name": "motion_x", + "type": "f32" }, { - "name":"y", - "type":"i32" + "name": "motion_z", + "type": "f32" }, { - "name":"z", - "type":"i32" + "name": "flag1", + "type": "bool" }, { - "name":"namedtag", - "type":"restBuffer" + "name": "flag2", + "type": "bool" } ] ], - "packet_player_input":[ + "packet_full_chunk_data": [ "container", [ { - "name":"motionX", - "type":"f32" + "name": "chunk_x", + "type": "varint" }, { - "name":"motionZ", - "type":"f32" + "name": "chunk_z", + "type": "varint" }, { - "name":"flags", - "type":"i16" - } - ] - ], - "packet_full_chunk_data":[ - "container", - [ - { - "name":"chunkX", - "type":"varint" + "name": "order", + "type": "u8" }, { - "name":"chunkZ", - "type":"varint" - }, - { - "name":"order", - "type":"i8" - }, - { - "name":"chunkData", - "type":[ + "name": "chunk_data", + "type": [ "buffer", { - "countType":"varint" + "countType": "varint", + "type": "i8" } ] } ] ], - "packet_set_difficulty":[ + "packet_set_commands_enabled": [ "container", [ { - "name":"difficulty", - "type":"varint" + "name": "enabled", + "type": "bool" } ] ], - "packet_player_list":[ + "packet_set_difficulty": [ "container", [ { - "name":"type", - "type":"i8" + "name": "difficulty", + "type": "varint" + } + ] + ], + "packet_change_dimension": [ + "container", + [ + { + "name": "dimension", + "type": "varint" }, { - "name":"entries", - "type":[ - "array", + "name": "position", + "type": "vector3" + }, + { + "name": "unknown", + "type": "bool" + } + ] + ], + "packet_set_player_game_type": [ + "container", + [ + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_player_list": [ + "container", + [ + { + "name": "records", + "type": "varint" + } + ] + ], + "packet_event": [ + "container", + [] + ], + "packet_spawn_experience_orb": [ + "container", + [ + { + "name": "position", + "type": "vector3" + }, + { + "name": "count", + "type": "varint" + } + ] + ], + "packet_clientbound_map_item_data_": [ + "container", + [ + { + "name": "mapinfo", + "type": "varint" + } + ] + ], + "packet_map_info_request": [ + "container", + [ + { + "name": "map_id", + "type": "varint" + } + ] + ], + "packet_request_chunk_radius": [ + "container", + [ + { + "name": "chunk_radius", + "type": "varint" + } + ] + ], + "packet_chunk_radius_update": [ + "container", + [ + { + "name": "chunk_radius", + "type": "varint" + } + ] + ], + "packet_item_fram_drop_item": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "item", + "type": "varint" + } + ] + ], + "packet_replace_selected_item": [ + "container", + [] + ], + "packet_game_rules_changed": [ + "container", + [ + { + "name": "rules", + "type": "varint" + } + ] + ], + "packet_camera": [ + "container", + [] + ], + "packet_add_item": [ + "container", + [] + ], + "packet_boss_event": [ + "container", + [] + ], + "packet_available_commands": [ + "container", + [ + { + "name": "commands", + "type": "string" + }, + { + "name": "unknown", + "type": "string" + } + ] + ], + "packet_command_step": [ + "container", + [ + { + "name": "command_name", + "type": "string" + }, + { + "name": "command_overload", + "type": "string" + }, + { + "name": "unknown_1", + "type": "varint" + }, + { + "name": "unknown_2", + "type": "varint" + }, + { + "name": "is_output", + "type": "bool" + }, + { + "name": "unknown_5", + "type": "varint" + }, + { + "name": "command_input_json", + "type": "string" + }, + { + "name": "command_output_json", + "type": "string" + }, + { + "name": "unknown_7", + "type": "u8" + }, + { + "name": "unknown_8", + "type": "u8" + }, + { + "name": "entity_id", + "type": "varint" + } + ] + ], + "packet_resource_pack_data_info": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "unknown1", + "type": "u32" + }, + { + "name": "unknown2", + "type": "u32" + }, + { + "name": "unknown3", + "type": "u64" + }, + { + "name": "unknown4", + "type": "string" + } + ] + ], + "packet_resource_pack_chunk_data": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "unknown1", + "type": "u32" + }, + { + "name": "unknown3", + "type": "u64" + }, + { + "name": "length", + "type": "u32" + }, + { + "name": "payload", + "type": [ + "buffer", { - "countType":"i32", - "type":[ - "switch", - { - "compareTo":"type", - "fields":{ - "0":[ - "container", - [ - { - "name":"clientUuid", - "type":"uuid" - }, - { - "name":"entityId", - "type":"i64" - }, - { - "name":"displayName", - "type":"string" - }, - { - "name":"skin", - "type":"skin" - } - ] - ], - "1":[ - "container", - [ - { - "name":"clientUuid", - "type":"uuid" - } - ] - ] - } - } - ] + "countType": "varint", + "type": "i8" } ] } ] ], - "map_info_request": [ + "packet_resource_pack_chunk_request": [ "container", [ { - "name":"mapID", - "type":"varint" - } - ] - ], - "packet_request_chunk_radius":[ - "container", - [ - { - "name":"chunkRadius", - "type":"varint" - } - ] - ], - "packet_chunk_radius_update":[ - "container", - [ - { - "name":"chunkRadius", - "type":"varint" - } - ] - ], - "packet_transfer":[ - "container", - [ - { - "name":"endpoint", - "type":"ipAddress" - } - ] - ], - "packet_spawn_experience_orb":[ - "container", - [ - { - "name":"entityId", - "type":"i64" + "name": "package_id", + "type": "string" }, { - "name":"x", - "type":"i32" - }, - { - "name":"y", - "type":"i32" - }, - { - "name":"z", - "type":"i32" - }, - { - "name":"count", - "type":"i32" - } - ] - ], - "packet_replace_selected_item":[ - "container", - [ - { - "name":"slot", - "type":"slot" + "name": "chunk_index", + "type": "i32" } ] ] From d478b66324f4bf6b154a75a994edf34e78dcc482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 14 Dec 2016 18:22:24 +0100 Subject: [PATCH 050/458] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d6110a5..433bbe8 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/mhsjlw/pocket-minecraft-protocol](https://badges.gitter.im/mhsjlw/pocket-minecraft-protocol.svg)](https://gitter.im/mhsjlw/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Parse and serialize Minecraft PE packets. +Parse and serialize Minecraft PE packets (use [this](https://gist.github.com/filfat/eb6cd08e1e789b5924f7f733babc4a25) to generate the protocol data). ## Features - * Supports Minecraft Pocket Edition `0.16.0` + * Supports Minecraft Pocket Edition `1.0` * Pure JavaScript * Easily send and listen for any packet * RakNet support through [node-raknet](https://github.com/mhsjlw/node-raknet) From f432468de3b925f18fb67ff7be4093fd7b7de3d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sat, 17 Dec 2016 18:25:20 +0100 Subject: [PATCH 051/458] 1.0 --- data/protocol.json | 106 +++++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index ba86305..02f4fdb 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -152,49 +152,50 @@ "0x22": "interact", "0x23": "use_item", "0x24": "player_action", - "0x25": "hurt_armor", - "0x26": "set_entity_data", - "0x27": "set_entity_motion", - "0x28": "set_entity_link", - "0x29": "set_health", - "0x2a": "set_spawn_position", - "0x2b": "animate", - "0x2c": "respawn", - "0x2d": "drop_item", - "0x2e": "inventory_action", - "0x2f": "container_open", - "0x30": "container_close", - "0x31": "container_set_slot", - "0x32": "container_set_data", - "0x33": "container_set_content", - "0x34": "crafting_data", - "0x35": "crafting_event", - "0x36": "adventure_settings", - "0x37": "block_entity_data", - "0x38": "player_input", - "0x39": "full_chunk_data", - "0x3a": "set_commands_enabled", - "0x3b": "set_difficulty", - "0x3c": "change_dimension", - "0x3d": "set_player_game_type", - "0x3e": "player_list", - "0x3f": "event", - "0x40": "spawn_experience_orb", - "0x41": "clientbound_map_item_data_", - "0x42": "map_info_request", - "0x43": "request_chunk_radius", - "0x44": "chunk_radius_update", - "0x45": "item_fram_drop_item", - "0x46": "replace_selected_item", - "0x47": "game_rules_changed", - "0x48": "camera", - "0x49": "add_item", - "0x4a": "boss_event", - "0x4b": "available_commands", - "0x4c": "command_step", - "0x4d": "resource_pack_data_info", - "0x4e": "resource_pack_chunk_data", - "0x4f": "resource_pack_chunk_request" + "0x25": "player_fall", + "0x26": "hurt_armor", + "0x27": "set_entity_data", + "0x28": "set_entity_motion", + "0x29": "set_entity_link", + "0x2a": "set_health", + "0x2b": "set_spawn_position", + "0x2c": "animate", + "0x2d": "respawn", + "0x2e": "drop_item", + "0x2f": "inventory_action", + "0x30": "container_open", + "0x31": "container_close", + "0x32": "container_set_slot", + "0x33": "container_set_data", + "0x34": "container_set_content", + "0x35": "crafting_data", + "0x36": "crafting_event", + "0x37": "adventure_settings", + "0x38": "block_entity_data", + "0x39": "player_input", + "0x3a": "full_chunk_data", + "0x3b": "set_commands_enabled", + "0x3c": "set_difficulty", + "0x3d": "change_dimension", + "0x3e": "set_player_game_type", + "0x3f": "player_list", + "0x40": "event", + "0x41": "spawn_experience_orb", + "0x42": "clientbound_map_item_data_", + "0x43": "map_info_request", + "0x44": "request_chunk_radius", + "0x45": "chunk_radius_update", + "0x46": "item_fram_drop_item", + "0x47": "replace_selected_item", + "0x48": "game_rules_changed", + "0x49": "camera", + "0x4a": "add_item", + "0x4b": "boss_event", + "0x4d": "available_commands", + "0x4e": "command_step", + "0x4f": "resource_pack_data_info", + "0x50": "resource_pack_chunk_data", + "0x51": "resource_pack_chunk_request" } } ] @@ -242,6 +243,7 @@ "interact": "packet_interact", "use_item": "packet_use_item", "player_action": "packet_player_action", + "player_fall": "packet_player_fall", "hurt_armor": "packet_hurt_armor", "set_entity_data": "packet_set_entity_data", "set_entity_motion": "packet_set_entity_motion", @@ -1103,6 +1105,10 @@ "name": "blockcoordinates", "type": "varint" }, + { + "name": "unknown", + "type": "varint" + }, { "name": "face", "type": "varint" @@ -1146,6 +1152,10 @@ } ] ], + "packet_player_fall": [ + "container", + [] + ], "packet_hurt_armor": [ "container", [ @@ -1322,12 +1332,16 @@ "type": "varint" }, { - "name": "unknown", + "name": "hotbarslot", "type": "varint" }, { "name": "item", "type": "varint" + }, + { + "name": "unknown2", + "type": "u8" } ] ], @@ -1457,10 +1471,6 @@ "name": "chunk_z", "type": "varint" }, - { - "name": "order", - "type": "u8" - }, { "name": "chunk_data", "type": [ From 74a3e6db452f27c24d5cc476fb38b482f6b4ce25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Tue, 20 Dec 2016 17:42:58 +0100 Subject: [PATCH 052/458] Add documentation. Add encryption toggle. --- src/createClient.js | 2 ++ src/createServer.js | 52 ++++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/createClient.js b/src/createClient.js index 3cd58e1..55d8f08 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -10,6 +10,8 @@ batchProto.addTypes(require("./datatypes/minecraft")); batchProto.addType("insideBatch",["endOfArray",{"type":["buffer",{"countType":"i32"}]}]); function createClient(options) { + return null; //FIXME + assert.ok(options, 'options is required'); var port = options.port || 19132; var host = options.host || 'localhost'; diff --git a/src/createServer.js b/src/createServer.js index da78b6f..e4e103d 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -20,66 +20,64 @@ batchProto.addType('insideBatch', ['endOfArray', { }]); const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; -function createServer(options) { + +// createServer (object, boolean) +// +// Create & launch a MCPE raknet-based server. +// object: raknet options +// encryption: enable/disable encryption +function createServer(options, encryption) { options = options || {}; - var port = options.port != null ? + const port = options.port != null ? options.port : options['server-port'] != null ? options['server-port'] : 19132; - var host = options.host || '0.0.0.0'; + const host = options.host || '0.0.0.0'; options.customPackets = require('../data/protocol'); options.customTypes = require('./datatypes/minecraft'); - var server = raknet.createServer(options); + let server = raknet.createServer(options); server.name = options.name || 'Minecraft Server'; - server.motd = options.motd || 'A Minecraft server'; - server.maxPlayers = options['max-players'] || 20; - server.playerCount = 0; - + server.motd = options.motd || 'A Minecraft server'; //FIXME + server.maxPlayers = options['max-players'] || 20; //FIXME + server.playerCount = 0; //FIXME + server.on('connection', function(client) { - - client.receiveCounter=0; - client.sendCounter=0; - - client.encryptionEnabled = false; + client.receiveCounter = 0; + client.sendCounter = 0; + client.encryptionEnabled = encryption ? encryption : true; let proto = new ProtoDef(); proto.addTypes(require('./datatypes/minecraft')); proto.addTypes(require('../data/protocol').types); client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); - - client.on('mcpe', packet => { - client.emit(packet.name, packet.params) - }); client.writeMCPE = (name, params) => { - if (client.encryptionEnabled) { + if (client.encryptionEnabled) client.mcpePacketSerializer.write({ name, params }); - } - else { + else client.writeEncapsulated('mcpe', { name, params }); - } }; - client.writeBatch = function(packets) { const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', - packets.map(packet => - client.mcpePacketSerializer.createPacketBuffer(packet)))); + packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packet)))); client.writeMCPE('batch', { payload: payload }); }; + client.on('mcpe', packet => { + client.emit(packet.name, packet.params) + }); client.on('batch', function(packet) { var buf = zlib.inflateSync(packet.payload); var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); }); - client.on('game_login', (packet) => { try { const dataProto = new ProtoDef(); @@ -95,6 +93,7 @@ function createServer(options) { }] }]]); + //FIXME: Xbox & Non-Xbox support let body = dataProto.parsePacketBuffer('data_chain', zlib.inflateSync(packet.body)), chain = null, decode = null, @@ -115,8 +114,9 @@ function createServer(options) { skinData: data.SkinData, skinId: data.SkinId }) - } catch(err) { + } catch (err) { console.log(err); + return null; } }); }); From 0ed2e7b61cf6ab9905fa1d9d8e9238341a63fd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Tue, 20 Dec 2016 18:22:37 +0100 Subject: [PATCH 053/458] Remove unused modules. --- src/createServer.js | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index e4e103d..516d548 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -4,18 +4,14 @@ let raknet = require('raknet'), ProtoDef = require('protodef').ProtoDef, Parser = require('protodef').Parser, Serializer = require('protodef').Serializer, - jwt = require('jwt-simple'), - crypto = require('crypto'), - Ber = require('asn1').Ber, - merge = require('lodash.merge'), - assert = require('assert'); + jwt = require('jwt-simple'); var debug = require('debug')('raknet'); -const batchProto = new ProtoDef(); +let batchProto = new ProtoDef(); batchProto.addTypes(require('./datatypes/minecraft')); batchProto.addType('insideBatch', ['endOfArray', { 'type': ['buffer', { - 'countType': 'varint' + 'countType': 'varint', }] }]); @@ -48,13 +44,22 @@ function createServer(options, encryption) { server.on('connection', function(client) { client.receiveCounter = 0; client.sendCounter = 0; - client.encryptionEnabled = encryption ? encryption : true; + client.encryptionEnabled = encryption ? encryption : false; let proto = new ProtoDef(); proto.addTypes(require('./datatypes/minecraft')); proto.addTypes(require('../data/protocol').types); client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); + client.on('mcpe', packet => { + client.emit(packet.name, packet.params) + }); + client.on('batch', function (packet) { + var buf = zlib.inflateSync(packet.payload); + var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; + packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); + }); + client.writeMCPE = (name, params) => { if (client.encryptionEnabled) client.mcpePacketSerializer.write({ name, params }); @@ -70,17 +75,9 @@ function createServer(options, encryption) { }); }; - client.on('mcpe', packet => { - client.emit(packet.name, packet.params) - }); - client.on('batch', function(packet) { - var buf = zlib.inflateSync(packet.payload); - var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); - }); client.on('game_login', (packet) => { try { - const dataProto = new ProtoDef(); + let dataProto = new ProtoDef(); dataProto.addType('data_chain', ['container', [{ 'name': 'chain', 'type': ['pstring', { @@ -102,7 +99,7 @@ function createServer(options, encryption) { body.data.chain = JSON.parse(body.data.chain); chain = body.data.chain.chain[0]; - decode = jwt.decode(chain, 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V', 'ES384'); + decode = jwt.decode(chain, PUBLIC_KEY, 'ES384'); data = jwt.decode(body.data.clientData, decode.identityPublicKey, 'ES384'); data.SkinData = null; From 0c1bf07d0ca51b243d6cc0466e0072830e595fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Tue, 20 Dec 2016 18:23:26 +0100 Subject: [PATCH 054/458] Fix encryption toggle. From 151be30ca5c919e7878f932f61f93c334da19ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 29 Dec 2016 16:06:03 +0100 Subject: [PATCH 055/458] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 433bbe8..ce7feab 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,7 @@ This project is run by these guys: - [Filiph Sandström](https://github.com/filfat) - [mhsjlw](https://github.com/mhsjlw) - [rom1504](https://github.com/rom1504) + +## License +Licensed under the MIT license. +ANY modifications/patches made by Filiph Sandström is licensed under the [ABRMS license](https://gist.github.com/filfat/d2ef7dffb50901064df06609d00f82ec). From 1dae81fcb284be8e067020a955d2666e7673926a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Thu, 29 Dec 2016 16:19:41 +0100 Subject: [PATCH 056/458] Retracted the ABRMS license. I still don't like you RMS though. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ce7feab..cb69cf7 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,3 @@ This project is run by these guys: ## License Licensed under the MIT license. -ANY modifications/patches made by Filiph Sandström is licensed under the [ABRMS license](https://gist.github.com/filfat/d2ef7dffb50901064df06609d00f82ec). From 24ef9c5da1456cd0142d22e1f8ba23a64fcd32e7 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Tue, 17 Jan 2017 16:05:15 +0100 Subject: [PATCH 057/458] adapt chat except translate see https://github.com/NiclasOlofsson/MiNET/blob/master/src/MiNET/MiNET/Net/McpeText.cs --- data/protocol.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 02f4fdb..08d4f97 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -440,8 +440,7 @@ { "compareTo": "type", "fields": { - "1": "string", - "3": "string" + "1": "string" }, "default": "void" } @@ -458,8 +457,7 @@ "1": "string", "2": "string", "3": "string", - "4": "string", - "5": "string" + "4": "string" }, "default": "void" } From ae22c37c20e1ba72e8a6426d12df17d3c6832ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Tue, 17 Jan 2017 23:10:42 +0100 Subject: [PATCH 058/458] Changed order of "Contributors". Let's face it, they've done a lot more than I'll eve be able to do for this project. Also, most likely they're a lot better looking than me too; so there's that. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb69cf7..54f647e 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,9 @@ Then view our `examples` for inspiration! ## Contributors This project is run by these guys: - - [Filiph Sandström](https://github.com/filfat) - [mhsjlw](https://github.com/mhsjlw) - [rom1504](https://github.com/rom1504) + - [Filiph Sandström](https://github.com/filfat) ## License Licensed under the MIT license. From e48f146528795cc7d003ea02b8fe270a3c8c14b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Wed, 18 Jan 2017 09:26:56 +0100 Subject: [PATCH 059/458] Add writePacket and writeData. --- src/createServer.js | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 516d548..90a6cdd 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -44,7 +44,7 @@ function createServer(options, encryption) { server.on('connection', function(client) { client.receiveCounter = 0; client.sendCounter = 0; - client.encryptionEnabled = encryption ? encryption : false; + client.encryptionEnabled = encryption ? true : false; let proto = new ProtoDef(); proto.addTypes(require('./datatypes/minecraft')); @@ -60,22 +60,45 @@ function createServer(options, encryption) { packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); }); - client.writeMCPE = (name, params) => { - if (client.encryptionEnabled) + // client.writePacket (string, object) + // Send data to the client + // + // string: packet name + // object: packet data + client.writeMCPE = function (name, params) { + if (client.encryptionEnabled) { client.mcpePacketSerializer.write({ name, params }); - else + } else { client.writeEncapsulated('mcpe', { name, params }); + } }; - client.writeBatch = function(packets) { + client.writePacket = client.writeMCPE; + + // client.writeData (array) + // Send data to the client + // + // array: packets to send + client.writeBatch = function (packets) { const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packet)))); - client.writeMCPE('batch', { + client.writePacket('batch', { payload: payload }); }; + client.writeData = client.writeBatch; - client.on('game_login', (packet) => { + // client.writeAll (string, object) + // Send data to the client + // + // string: packet name + // object: packet data + client.writeAll = function (name, data) { + return; //TODO + server._writeAll(name, data); + }; + + client.on('game_login', function (packet) { try { let dataProto = new ProtoDef(); dataProto.addType('data_chain', ['container', [{ @@ -91,6 +114,7 @@ function createServer(options, encryption) { }]]); //FIXME: Xbox & Non-Xbox support + console.log(packet); let body = dataProto.parsePacketBuffer('data_chain', zlib.inflateSync(packet.body)), chain = null, decode = null, @@ -120,4 +144,4 @@ function createServer(options, encryption) { return server; } -module.exports = createServer; +module.exports = createServer; \ No newline at end of file From 239acc73b4d24f115db0f9ed7a7834ee6c3b582e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Fri, 20 Jan 2017 09:18:06 +0100 Subject: [PATCH 060/458] Update createServer.js --- src/createServer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 90a6cdd..01bcff3 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -80,7 +80,7 @@ function createServer(options, encryption) { // array: packets to send client.writeBatch = function (packets) { const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', - packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packet)))); + packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packets)))); client.writePacket('batch', { payload: payload @@ -144,4 +144,4 @@ function createServer(options, encryption) { return server; } -module.exports = createServer; \ No newline at end of file +module.exports = createServer; From 5c6042b61f3ba351033c43bba9a1c53aa4e482de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Fri, 20 Jan 2017 09:21:05 +0100 Subject: [PATCH 061/458] *faceplam* --- src/createServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/createServer.js b/src/createServer.js index 01bcff3..aaa3f44 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -80,7 +80,7 @@ function createServer(options, encryption) { // array: packets to send client.writeBatch = function (packets) { const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', - packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packets)))); + packets.map(packets => client.mcpePacketSerializer.createPacketBuffer(packets)))); client.writePacket('batch', { payload: payload From dd4393272061c45eedb06d0f0d5f2943478b7f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Fri, 20 Jan 2017 09:44:22 +0100 Subject: [PATCH 062/458] Update protocol.json --- data/protocol.json | 92 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 08d4f97..a6ba045 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -17,15 +17,15 @@ [ { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" } ] ], @@ -51,15 +51,15 @@ [ { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" }, { "name": "yaw", @@ -543,11 +543,11 @@ }, { "name": "rain_level", - "type": "f32" + "type": "lf32" }, { "name": "lightnig_level", - "type": "f32" + "type": "lf32" }, { "name": "enable_commands", @@ -588,39 +588,39 @@ }, { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" }, { "name": "speed_x", - "type": "f32" + "type": "lf32" }, { "name": "speed_y", - "type": "f32" + "type": "lf32" }, { "name": "speed_z", - "type": "f32" + "type": "lf32" }, { "name": "pitch", - "type": "f32" + "type": "lf32" }, { "name": "head_yaw", - "type": "f32" + "type": "lf32" }, { "name": "yaw", - "type": "f32" + "type": "lf32" }, { "name": "item", @@ -649,35 +649,35 @@ }, { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" }, { "name": "speed_x", - "type": "f32" + "type": "lf32" }, { "name": "speed_y", - "type": "f32" + "type": "lf32" }, { "name": "speed_z", - "type": "f32" + "type": "lf32" }, { "name": "yaw", - "type": "f32" + "type": "lf32" }, { "name": "pitch", - "type": "f32" + "type": "lf32" }, { "name": "attributes", @@ -719,27 +719,27 @@ }, { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" }, { "name": "speed_x", - "type": "f32" + "type": "lf32" }, { "name": "speed_y", - "type": "f32" + "type": "lf32" }, { "name": "speed_z", - "type": "f32" + "type": "lf32" } ] ], @@ -799,27 +799,27 @@ }, { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" }, { "name": "pitch", - "type": "f32" + "type": "lf32" }, { "name": "head_yaw", - "type": "f32" + "type": "lf32" }, { "name": "yaw", - "type": "f32" + "type": "lf32" }, { "name": "mode", @@ -895,7 +895,7 @@ }, { "name": "radius", - "type": "f32" + "type": "lf32" }, { "name": "records", @@ -941,15 +941,15 @@ }, { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" }, { "name": "data", @@ -1246,15 +1246,15 @@ [ { "name": "x", - "type": "f32" + "type": "lf32" }, { "name": "y", - "type": "f32" + "type": "lf32" }, { "name": "z", - "type": "f32" + "type": "lf32" } ] ], @@ -1442,11 +1442,11 @@ [ { "name": "motion_x", - "type": "f32" + "type": "lf32" }, { "name": "motion_z", - "type": "f32" + "type": "lf32" }, { "name": "flag1", From c3671edc01a060ecfb34c5a4e69c3444c4e4c159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sat, 21 Jan 2017 12:44:12 +0100 Subject: [PATCH 063/458] Fix minor issue. --- src/createServer.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index aaa3f44..afb0845 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -52,10 +52,11 @@ function createServer(options, encryption) { client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); client.on('mcpe', packet => { - client.emit(packet.name, packet.params) + client.emit(packet.name, packet.params); + client.emit('debug', packet.name); }); - client.on('batch', function (packet) { - var buf = zlib.inflateSync(packet.payload); + client.on('batch', function (packets) { + var buf = zlib.inflateSync(packets.payload); var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); }); @@ -80,7 +81,7 @@ function createServer(options, encryption) { // array: packets to send client.writeBatch = function (packets) { const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', - packets.map(packets => client.mcpePacketSerializer.createPacketBuffer(packets)))); + packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packet)))); client.writePacket('batch', { payload: payload From a187f0a9bedc8991b326db9af8b09b5fbea6222c Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Sun, 22 Jan 2017 13:28:23 -0500 Subject: [PATCH 064/458] updates ! --- data/protocol.json | 4045 +++++++++++++++++++++++++------------------- 1 file changed, 2296 insertions(+), 1749 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index a6ba045..5f72188 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -1,1760 +1,2307 @@ { - "types": { - "string": [ - "pstring", + "types":{ + "string":[ + "pstring", + { + "countType":"varint" + } + ], + "lstring":[ + "pstring", + { + "countType":"li16" + } + ], + "rules":[ + "array", + { + "countType":"varint", + "type":[ + "container", + [ { - "countType": "i16" - } - ], - "lstring": [ - "pstring", + "name":"name", + "type":"string" + }, { - "countType": "li16" + "name":"unknown1", + "type":"bool" + }, + { + "name":"unknown2", + "type":"bool" } - ], - "vector3": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vector2": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - } - ] - ], - "playerlocation": [ + ] + ] + } + ], + "shapeless_recipe":[ + "container", + [ + { + "name":"ingredientList", + "type":[ "array", { - "countType": "i16", - "type": [ + "countType":"i32", + "type":"slot" + } + ] + }, + { + "name":"resultCount", + "type":"i32" + }, + { + "name":"slot", + "type":"slot" + }, + { + "name":"id", + "type":"uuid" + } + ] + ], + "shaped_recipe":[ + "container", + [ + { + "name":"width", + "type":[ + "count", + { + "type":"i32", + "countFor":"shape" + } + ] + }, + { + "name":"height", + "type":[ + "count", + { + "type":"i32", + "countFor":"shape/0" + } + ] + }, + { + "name":"shape", + "type":[ + "array", + { + "count":"width", + "type":[ + "array", + { + "count":"height", + "type":"slot" + } + ] + } + ] + }, + { + "name":"resultCount", + "type":"i32" + }, + { + "name":"slot", + "type":"slot" + }, + { + "name":"id", + "type":"uuid" + } + ] + ], + "furnace_recipe":[ + "container", + [ + { + "name":"meta", + "type":"i16" + }, + { + "name":"id", + "type":"i16" + }, + { + "name":"result", + "type":"slot" + } + ] + ], + "furnace_recipe_data":[ + "container", + [ + { + "name":"id", + "type":"i16" + }, + { + "name":"meta", + "type":"i16" + }, + { + "name":"result", + "type":"slot" + } + ] + ], + "enchant_list":[ + "array", + { + "countType":"i8", + "type":[ + "container", + [ + { + "name":"cost", + "type":"i32" + }, + { + "name":"enchantments", + "type":[ + "array", + { + "countType":"i8", + "type":[ "container", [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "headYaw", - "type": "f32" - } + { + "name":"id", + "type":"i32" + }, + { + "name":"level", + "type":"i32" + } ] - ] + ] + } + ] + }, + { + "name":"name", + "type":"string" } - ], - "encapsulated_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0xfe": "mcpe" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "mcpe": "mcpe_packet" - } - } - ] - } - ] - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0x01": "game_login", - "0x02": "player_status", - "0x03": "server_to_client_handshake", - "0x04": "client_to_server_handshake", - "0x05": "disconnect", - "0x06": "batch", - "0x07": "resource_packs_info", - "0x08": "resource_pack_stack", - "0x09": "resource_pack_client_response", - "0x0a": "text", - "0x0b": "set_time", - "0x0c": "start_game", - "0x0d": "add_player", - "0x0e": "add_entity", - "0x0f": "remove_entity", - "0x10": "add_item_entity", - "0x11": "add_hanging_entity", - "0x12": "take_item_entity", - "0x13": "move_entity", - "0x14": "move_player", - "0x15": "rider_jump", - "0x16": "remove_block", - "0x17": "update_block", - "0x18": "add_painting", - "0x19": "explode", - "0x1a": "level_sound_event", - "0x1b": "level_event", - "0x1c": "block_event", - "0x1d": "entity_event", - "0x1e": "mob_effect", - "0x1f": "update_attributes", - "0x20": "mob_equipment", - "0x21": "mob_armor_equipment", - "0x22": "interact", - "0x23": "use_item", - "0x24": "player_action", - "0x25": "player_fall", - "0x26": "hurt_armor", - "0x27": "set_entity_data", - "0x28": "set_entity_motion", - "0x29": "set_entity_link", - "0x2a": "set_health", - "0x2b": "set_spawn_position", - "0x2c": "animate", - "0x2d": "respawn", - "0x2e": "drop_item", - "0x2f": "inventory_action", - "0x30": "container_open", - "0x31": "container_close", - "0x32": "container_set_slot", - "0x33": "container_set_data", - "0x34": "container_set_content", - "0x35": "crafting_data", - "0x36": "crafting_event", - "0x37": "adventure_settings", - "0x38": "block_entity_data", - "0x39": "player_input", - "0x3a": "full_chunk_data", - "0x3b": "set_commands_enabled", - "0x3c": "set_difficulty", - "0x3d": "change_dimension", - "0x3e": "set_player_game_type", - "0x3f": "player_list", - "0x40": "event", - "0x41": "spawn_experience_orb", - "0x42": "clientbound_map_item_data_", - "0x43": "map_info_request", - "0x44": "request_chunk_radius", - "0x45": "chunk_radius_update", - "0x46": "item_fram_drop_item", - "0x47": "replace_selected_item", - "0x48": "game_rules_changed", - "0x49": "camera", - "0x4a": "add_item", - "0x4b": "boss_event", - "0x4d": "available_commands", - "0x4e": "command_step", - "0x4f": "resource_pack_data_info", - "0x50": "resource_pack_chunk_data", - "0x51": "resource_pack_chunk_request" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "game_login": "packet_game_login", - "player_status": "packet_player_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "batch": "packet_batch", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "add_hanging_entity": "packet_add_hanging_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "remove_block": "packet_remove_block", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "explode": "packet_explode", - "level_sound_event": "packet_level_sound_event", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "use_item": "packet_use_item", - "player_action": "packet_player_action", - "player_fall": "packet_player_fall", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "drop_item": "packet_drop_item", - "inventory_action": "packet_inventory_action", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "container_set_slot": "packet_container_set_slot", - "container_set_data": "packet_container_set_data", - "container_set_content": "packet_container_set_content", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "full_chunk_data": "packet_full_chunk_data", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "event": "packet_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data_": "packet_clientbound_map_item_data_", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_fram_drop_item": "packet_item_fram_drop_item", - "replace_selected_item": "packet_replace_selected_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "add_item": "packet_add_item", - "boss_event": "packet_boss_event", - "available_commands": "packet_available_commands", - "command_step": "packet_command_step", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request" - } - } - ] - } - ] - ], - "packet_game_login": [ - "container", - [ - { - "name": "protocol", - "type": "i32" - }, - { - "name": "edition", - "type": "i8" - }, - { - "name": "body", - "type": [ - "buffer", - { - "countType": "varint" - } - ] - } - ] - ], - "packet_player_status": [ - "container", - [ - { - "name": "status", - "type": "i32" - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "server_public_key", - "type": "string" - }, - { - "name": "token_length", - "type": "length" - }, - { - "name": "token", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_batch": [ - "container", - [ - { - "name": "payload", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behahaviorpackinfos", - "type": "varint" - }, - { - "name": "resourcepackinfos", - "type": "varint" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behaviorpackidversions", - "type": "varint" - }, - { - "name": "resourcepackidversions", - "type": "varint" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": "u8" - }, - { - "name": "resourcepackidversions", - "type": "varint" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": "i8" - }, - { - "name": "source", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "1": "string" - }, - "default": "void" - } - ] - }, - { - "name": "message", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "0": "string", - "1": "string", - "2": "string", - "3": "string", - "4": "string" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "varint" - }, - { - "name": "started", - "type": "bool" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "spawn", - "type": "vector3" - }, - { - "name": "unknown_1", - "type": "vector2" - }, - { - "name": "seed", - "type": "varint" - }, - { - "name": "dimension", - "type": "varint" - }, - { - "name": "generator", - "type": "varint" - }, - { - "name": "gamemode", - "type": "varint" - }, - { - "name": "difficulty", - "type": "varint" - }, - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - }, - { - "name": "has_achievements_disabled", - "type": "bool" - }, - { - "name": "day_cycle_stop_time", - "type": "varint" - }, - { - "name": "edu_mode", - "type": "bool" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightnig_level", - "type": "lf32" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - { - "name": "secret", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "metadata", - "type": "varint" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "attributes", - "type": "varint" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "links", - "type": "links" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - } - ] - ], - "packet_add_hanging_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "target", - "type": "varint" - }, - { - "name": "entity_id", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "position", - "type": "playerlocation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": "u8" - }, - { - "name": "on_ground", - "type": "bool" - } - ] - ], - "packet_rider_jump": [ - "container", - [] - ], - "packet_remove_block": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "block_id", - "type": "varint" - }, - { - "name": "block_meta_and_priority", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "direction", - "type": "varint" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_explode": [ - "container", - [ - { - "name": "position", - "type": "vector3" - }, - { - "name": "radius", - "type": "lf32" - }, - { - "name": "records", - "type": "varint" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "volume", - "type": "varint" - }, - { - "name": "pitch", - "type": "varint" - }, - { - "name": "unknown1", - "type": "bool" - }, - { - "name": "unknown2", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "data", - "type": "varint" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "case_1", - "type": "varint" - }, - { - "name": "case_2", - "type": "varint" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "varint" - }, - { - "name": "amplifier", - "type": "varint" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "varint" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "attributes", - "type": "varint" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "unknown", - "type": "u8" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "helmet", - "type": "varint" - }, - { - "name": "chestplate", - "type": "varint" - }, - { - "name": "leggings", - "type": "varint" - }, - { - "name": "boots", - "type": "varint" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": "u8" - }, - { - "name": "target_entity_id", - "type": "varint" - } - ] - ], - "packet_use_item": [ - "container", - [ - { - "name": "blockcoordinates", - "type": "varint" - }, - { - "name": "unknown", - "type": "varint" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "facecoordinates", - "type": "vector3" - }, - { - "name": "playerposition", - "type": "vector3" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "action_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "face", - "type": "varint" - } - ] - ], - "packet_player_fall": [ - "container", - [] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "varint" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "metadata", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "velocity", - "type": "vector3" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "rider_id", - "type": "varint" - }, - { - "name": "ridden_id", - "type": "varint" - }, - { - "name": "link_type", - "type": "u8" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "varint" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "unknown_1", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": "varint" - }, - { - "name": "entity_id", - "type": "varint" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "packet_drop_item": [ - "container", - [ - { - "name": "itemtype", - "type": "u8" - }, - { - "name": "item", - "type": "varint" - } - ] - ], - "packet_inventory_action": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "slot_count", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "unown_entity_id", - "type": "varint" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - } - ] - ], - "packet_container_set_slot": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "hotbarslot", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "unknown2", - "type": "u8" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "property", - "type": "varint" - }, - { - "name": "value", - "type": "varint" - } - ] - ], - "packet_container_set_content": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "slot_data", - "type": "varint" - }, - { - "name": "hotbar_data", - "type": "varint" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "varint" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "recipe_type", - "type": "varint" - }, - { - "name": "recipe_id", - "type": "uuid" - }, - { - "name": "input", - "type": "varint" - }, - { - "name": "result", - "type": "varint" - } - ] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "varint" - }, - { - "name": "user_permission", - "type": "varint" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "flag1", - "type": "bool" - }, - { - "name": "flag2", - "type": "bool" - } - ] - ], - "packet_full_chunk_data": [ - "container", - [ - { - "name": "chunk_x", - "type": "varint" - }, - { - "name": "chunk_z", - "type": "varint" - }, - { - "name": "chunk_data", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "unknown", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "varint" - } - ] - ], - "packet_event": [ - "container", - [] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vector3" - }, - { - "name": "count", - "type": "varint" - } - ] - ], - "packet_clientbound_map_item_data_": [ - "container", - [ - { - "name": "mapinfo", - "type": "varint" - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "varint" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "varint" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "varint" - } - ] - ], - "packet_item_fram_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - } - ] - ], - "packet_replace_selected_item": [ - "container", - [] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "varint" - } - ] - ], - "packet_camera": [ - "container", - [] - ], - "packet_add_item": [ - "container", - [] - ], - "packet_boss_event": [ - "container", - [] - ], - "packet_available_commands": [ - "container", - [ - { - "name": "commands", - "type": "string" - }, - { - "name": "unknown", - "type": "string" - } - ] - ], - "packet_command_step": [ - "container", - [ - { - "name": "command_name", - "type": "string" - }, - { - "name": "command_overload", - "type": "string" - }, - { - "name": "unknown_1", - "type": "varint" - }, - { - "name": "unknown_2", - "type": "varint" - }, - { - "name": "is_output", - "type": "bool" - }, - { - "name": "unknown_5", - "type": "varint" - }, - { - "name": "command_input_json", - "type": "string" - }, - { - "name": "command_output_json", - "type": "string" - }, - { - "name": "unknown_7", - "type": "u8" - }, - { - "name": "unknown_8", - "type": "u8" - }, - { - "name": "entity_id", - "type": "varint" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "unknown1", - "type": "u32" - }, - { - "name": "unknown2", - "type": "u32" - }, - { - "name": "unknown3", - "type": "u64" - }, - { - "name": "unknown4", - "type": "string" - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "unknown1", - "type": "u32" - }, - { - "name": "unknown3", - "type": "u64" - }, - { - "name": "length", - "type": "u32" - }, - { - "name": "payload", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "i32" - } - ] + ] ] - } -} + } + ], + "blockcoordinates":[ + "container", + [ + { + "name":"x", + "type":"i32" + }, + { + "name":"y", + "type":"i32" + }, + { + "name":"z", + "type":"i32" + } + ] + ], + "records":[ + "array", + { + "countType":"varint", + "type":[ + "container", + [ + { + "name":"record", + "type":"blockcoordinates" + } + ] + ] + } + ], + "itemstacks":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"slot", + "type":"slot" + } + ] + ] + } + ], + "links":[ + "array", + { + "countType":"varint", + "type":[ + "container", + [ + { + "name":"item_1", + "type":"varint" + }, + { + "name":"item_2", + "type":"varint" + }, + { + "name":"unknown", + "type":"li16" + } + ] + ] + } + ], + "player_attributes":[ + "array", + { + "countType":"varint", + "type":[ + "container", + [ + { + "name":"min_value", + "type":"f32" + }, + { + "name":"max_value", + "type":"f32" + }, + { + "name":"value", + "type":"f32" + }, + { + "name":"unknown", + "type":"f32" + }, + { + "name":"name", + "type":"string" + } + ] + ] + } + ], + "entity_attributes":[ + "array", + { + "countType":"varint", + "type":[ + "container", + [ + { + "name":"name", + "type":"string" + }, + { + "name":"min_value", + "type":"f32" + }, + { + "name":"value", + "type":"f32" + }, + { + "name":"max_value", + "type":"f32" + } + ] + ] + } + ], + "pack_entries":[ + "array", + { + "countType":"li16", + "type":[ + "container", + [ + { + "name":"pack_id", + "type":"string" + }, + { + "name":"version", + "type":"string" + }, + { + "name":"pack_size", + "type":"u64" + } + ] + ] + } + ], + "pack_versions":[ + "array", + { + "countType":"li16", + "type":[ + "container", + [ + { + "name":"pack_id", + "type":"string" + }, + { + "name":"version", + "type":"string" + } + ] + ] + } + ], + "vector3":[ + "container", + [ + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + } + ] + ], + "metadataints":[ + "array", + { + "countType":"varint", + "type":[ + "container", + [ + { + + } + ] + ] + } + ], + "vector2":[ + "container", + [ + { + "name":"x", + "type":"f32" + }, + { + "name":"y", + "type":"f32" + } + ] + ], + "metadatadictionary":[ + "entityMetadataLoop", + { + "endVal":127, + "type":[ + "container", + [ + { + "anon":true, + "type":[ + "bitfield", + [ + { + "name":"type", + "size":3, + "signed":false + }, + { + "name":"key", + "size":5, + "signed":false + } + ] + ] + }, + { + "name":"value", + "type":[ + "entityMetadataItem", + { + "compareTo":"type" + } + ] + } + ] + ] + } + ], + "slot":[ + "container", + [ + { + "name":"blockId", + "type":"i16" + }, + { + "anon":true, + "type":[ + "switch", + { + "compareTo":"blockId", + "fields":{ + "0":"void" + }, + "default":[ + "container", + [ + { + "name":"itemCount", + "type":"i8" + }, + { + "name":"itemDamage", + "type":"i16" + }, + { + "name":"nbtData", + "type":[ + "buffer", + { + "countType":"li16" + } + ] + } + ] + ] + } + ] + } + ] + ], + "playerlocation":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + }, + { + "name":"yaw", + "type":"f32" + }, + { + "name":"pitch", + "type":"f32" + }, + { + "name":"headYaw", + "type":"f32" + } + ] + ] + } + ], + "encapsulated_packet":[ + "container", + [ + { + "name":"name", + "type":[ + "mapper", + { + "type":"u8", + "mappings":{ + "0xfe":"mcpe" + } + } + ] + }, + { + "name":"params", + "type":[ + "switch", + { + "compareTo":"name", + "fields":{ + "mcpe":"mcpe_packet" + } + } + ] + } + ] + ], + "mcpe_packet":[ + "container", + [ + { + "name":"name", + "type":[ + "mapper", + { + "type":"u8", + "mappings":{ + "0x01":"game_login", + "0x02":"player_status", + "0x03":"server_to_client_handshake", + "0x04":"client_to_server_handshake", + "0x05":"disconnect", + "0x06":"batch", + "0x07":"resource_packs_info", + "0x08":"resource_pack_stack", + "0x09":"resource_pack_client_response", + "0x0a":"text", + "0x0b":"set_time", + "0x0c":"start_game", + "0x0d":"add_player", + "0x0e":"add_entity", + "0x0f":"remove_entity", + "0x10":"add_item_entity", + "0x11":"add_hanging_entity", + "0x12":"take_item_entity", + "0x13":"move_entity", + "0x14":"move_player", + "0x15":"rider_jump", + "0x16":"remove_block", + "0x17":"update_block", + "0x18":"add_painting", + "0x19":"explode", + "0x1a":"level_sound_event", + "0x1b":"level_event", + "0x1c":"block_event", + "0x1d":"entity_event", + "0x1e":"mob_effect", + "0x1f":"update_attributes", + "0x20":"mob_equipment", + "0x21":"mob_armor_equipment", + "0x22":"interact", + "0x23":"use_item", + "0x24":"player_action", + "0x25":"player_fall", + "0x26":"hurt_armor", + "0x27":"set_entity_data", + "0x28":"set_entity_motion", + "0x29":"set_entity_link", + "0x2a":"set_health", + "0x2b":"set_spawn_position", + "0x2c":"animate", + "0x2d":"respawn", + "0x2e":"drop_item", + "0x2f":"inventory_action", + "0x30":"container_open", + "0x31":"container_close", + "0x32":"container_set_slot", + "0x33":"container_set_data", + "0x34":"container_set_content", + "0x35":"crafting_data", + "0x36":"crafting_event", + "0x37":"adventure_settings", + "0x38":"block_entity_data", + "0x39":"player_input", + "0x3a":"full_chunk_data", + "0x3b":"set_commands_enabled", + "0x3c":"set_difficulty", + "0x3d":"change_dimension", + "0x3e":"set_player_game_type", + "0x3f":"player_list", + "0x40":"event", + "0x41":"spawn_experience_orb", + "0x42":"clientbound_map_item_data_", + "0x43":"map_info_request", + "0x44":"request_chunk_radius", + "0x45":"chunk_radius_update", + "0x46":"item_fram_drop_item", + "0x47":"replace_selected_item", + "0x48":"game_rules_changed", + "0x49":"camera", + "0x4a":"add_item", + "0x4b":"boss_event", + "0x4d":"available_commands", + "0x4e":"command_step", + "0x4f":"resource_pack_data_info", + "0x50":"resource_pack_chunk_data", + "0x51":"resource_pack_chunk_request" + } + } + ] + }, + { + "name":"params", + "type":[ + "switch", + { + "compareTo":"name", + "fields":{ + "game_login":"packet_game_login", + "player_status":"packet_player_status", + "server_to_client_handshake":"packet_server_to_client_handshake", + "client_to_server_handshake":"packet_client_to_server_handshake", + "disconnect":"packet_disconnect", + "batch":"packet_batch", + "resource_packs_info":"packet_resource_packs_info", + "resource_pack_stack":"packet_resource_pack_stack", + "resource_pack_client_response":"packet_resource_pack_client_response", + "text":"packet_text", + "set_time":"packet_set_time", + "start_game":"packet_start_game", + "add_player":"packet_add_player", + "add_entity":"packet_add_entity", + "remove_entity":"packet_remove_entity", + "add_item_entity":"packet_add_item_entity", + "add_hanging_entity":"packet_add_hanging_entity", + "take_item_entity":"packet_take_item_entity", + "move_entity":"packet_move_entity", + "move_player":"packet_move_player", + "rider_jump":"packet_rider_jump", + "remove_block":"packet_remove_block", + "update_block":"packet_update_block", + "add_painting":"packet_add_painting", + "explode":"packet_explode", + "level_sound_event":"packet_level_sound_event", + "level_event":"packet_level_event", + "block_event":"packet_block_event", + "entity_event":"packet_entity_event", + "mob_effect":"packet_mob_effect", + "update_attributes":"packet_update_attributes", + "mob_equipment":"packet_mob_equipment", + "mob_armor_equipment":"packet_mob_armor_equipment", + "interact":"packet_interact", + "use_item":"packet_use_item", + "player_action":"packet_player_action", + "player_fall":"packet_player_fall", + "hurt_armor":"packet_hurt_armor", + "set_entity_data":"packet_set_entity_data", + "set_entity_motion":"packet_set_entity_motion", + "set_entity_link":"packet_set_entity_link", + "set_health":"packet_set_health", + "set_spawn_position":"packet_set_spawn_position", + "animate":"packet_animate", + "respawn":"packet_respawn", + "drop_item":"packet_drop_item", + "inventory_action":"packet_inventory_action", + "container_open":"packet_container_open", + "container_close":"packet_container_close", + "container_set_slot":"packet_container_set_slot", + "container_set_data":"packet_container_set_data", + "container_set_content":"packet_container_set_content", + "crafting_data":"packet_crafting_data", + "crafting_event":"packet_crafting_event", + "adventure_settings":"packet_adventure_settings", + "block_entity_data":"packet_block_entity_data", + "player_input":"packet_player_input", + "full_chunk_data":"packet_full_chunk_data", + "set_commands_enabled":"packet_set_commands_enabled", + "set_difficulty":"packet_set_difficulty", + "change_dimension":"packet_change_dimension", + "set_player_game_type":"packet_set_player_game_type", + "player_list":"packet_player_list", + "event":"packet_event", + "spawn_experience_orb":"packet_spawn_experience_orb", + "clientbound_map_item_data_":"packet_clientbound_map_item_data_", + "map_info_request":"packet_map_info_request", + "request_chunk_radius":"packet_request_chunk_radius", + "chunk_radius_update":"packet_chunk_radius_update", + "item_fram_drop_item":"packet_item_fram_drop_item", + "replace_selected_item":"packet_replace_selected_item", + "game_rules_changed":"packet_game_rules_changed", + "camera":"packet_camera", + "add_item":"packet_add_item", + "boss_event":"packet_boss_event", + "available_commands":"packet_available_commands", + "command_step":"packet_command_step", + "resource_pack_data_info":"packet_resource_pack_data_info", + "resource_pack_chunk_data":"packet_resource_pack_chunk_data", + "resource_pack_chunk_request":"packet_resource_pack_chunk_request" + } + } + ] + } + ] + ], + "packet_game_login":[ + "container", + [ + { + "name":"protocol", + "type":"i32" + }, + { + "name":"edition", + "type":"i8" + }, + { + "name":"body", + "type":[ + "buffer", + { + "countType":"varint" + } + ] + } + ] + ], + "packet_player_status":[ + "container", + [ + { + "name":"status", + "type":"i32" + } + ] + ], + "packet_server_to_client_handshake":[ + "container", + [ + { + "name":"server_public_key", + "type":"string" + }, + { + "name":"token", + "type":[ + "buffer", + { + "countType":"varint", + "type":"i8" + } + ] + } + ] + ], + "packet_client_to_server_handshake":[ + "container", + [ + + ] + ], + "packet_disconnect":[ + "container", + [ + { + "name":"hide_disconnection_screen", + "type":"bool" + }, + { + "name":"message", + "type":"string" + } + ] + ], + "packet_batch":[ + "container", + [ + { + "name":"payload", + "type":[ + "buffer", + { + "countType":"varint", + "type":"i8" + } + ] + } + ] + ], + "packet_resource_packs_info":[ + "container", + [ + { + "name":"must_accept", + "type":"bool" + }, + { + "name":"behavior_pack_entries", + "type":"pack_entries" + }, + { + "name":"resource_pack_entries", + "type":"pack_entries" + } + ] + ], + "packet_resource_pack_stack":[ + "container", + [ + { + "name":"must_accept", + "type":"bool" + }, + { + "name":"behavior_pack_versions", + "type":"pack_versions" + }, + { + "name":"resource_pack_versions", + "type":"pack_versions" + } + ] + ], + "packet_resource_pack_client_response":[ + "container", + [ + { + "name":"response_status", + "type":"u8" + }, + { + "name":"resourcepackidversions", + "type":"pack_versions" + } + ] + ], + "packet_text":[ + "container", + [ + { + "name":"type", + "type":"i8" + }, + { + "name":"source", + "type":[ + "switch", + { + "compareTo":"type", + "fields":{ + "1":"string" + }, + "default":"void" + } + ] + }, + { + "name":"message", + "type":[ + "switch", + { + "compareTo":"type", + "fields":{ + "0":"string", + "1":"string", + "2":"string", + "3":"string", + "4":"string" + }, + "default":"void" + } + ] + } + ] + ], + "packet_set_time":[ + "container", + [ + { + "name":"time", + "type":"varint" + }, + { + "name":"started", + "type":"bool" + } + ] + ], + "packet_start_game":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"runtime_entity_id", + "type":"varint" + }, + { + "name":"spawn", + "type":"vector3" + }, + { + "name":"unknown_1", + "type":"vector2" + }, + { + "name":"seed", + "type":"varint" + }, + { + "name":"dimension", + "type":"varint" + }, + { + "name":"generator", + "type":"varint" + }, + { + "name":"gamemode", + "type":"varint" + }, + { + "name":"difficulty", + "type":"varint" + }, + { + "name":"x", + "type":"varint" + }, + { + "name":"y", + "type":"varint" + }, + { + "name":"z", + "type":"varint" + }, + { + "name":"has_achievements_disabled", + "type":"bool" + }, + { + "name":"day_cycle_stop_time", + "type":"varint" + }, + { + "name":"edu_mode", + "type":"bool" + }, + { + "name":"rain_level", + "type":"lf32" + }, + { + "name":"lightnig_level", + "type":"lf32" + }, + { + "name":"enable_commands", + "type":"bool" + }, + { + "name":"is_texturepacks_required", + "type":"bool" + }, + { + "name":"secret", + "type":"string" + }, + { + "name":"world_name", + "type":"string" + } + ] + ], + "packet_add_player":[ + "container", + [ + { + "name":"uuid", + "type":"uuid" + }, + { + "name":"username", + "type":"string" + }, + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"runtime_entity_id", + "type":"varint" + }, + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + }, + { + "name":"speed_x", + "type":"lf32" + }, + { + "name":"speed_y", + "type":"lf32" + }, + { + "name":"speed_z", + "type":"lf32" + }, + { + "name":"pitch", + "type":"lf32" + }, + { + "name":"head_yaw", + "type":"lf32" + }, + { + "name":"yaw", + "type":"lf32" + }, + { + "name":"item", + "type":"slot" + }, + { + "name":"metadata", + "type":"metadatadictionary" + } + ] + ], + "packet_add_entity":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"runtime_entity_id", + "type":"varint" + }, + { + "name":"entity_type", + "type":"varint" + }, + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + }, + { + "name":"speed_x", + "type":"lf32" + }, + { + "name":"speed_y", + "type":"lf32" + }, + { + "name":"speed_z", + "type":"lf32" + }, + { + "name":"yaw", + "type":"lf32" + }, + { + "name":"pitch", + "type":"lf32" + }, + { + "name":"attributes", + "type":"entity_attributes" + }, + { + "name":"metadata", + "type":"metadatadictionary" + }, + { + "name":"links", + "type":"links" + } + ] + ], + "packet_remove_entity":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + } + ] + ], + "packet_add_item_entity":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"runtime_entity_id", + "type":"varint" + }, + { + "name":"item", + "type":"slot" + }, + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + }, + { + "name":"speed_x", + "type":"lf32" + }, + { + "name":"speed_y", + "type":"lf32" + }, + { + "name":"speed_z", + "type":"lf32" + } + ] + ], + "packet_add_hanging_entity":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"runtime_entity_id", + "type":"varint" + }, + { + "name":"coordinates", + "type":"blockcoordinates" + }, + { + "name":"unknown", + "type":"varint" + } + ] + ], + "packet_take_item_entity":[ + "container", + [ + { + "name":"target", + "type":"varint" + }, + { + "name":"entity_id", + "type":"varint" + } + ] + ], + "packet_move_entity":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"position", + "type":"playerlocation" + } + ] + ], + "packet_move_player":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + }, + { + "name":"pitch", + "type":"lf32" + }, + { + "name":"head_yaw", + "type":"lf32" + }, + { + "name":"yaw", + "type":"lf32" + }, + { + "name":"mode", + "type":"u8" + }, + { + "name":"on_ground", + "type":"bool" + } + ] + ], + "packet_rider_jump":[ + "container", + [ + + ] + ], + "packet_remove_block":[ + "container", + [ + { + "name":"coordinates", + "type":"blockcoordinates" + } + ] + ], + "packet_update_block":[ + "container", + [ + { + "name":"coordinates", + "type":"blockcoordinates" + }, + { + "name":"block_id", + "type":"varint" + }, + { + "name":"block_meta_and_priority", + "type":"varint" + } + ] + ], + "packet_add_painting":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"runtime_entity_id", + "type":"varint" + }, + { + "name":"coordinates", + "type":"blockcoordinates" + }, + { + "name":"direction", + "type":"varint" + }, + { + "name":"title", + "type":"string" + } + ] + ], + "packet_explode":[ + "container", + [ + { + "name":"position", + "type":"vector3" + }, + { + "name":"radius", + "type":"lf32" + }, + { + "name":"records", + "type":"records" + } + ] + ], + "packet_level_sound_event":[ + "container", + [ + { + "name":"sound_id", + "type":"u8" + }, + { + "name":"position", + "type":"vector3" + }, + { + "name":"volume", + "type":"varint" + }, + { + "name":"pitch", + "type":"varint" + }, + { + "name":"unknown1", + "type":"bool" + }, + { + "name":"unknown2", + "type":"bool" + } + ] + ], + "packet_level_event":[ + "container", + [ + { + "name":"event_id", + "type":"varint" + }, + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + }, + { + "name":"data", + "type":"varint" + } + ] + ], + "packet_block_event":[ + "container", + [ + { + "name":"coordinates", + "type":"blockcoordinates" + }, + { + "name":"case_1", + "type":"varint" + }, + { + "name":"case_2", + "type":"varint" + } + ] + ], + "packet_entity_event":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"event_id", + "type":"u8" + }, + { + "name":"unknown", + "type":"varint" + } + ] + ], + "packet_mob_effect":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"event_id", + "type":"u8" + }, + { + "name":"effect_id", + "type":"varint" + }, + { + "name":"amplifier", + "type":"varint" + }, + { + "name":"particles", + "type":"bool" + }, + { + "name":"duration", + "type":"varint" + } + ] + ], + "packet_update_attributes":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"attributes", + "type":"player_attributes" + } + ] + ], + "packet_mob_equipment":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"item", + "type":"varint" + }, + { + "name":"slot", + "type":"u8" + }, + { + "name":"selected_slot", + "type":"u8" + }, + { + "name":"unknown", + "type":"u8" + } + ] + ], + "packet_mob_armor_equipment":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"helmet", + "type":"slot" + }, + { + "name":"chestplate", + "type":"slot" + }, + { + "name":"leggings", + "type":"slot" + }, + { + "name":"boots", + "type":"slot" + } + ] + ], + "packet_interact":[ + "container", + [ + { + "name":"action_id", + "type":"u8" + }, + { + "name":"target_entity_id", + "type":"varint" + } + ] + ], + "packet_use_item":[ + "container", + [ + { + "name":"blockcoordinates", + "type":"blockcoordinates" + }, + { + "name":"unknown", + "type":"varint" + }, + { + "name":"face", + "type":"varint" + }, + { + "name":"facecoordinates", + "type":"vector3" + }, + { + "name":"playerposition", + "type":"vector3" + }, + { + "name":"slot", + "type":"varint" + }, + { + "name":"item", + "type":"slot" + } + ] + ], + "packet_player_action":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"action_id", + "type":"varint" + }, + { + "name":"coordinates", + "type":"blockcoordinates" + }, + { + "name":"face", + "type":"varint" + } + ] + ], + "packet_player_fall":[ + "container", + [ + + ] + ], + "packet_hurt_armor":[ + "container", + [ + { + "name":"health", + "type":"varint" + } + ] + ], + "packet_set_entity_data":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"metadata", + "type":"metadatadictionary" + } + ] + ], + "packet_set_entity_motion":[ + "container", + [ + { + "name":"entity_id", + "type":"varint" + }, + { + "name":"velocity", + "type":"vector3" + } + ] + ], + "packet_set_entity_link":[ + "container", + [ + { + "name":"rider_id", + "type":"varint" + }, + { + "name":"ridden_id", + "type":"varint" + }, + { + "name":"link_type", + "type":"u8" + } + ] + ], + "packet_set_health":[ + "container", + [ + { + "name":"health", + "type":"varint" + } + ] + ], + "packet_set_spawn_position":[ + "container", + [ + { + "name":"unknown_1", + "type":"varint" + }, + { + "name":"coordinates", + "type":"blockcoordinates" + } + ] + ], + "packet_animate":[ + "container", + [ + { + "name":"action_id", + "type":"varint" + }, + { + "name":"entity_id", + "type":"varint" + } + ] + ], + "packet_respawn":[ + "container", + [ + { + "name":"x", + "type":"lf32" + }, + { + "name":"y", + "type":"lf32" + }, + { + "name":"z", + "type":"lf32" + } + ] + ], + "packet_drop_item":[ + "container", + [ + { + "name":"itemtype", + "type":"u8" + }, + { + "name":"item", + "type":"slot" + } + ] + ], + "packet_inventory_action":[ + "container", + [ + { + "name":"unknown", + "type":"varint" + }, + { + "name":"item", + "type":"slot" + } + ] + ], + "packet_container_open":[ + "container", + [ + { + "name":"window_id", + "type":"u8" + }, + { + "name":"type", + "type":"u8" + }, + { + "name":"slot_count", + "type":"varint" + }, + { + "name":"coordinates", + "type":"blockcoordinates" + }, + { + "name":"unown_entity_id", + "type":"varint" + } + ] + ], + "packet_container_close":[ + "container", + [ + { + "name":"window_id", + "type":"u8" + } + ] + ], + "packet_container_set_slot":[ + "container", + [ + { + "name":"window_id", + "type":"u8" + }, + { + "name":"slot", + "type":"varint" + }, + { + "name":"hotbarslot", + "type":"varint" + }, + { + "name":"item", + "type":"slot" + }, + { + "name":"unknown2", + "type":"u8" + } + ] + ], + "packet_container_set_data":[ + "container", + [ + { + "name":"window_id", + "type":"u8" + }, + { + "name":"property", + "type":"varint" + }, + { + "name":"value", + "type":"varint" + } + ] + ], + "packet_container_set_content":[ + "container", + [ + { + "name":"windowId", + "type":"i8" + }, + { + "name":"slotData", + "type":"itemstacks" + }, + { + "name":"hotbarData", + "type":[ + "switch", + { + "compareTo":"windowId", + "fields":{ + "0":[ + "array", + { + "countType":"i16", + "type":[ + "container", + [ + { + "name":"slot", + "type":"i32" + } + ] + ] + } + ] + }, + "default":"i16" + } + ] + } + ] + ], + "packet_crafting_data":[ + "container", + [ + { + "name":"recipes", + "type":[ + "container", + [ + { + "name":"entryType", + "type":"i32" + }, + { + "name":"recipe", + "type":[ + "array", + { + "countType":"i32", + "type":[ + "switch", + { + "compareTo":"entryType", + "fields":{ + "0":"shapelessRecipe", + "1":"shapedRecipe", + "2":"furnaceRecipe", + "3":"furnaceRecipeData", + "4":"enchantList" + }, + "default":"void" + } + ] + } + ] + } + ] + ] + }, + { + "name":"cleanRecipes", + "type":"i8" + } + ] + ], + "packet_crafting_event":[ + "container", + [ + { + "name":"window_id", + "type":"u8" + }, + { + "name":"recipe_type", + "type":"varint" + }, + { + "name":"recipe_id", + "type":"uuid" + }, + { + "name":"input", + "type":"itemstacks" + }, + { + "name":"result", + "type":"itemstacks" + } + ] + ], + "packet_adventure_settings":[ + "container", + [ + { + "name":"flags", + "type":"varint" + }, + { + "name":"user_permission", + "type":"varint" + } + ] + ], + "packet_block_entity_data":[ + "container", + [ + { + "name":"coordinates", + "type":"blockcoordinates" + }, + { + "name":"nbtData", + "type":[ + "buffer", + { + "countType":"varint" + } + ] + } + ] + ], + "packet_player_input":[ + "container", + [ + { + "name":"motion_x", + "type":"lf32" + }, + { + "name":"motion_z", + "type":"lf32" + }, + { + "name":"flag1", + "type":"bool" + }, + { + "name":"flag2", + "type":"bool" + } + ] + ], + "packet_full_chunk_data":[ + "container", + [ + { + "name":"chunk_x", + "type":"varint" + }, + { + "name":"chunk_z", + "type":"varint" + }, + { + "name":"chunk_data", + "type":[ + "buffer", + { + "countType":"varint", + "type":"i8" + } + ] + } + ] + ], + "packet_set_commands_enabled":[ + "container", + [ + { + "name":"enabled", + "type":"bool" + } + ] + ], + "packet_set_difficulty":[ + "container", + [ + { + "name":"difficulty", + "type":"varint" + } + ] + ], + "packet_change_dimension":[ + "container", + [ + { + "name":"dimension", + "type":"varint" + }, + { + "name":"position", + "type":"vector3" + }, + { + "name":"unknown", + "type":"bool" + } + ] + ], + "packet_set_player_game_type":[ + "container", + [ + { + "name":"unknown", + "type":"varint" + } + ] + ], + "packet_player_list":[ + "container", + [ + { + "name":"type", + "type":"i8" + }, + { + "name":"entries", + "type":[ + "array", + { + "countType":"i32", + "type":[ + "switch", + { + "compareTo":"type", + "fields":{ + "0":[ + "container", + [ + { + "name":"clientUuid", + "type":"uuid" + }, + { + "name":"entityId", + "type":"i64" + }, + { + "name":"displayName", + "type":"string" + }, + { + "name":"skin", + "type":"skin" + } + ] + ], + "1":[ + "container", + [ + { + "name":"clientUuid", + "type":"uuid" + } + ] + ] + } + } + ] + } + ] + } + ] + ], + "packet_event":[ + "container", + [ + + ] + ], + "packet_spawn_experience_orb":[ + "container", + [ + { + "name":"position", + "type":"vector3" + }, + { + "name":"count", + "type":"varint" + } + ] + ], + "packet_request_chunk_radius":[ + "container", + [ + { + "name":"chunk_radius", + "type":"varint" + } + ] + ], + "packet_chunk_radius_update":[ + "container", + [ + { + "name":"chunk_radius", + "type":"varint" + } + ] + ], + "packet_item_frame_drop_item":[ + "container", + [ + { + "name":"coordinates", + "type":"blockcoordinatesk" + }, + { + "name":"item", + "type":"slot" + } + ] + ], + "packet_replace_selected_item":[ + "container", + [ + + ] + ], + "packet_game_rules_changed":[ + "container", + [ + { + "name":"rules", + "type":"rules" + } + ] + ], + "packet_camera":[ + "container", + [ + + ] + ], + "packet_add_item":[ + "container", + [ + + ] + ], + "packet_boss_event":[ + "container", + [ + + ] + ], + "packet_available_commands":[ + "container", + [ + { + "name":"commands", + "type":"string" + }, + { + "name":"unknown", + "type":"string" + } + ] + ], + "packet_command_step":[ + "container", + [ + { + "name":"command_name", + "type":"string" + }, + { + "name":"command_overload", + "type":"string" + }, + { + "name":"unknown_1", + "type":"varint" + }, + { + "name":"unknown_2", + "type":"varint" + }, + { + "name":"is_output", + "type":"bool" + }, + { + "name":"unknown_5", + "type":"varint" + }, + { + "name":"command_input_json", + "type":"string" + }, + { + "name":"command_output_json", + "type":"string" + }, + { + "name":"unknown_7", + "type":"u8" + }, + { + "name":"unknown_8", + "type":"u8" + }, + { + "name":"entity_id", + "type":"varint" + } + ] + ], + "packet_resource_pack_data_info":[ + "container", + [ + { + "name":"package_id", + "type":"string" + }, + { + "name":"unknown1", + "type":"u32" + }, + { + "name":"unknown2", + "type":"u32" + }, + { + "name":"unknown3", + "type":"u64" + }, + { + "name":"unknown4", + "type":"string" + } + ] + ], + "packet_resource_pack_chunk_data":[ + "container", + [ + { + "name":"package_id", + "type":"string" + }, + { + "name":"unknown1", + "type":"u32" + }, + { + "name":"unknown3", + "type":"u64" + }, + { + "name":"length", + "type":"u32" + }, + { + "name":"payload", + "type":[ + "buffer", + { + "countType":"varint", + "type":"i8" + } + ] + } + ] + ], + "packet_resource_pack_chunk_request":[ + "container", + [ + { + "name":"package_id", + "type":"string" + }, + { + "name":"chunk_index", + "type":"i32" + } + ] + ] + } +} \ No newline at end of file From 166960e2571f124c83616165591e85092b8b7703 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Sun, 22 Jan 2017 13:41:45 -0500 Subject: [PATCH 065/458] skin --- data/protocol.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/data/protocol.json b/data/protocol.json index 5f72188..5eaf9fc 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -12,6 +12,19 @@ "countType":"li16" } ], + "skin": [ + "container", + [ + { + "name": "skin_type", + "type": "string" + }, + { + "name": "texture", + "type": ["buffer",{"countType":"i16"}] + } + ] + ], "rules":[ "array", { From a244ed62dfdcff242001e5858a3e3a2f487323c5 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Sun, 22 Jan 2017 13:44:21 -0500 Subject: [PATCH 066/458] skin data --- src/createServer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/createServer.js b/src/createServer.js index afb0845..65c0a37 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -127,7 +127,6 @@ function createServer(options, encryption) { decode = jwt.decode(chain, PUBLIC_KEY, 'ES384'); data = jwt.decode(body.data.clientData, decode.identityPublicKey, 'ES384'); - data.SkinData = null; client.emit('mcpe_login', { protocol: packet.protocol, uuid: (decode.extraData != null) ? decode.extraData.identity : null, From d61ddd7d20e71b3485f23f0a83e30488119e027b Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Sun, 22 Jan 2017 13:59:07 -0500 Subject: [PATCH 067/458] oops --- data/protocol.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 5eaf9fc..c8702c7 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -208,15 +208,15 @@ [ { "name":"x", - "type":"i32" + "type":"varint" }, { "name":"y", - "type":"i32" + "type":"varint" }, { "name":"z", - "type":"i32" + "type":"varint" } ] ], From acafc8df1bf8a7f5f72411eb1b81f92999c6ba86 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Sat, 15 Apr 2017 07:46:55 -0400 Subject: [PATCH 068/458] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ed407ea..45885e7 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ -pocket-minecraft-protocol +pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/mhsjlw/pocket-minecraft-protocol](https://badges.gitter.im/mhsjlw/pocket-minecraft-protocol.svg)](https://gitter.im/mhsjlw/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ========================= -[![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) -[![Join the chat at https://gitter.im/mhsjlw/pocket-minecraft-protocol](https://badges.gitter.im/mhsjlw/pocket-minecraft-protocol.svg)](https://gitter.im/mhsjlw/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +> Note: If you're looking for experimental encryption or 1.0.\* support, please see the [1.0](https://github.com/mhsjlw/pocket-minecraft-protocol/tree/1.0) branch -Parse and serialize Minecraft PE packets. +Parse and serialize Minecraft: Pocket Edition packets ## Features @@ -16,7 +15,7 @@ Parse and serialize Minecraft PE packets. ## Installation Simply run - npm install pocket-minecraft-protcol + npm install pocket-minecraft-protocol Then view our `examples` for inspiration! From 7c17673f3f6497d15624981c4ff4d8d6f7709ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 18 Jun 2017 17:54:02 +0200 Subject: [PATCH 069/458] TODO --- data/protocol.json | 4248 ++++++++++++++++++++------------------------ 1 file changed, 1948 insertions(+), 2300 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index c8702c7..a0c118d 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -1,2320 +1,1968 @@ { - "types":{ - "string":[ - "pstring", - { - "countType":"varint" - } - ], - "lstring":[ - "pstring", - { - "countType":"li16" - } - ], - "skin": [ - "container", - [ - { - "name": "skin_type", - "type": "string" - }, - { - "name": "texture", - "type": ["buffer",{"countType":"i16"}] - } - ] - ], - "rules":[ - "array", - { - "countType":"varint", - "type":[ - "container", - [ + "types": { + "string": [ + "pstring", { - "name":"name", - "type":"string" - }, - { - "name":"unknown1", - "type":"bool" - }, - { - "name":"unknown2", - "type":"bool" + "countType": "i16" } - ] - ] - } - ], - "shapeless_recipe":[ - "container", - [ - { - "name":"ingredientList", - "type":[ - "array", + ], + "lstring": [ + "pstring", { - "countType":"i32", - "type":"slot" + "countType": "li16" } - ] - }, - { - "name":"resultCount", - "type":"i32" - }, - { - "name":"slot", - "type":"slot" - }, - { - "name":"id", - "type":"uuid" - } - ] - ], - "shaped_recipe":[ - "container", - [ - { - "name":"width", - "type":[ - "count", - { - "type":"i32", - "countFor":"shape" - } - ] - }, - { - "name":"height", - "type":[ - "count", - { - "type":"i32", - "countFor":"shape/0" - } - ] - }, - { - "name":"shape", - "type":[ - "array", - { - "count":"width", - "type":[ - "array", - { - "count":"height", - "type":"slot" - } - ] - } - ] - }, - { - "name":"resultCount", - "type":"i32" - }, - { - "name":"slot", - "type":"slot" - }, - { - "name":"id", - "type":"uuid" - } - ] - ], - "furnace_recipe":[ - "container", - [ - { - "name":"meta", - "type":"i16" - }, - { - "name":"id", - "type":"i16" - }, - { - "name":"result", - "type":"slot" - } - ] - ], - "furnace_recipe_data":[ - "container", - [ - { - "name":"id", - "type":"i16" - }, - { - "name":"meta", - "type":"i16" - }, - { - "name":"result", - "type":"slot" - } - ] - ], - "enchant_list":[ - "array", - { - "countType":"i8", - "type":[ - "container", - [ - { - "name":"cost", - "type":"i32" - }, - { - "name":"enchantments", - "type":[ - "array", - { - "countType":"i8", - "type":[ - "container", - [ - { - "name":"id", - "type":"i32" - }, - { - "name":"level", - "type":"i32" - } - ] - ] - } - ] - }, - { - "name":"name", - "type":"string" - } - ] - ] - } - ], - "blockcoordinates":[ - "container", - [ - { - "name":"x", - "type":"varint" - }, - { - "name":"y", - "type":"varint" - }, - { - "name":"z", - "type":"varint" - } - ] - ], - "records":[ - "array", - { - "countType":"varint", - "type":[ - "container", - [ - { - "name":"record", - "type":"blockcoordinates" - } - ] - ] - } - ], - "itemstacks":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"slot", - "type":"slot" - } - ] - ] - } - ], - "links":[ - "array", - { - "countType":"varint", - "type":[ - "container", - [ - { - "name":"item_1", - "type":"varint" - }, - { - "name":"item_2", - "type":"varint" - }, - { - "name":"unknown", - "type":"li16" - } - ] - ] - } - ], - "player_attributes":[ - "array", - { - "countType":"varint", - "type":[ - "container", - [ - { - "name":"min_value", - "type":"f32" - }, - { - "name":"max_value", - "type":"f32" - }, - { - "name":"value", - "type":"f32" - }, - { - "name":"unknown", - "type":"f32" - }, - { - "name":"name", - "type":"string" - } - ] - ] - } - ], - "entity_attributes":[ - "array", - { - "countType":"varint", - "type":[ - "container", - [ - { - "name":"name", - "type":"string" - }, - { - "name":"min_value", - "type":"f32" - }, - { - "name":"value", - "type":"f32" - }, - { - "name":"max_value", - "type":"f32" - } - ] - ] - } - ], - "pack_entries":[ - "array", - { - "countType":"li16", - "type":[ - "container", - [ - { - "name":"pack_id", - "type":"string" - }, - { - "name":"version", - "type":"string" - }, - { - "name":"pack_size", - "type":"u64" - } - ] - ] - } - ], - "pack_versions":[ - "array", - { - "countType":"li16", - "type":[ - "container", - [ - { - "name":"pack_id", - "type":"string" - }, - { - "name":"version", - "type":"string" - } - ] - ] - } - ], - "vector3":[ - "container", - [ - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - } - ] - ], - "metadataints":[ - "array", - { - "countType":"varint", - "type":[ - "container", - [ - { - - } - ] - ] - } - ], - "vector2":[ - "container", - [ - { - "name":"x", - "type":"f32" - }, - { - "name":"y", - "type":"f32" - } - ] - ], - "metadatadictionary":[ - "entityMetadataLoop", - { - "endVal":127, - "type":[ - "container", - [ - { - "anon":true, - "type":[ - "bitfield", - [ - { - "name":"type", - "size":3, - "signed":false - }, - { - "name":"key", - "size":5, - "signed":false - } - ] - ] - }, - { - "name":"value", - "type":[ - "entityMetadataItem", - { - "compareTo":"type" - } - ] - } - ] - ] - } - ], - "slot":[ - "container", - [ - { - "name":"blockId", - "type":"i16" - }, - { - "anon":true, - "type":[ - "switch", - { - "compareTo":"blockId", - "fields":{ - "0":"void" - }, - "default":[ - "container", - [ - { - "name":"itemCount", - "type":"i8" - }, - { - "name":"itemDamage", - "type":"i16" - }, - { - "name":"nbtData", - "type":[ - "buffer", - { - "countType":"li16" - } - ] - } - ] - ] - } - ] - } - ] - ], - "playerlocation":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - }, - { - "name":"yaw", - "type":"f32" - }, - { - "name":"pitch", - "type":"f32" - }, - { - "name":"headYaw", - "type":"f32" - } - ] - ] - } - ], - "encapsulated_packet":[ - "container", - [ - { - "name":"name", - "type":[ - "mapper", - { - "type":"u8", - "mappings":{ - "0xfe":"mcpe" - } - } - ] - }, - { - "name":"params", - "type":[ - "switch", - { - "compareTo":"name", - "fields":{ - "mcpe":"mcpe_packet" - } - } - ] - } - ] - ], - "mcpe_packet":[ - "container", - [ - { - "name":"name", - "type":[ - "mapper", - { - "type":"u8", - "mappings":{ - "0x01":"game_login", - "0x02":"player_status", - "0x03":"server_to_client_handshake", - "0x04":"client_to_server_handshake", - "0x05":"disconnect", - "0x06":"batch", - "0x07":"resource_packs_info", - "0x08":"resource_pack_stack", - "0x09":"resource_pack_client_response", - "0x0a":"text", - "0x0b":"set_time", - "0x0c":"start_game", - "0x0d":"add_player", - "0x0e":"add_entity", - "0x0f":"remove_entity", - "0x10":"add_item_entity", - "0x11":"add_hanging_entity", - "0x12":"take_item_entity", - "0x13":"move_entity", - "0x14":"move_player", - "0x15":"rider_jump", - "0x16":"remove_block", - "0x17":"update_block", - "0x18":"add_painting", - "0x19":"explode", - "0x1a":"level_sound_event", - "0x1b":"level_event", - "0x1c":"block_event", - "0x1d":"entity_event", - "0x1e":"mob_effect", - "0x1f":"update_attributes", - "0x20":"mob_equipment", - "0x21":"mob_armor_equipment", - "0x22":"interact", - "0x23":"use_item", - "0x24":"player_action", - "0x25":"player_fall", - "0x26":"hurt_armor", - "0x27":"set_entity_data", - "0x28":"set_entity_motion", - "0x29":"set_entity_link", - "0x2a":"set_health", - "0x2b":"set_spawn_position", - "0x2c":"animate", - "0x2d":"respawn", - "0x2e":"drop_item", - "0x2f":"inventory_action", - "0x30":"container_open", - "0x31":"container_close", - "0x32":"container_set_slot", - "0x33":"container_set_data", - "0x34":"container_set_content", - "0x35":"crafting_data", - "0x36":"crafting_event", - "0x37":"adventure_settings", - "0x38":"block_entity_data", - "0x39":"player_input", - "0x3a":"full_chunk_data", - "0x3b":"set_commands_enabled", - "0x3c":"set_difficulty", - "0x3d":"change_dimension", - "0x3e":"set_player_game_type", - "0x3f":"player_list", - "0x40":"event", - "0x41":"spawn_experience_orb", - "0x42":"clientbound_map_item_data_", - "0x43":"map_info_request", - "0x44":"request_chunk_radius", - "0x45":"chunk_radius_update", - "0x46":"item_fram_drop_item", - "0x47":"replace_selected_item", - "0x48":"game_rules_changed", - "0x49":"camera", - "0x4a":"add_item", - "0x4b":"boss_event", - "0x4d":"available_commands", - "0x4e":"command_step", - "0x4f":"resource_pack_data_info", - "0x50":"resource_pack_chunk_data", - "0x51":"resource_pack_chunk_request" - } - } - ] - }, - { - "name":"params", - "type":[ - "switch", - { - "compareTo":"name", - "fields":{ - "game_login":"packet_game_login", - "player_status":"packet_player_status", - "server_to_client_handshake":"packet_server_to_client_handshake", - "client_to_server_handshake":"packet_client_to_server_handshake", - "disconnect":"packet_disconnect", - "batch":"packet_batch", - "resource_packs_info":"packet_resource_packs_info", - "resource_pack_stack":"packet_resource_pack_stack", - "resource_pack_client_response":"packet_resource_pack_client_response", - "text":"packet_text", - "set_time":"packet_set_time", - "start_game":"packet_start_game", - "add_player":"packet_add_player", - "add_entity":"packet_add_entity", - "remove_entity":"packet_remove_entity", - "add_item_entity":"packet_add_item_entity", - "add_hanging_entity":"packet_add_hanging_entity", - "take_item_entity":"packet_take_item_entity", - "move_entity":"packet_move_entity", - "move_player":"packet_move_player", - "rider_jump":"packet_rider_jump", - "remove_block":"packet_remove_block", - "update_block":"packet_update_block", - "add_painting":"packet_add_painting", - "explode":"packet_explode", - "level_sound_event":"packet_level_sound_event", - "level_event":"packet_level_event", - "block_event":"packet_block_event", - "entity_event":"packet_entity_event", - "mob_effect":"packet_mob_effect", - "update_attributes":"packet_update_attributes", - "mob_equipment":"packet_mob_equipment", - "mob_armor_equipment":"packet_mob_armor_equipment", - "interact":"packet_interact", - "use_item":"packet_use_item", - "player_action":"packet_player_action", - "player_fall":"packet_player_fall", - "hurt_armor":"packet_hurt_armor", - "set_entity_data":"packet_set_entity_data", - "set_entity_motion":"packet_set_entity_motion", - "set_entity_link":"packet_set_entity_link", - "set_health":"packet_set_health", - "set_spawn_position":"packet_set_spawn_position", - "animate":"packet_animate", - "respawn":"packet_respawn", - "drop_item":"packet_drop_item", - "inventory_action":"packet_inventory_action", - "container_open":"packet_container_open", - "container_close":"packet_container_close", - "container_set_slot":"packet_container_set_slot", - "container_set_data":"packet_container_set_data", - "container_set_content":"packet_container_set_content", - "crafting_data":"packet_crafting_data", - "crafting_event":"packet_crafting_event", - "adventure_settings":"packet_adventure_settings", - "block_entity_data":"packet_block_entity_data", - "player_input":"packet_player_input", - "full_chunk_data":"packet_full_chunk_data", - "set_commands_enabled":"packet_set_commands_enabled", - "set_difficulty":"packet_set_difficulty", - "change_dimension":"packet_change_dimension", - "set_player_game_type":"packet_set_player_game_type", - "player_list":"packet_player_list", - "event":"packet_event", - "spawn_experience_orb":"packet_spawn_experience_orb", - "clientbound_map_item_data_":"packet_clientbound_map_item_data_", - "map_info_request":"packet_map_info_request", - "request_chunk_radius":"packet_request_chunk_radius", - "chunk_radius_update":"packet_chunk_radius_update", - "item_fram_drop_item":"packet_item_fram_drop_item", - "replace_selected_item":"packet_replace_selected_item", - "game_rules_changed":"packet_game_rules_changed", - "camera":"packet_camera", - "add_item":"packet_add_item", - "boss_event":"packet_boss_event", - "available_commands":"packet_available_commands", - "command_step":"packet_command_step", - "resource_pack_data_info":"packet_resource_pack_data_info", - "resource_pack_chunk_data":"packet_resource_pack_chunk_data", - "resource_pack_chunk_request":"packet_resource_pack_chunk_request" - } - } - ] - } - ] - ], - "packet_game_login":[ - "container", - [ - { - "name":"protocol", - "type":"i32" - }, - { - "name":"edition", - "type":"i8" - }, - { - "name":"body", - "type":[ - "buffer", - { - "countType":"varint" - } - ] - } - ] - ], - "packet_player_status":[ - "container", - [ - { - "name":"status", - "type":"i32" - } - ] - ], - "packet_server_to_client_handshake":[ - "container", - [ - { - "name":"server_public_key", - "type":"string" - }, - { - "name":"token", - "type":[ - "buffer", - { - "countType":"varint", - "type":"i8" - } - ] - } - ] - ], - "packet_client_to_server_handshake":[ - "container", - [ - - ] - ], - "packet_disconnect":[ - "container", - [ - { - "name":"hide_disconnection_screen", - "type":"bool" - }, - { - "name":"message", - "type":"string" - } - ] - ], - "packet_batch":[ - "container", - [ - { - "name":"payload", - "type":[ - "buffer", - { - "countType":"varint", - "type":"i8" - } - ] - } - ] - ], - "packet_resource_packs_info":[ - "container", - [ - { - "name":"must_accept", - "type":"bool" - }, - { - "name":"behavior_pack_entries", - "type":"pack_entries" - }, - { - "name":"resource_pack_entries", - "type":"pack_entries" - } - ] - ], - "packet_resource_pack_stack":[ - "container", - [ - { - "name":"must_accept", - "type":"bool" - }, - { - "name":"behavior_pack_versions", - "type":"pack_versions" - }, - { - "name":"resource_pack_versions", - "type":"pack_versions" - } - ] - ], - "packet_resource_pack_client_response":[ - "container", - [ - { - "name":"response_status", - "type":"u8" - }, - { - "name":"resourcepackidversions", - "type":"pack_versions" - } - ] - ], - "packet_text":[ - "container", - [ - { - "name":"type", - "type":"i8" - }, - { - "name":"source", - "type":[ - "switch", - { - "compareTo":"type", - "fields":{ - "1":"string" - }, - "default":"void" - } - ] - }, - { - "name":"message", - "type":[ - "switch", - { - "compareTo":"type", - "fields":{ - "0":"string", - "1":"string", - "2":"string", - "3":"string", - "4":"string" - }, - "default":"void" - } - ] - } - ] - ], - "packet_set_time":[ - "container", - [ - { - "name":"time", - "type":"varint" - }, - { - "name":"started", - "type":"bool" - } - ] - ], - "packet_start_game":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"runtime_entity_id", - "type":"varint" - }, - { - "name":"spawn", - "type":"vector3" - }, - { - "name":"unknown_1", - "type":"vector2" - }, - { - "name":"seed", - "type":"varint" - }, - { - "name":"dimension", - "type":"varint" - }, - { - "name":"generator", - "type":"varint" - }, - { - "name":"gamemode", - "type":"varint" - }, - { - "name":"difficulty", - "type":"varint" - }, - { - "name":"x", - "type":"varint" - }, - { - "name":"y", - "type":"varint" - }, - { - "name":"z", - "type":"varint" - }, - { - "name":"has_achievements_disabled", - "type":"bool" - }, - { - "name":"day_cycle_stop_time", - "type":"varint" - }, - { - "name":"edu_mode", - "type":"bool" - }, - { - "name":"rain_level", - "type":"lf32" - }, - { - "name":"lightnig_level", - "type":"lf32" - }, - { - "name":"enable_commands", - "type":"bool" - }, - { - "name":"is_texturepacks_required", - "type":"bool" - }, - { - "name":"secret", - "type":"string" - }, - { - "name":"world_name", - "type":"string" - } - ] - ], - "packet_add_player":[ - "container", - [ - { - "name":"uuid", - "type":"uuid" - }, - { - "name":"username", - "type":"string" - }, - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"runtime_entity_id", - "type":"varint" - }, - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - }, - { - "name":"speed_x", - "type":"lf32" - }, - { - "name":"speed_y", - "type":"lf32" - }, - { - "name":"speed_z", - "type":"lf32" - }, - { - "name":"pitch", - "type":"lf32" - }, - { - "name":"head_yaw", - "type":"lf32" - }, - { - "name":"yaw", - "type":"lf32" - }, - { - "name":"item", - "type":"slot" - }, - { - "name":"metadata", - "type":"metadatadictionary" - } - ] - ], - "packet_add_entity":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"runtime_entity_id", - "type":"varint" - }, - { - "name":"entity_type", - "type":"varint" - }, - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - }, - { - "name":"speed_x", - "type":"lf32" - }, - { - "name":"speed_y", - "type":"lf32" - }, - { - "name":"speed_z", - "type":"lf32" - }, - { - "name":"yaw", - "type":"lf32" - }, - { - "name":"pitch", - "type":"lf32" - }, - { - "name":"attributes", - "type":"entity_attributes" - }, - { - "name":"metadata", - "type":"metadatadictionary" - }, - { - "name":"links", - "type":"links" - } - ] - ], - "packet_remove_entity":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - } - ] - ], - "packet_add_item_entity":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"runtime_entity_id", - "type":"varint" - }, - { - "name":"item", - "type":"slot" - }, - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - }, - { - "name":"speed_x", - "type":"lf32" - }, - { - "name":"speed_y", - "type":"lf32" - }, - { - "name":"speed_z", - "type":"lf32" - } - ] - ], - "packet_add_hanging_entity":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"runtime_entity_id", - "type":"varint" - }, - { - "name":"coordinates", - "type":"blockcoordinates" - }, - { - "name":"unknown", - "type":"varint" - } - ] - ], - "packet_take_item_entity":[ - "container", - [ - { - "name":"target", - "type":"varint" - }, - { - "name":"entity_id", - "type":"varint" - } - ] - ], - "packet_move_entity":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"position", - "type":"playerlocation" - } - ] - ], - "packet_move_player":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - }, - { - "name":"pitch", - "type":"lf32" - }, - { - "name":"head_yaw", - "type":"lf32" - }, - { - "name":"yaw", - "type":"lf32" - }, - { - "name":"mode", - "type":"u8" - }, - { - "name":"on_ground", - "type":"bool" - } - ] - ], - "packet_rider_jump":[ - "container", - [ - - ] - ], - "packet_remove_block":[ - "container", - [ - { - "name":"coordinates", - "type":"blockcoordinates" - } - ] - ], - "packet_update_block":[ - "container", - [ - { - "name":"coordinates", - "type":"blockcoordinates" - }, - { - "name":"block_id", - "type":"varint" - }, - { - "name":"block_meta_and_priority", - "type":"varint" - } - ] - ], - "packet_add_painting":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"runtime_entity_id", - "type":"varint" - }, - { - "name":"coordinates", - "type":"blockcoordinates" - }, - { - "name":"direction", - "type":"varint" - }, - { - "name":"title", - "type":"string" - } - ] - ], - "packet_explode":[ - "container", - [ - { - "name":"position", - "type":"vector3" - }, - { - "name":"radius", - "type":"lf32" - }, - { - "name":"records", - "type":"records" - } - ] - ], - "packet_level_sound_event":[ - "container", - [ - { - "name":"sound_id", - "type":"u8" - }, - { - "name":"position", - "type":"vector3" - }, - { - "name":"volume", - "type":"varint" - }, - { - "name":"pitch", - "type":"varint" - }, - { - "name":"unknown1", - "type":"bool" - }, - { - "name":"unknown2", - "type":"bool" - } - ] - ], - "packet_level_event":[ - "container", - [ - { - "name":"event_id", - "type":"varint" - }, - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - }, - { - "name":"data", - "type":"varint" - } - ] - ], - "packet_block_event":[ - "container", - [ - { - "name":"coordinates", - "type":"blockcoordinates" - }, - { - "name":"case_1", - "type":"varint" - }, - { - "name":"case_2", - "type":"varint" - } - ] - ], - "packet_entity_event":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"event_id", - "type":"u8" - }, - { - "name":"unknown", - "type":"varint" - } - ] - ], - "packet_mob_effect":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"event_id", - "type":"u8" - }, - { - "name":"effect_id", - "type":"varint" - }, - { - "name":"amplifier", - "type":"varint" - }, - { - "name":"particles", - "type":"bool" - }, - { - "name":"duration", - "type":"varint" - } - ] - ], - "packet_update_attributes":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"attributes", - "type":"player_attributes" - } - ] - ], - "packet_mob_equipment":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"item", - "type":"varint" - }, - { - "name":"slot", - "type":"u8" - }, - { - "name":"selected_slot", - "type":"u8" - }, - { - "name":"unknown", - "type":"u8" - } - ] - ], - "packet_mob_armor_equipment":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"helmet", - "type":"slot" - }, - { - "name":"chestplate", - "type":"slot" - }, - { - "name":"leggings", - "type":"slot" - }, - { - "name":"boots", - "type":"slot" - } - ] - ], - "packet_interact":[ - "container", - [ - { - "name":"action_id", - "type":"u8" - }, - { - "name":"target_entity_id", - "type":"varint" - } - ] - ], - "packet_use_item":[ - "container", - [ - { - "name":"blockcoordinates", - "type":"blockcoordinates" - }, - { - "name":"unknown", - "type":"varint" - }, - { - "name":"face", - "type":"varint" - }, - { - "name":"facecoordinates", - "type":"vector3" - }, - { - "name":"playerposition", - "type":"vector3" - }, - { - "name":"slot", - "type":"varint" - }, - { - "name":"item", - "type":"slot" - } - ] - ], - "packet_player_action":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"action_id", - "type":"varint" - }, - { - "name":"coordinates", - "type":"blockcoordinates" - }, - { - "name":"face", - "type":"varint" - } - ] - ], - "packet_player_fall":[ - "container", - [ - - ] - ], - "packet_hurt_armor":[ - "container", - [ - { - "name":"health", - "type":"varint" - } - ] - ], - "packet_set_entity_data":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"metadata", - "type":"metadatadictionary" - } - ] - ], - "packet_set_entity_motion":[ - "container", - [ - { - "name":"entity_id", - "type":"varint" - }, - { - "name":"velocity", - "type":"vector3" - } - ] - ], - "packet_set_entity_link":[ - "container", - [ - { - "name":"rider_id", - "type":"varint" - }, - { - "name":"ridden_id", - "type":"varint" - }, - { - "name":"link_type", - "type":"u8" - } - ] - ], - "packet_set_health":[ - "container", - [ - { - "name":"health", - "type":"varint" - } - ] - ], - "packet_set_spawn_position":[ - "container", - [ - { - "name":"unknown_1", - "type":"varint" - }, - { - "name":"coordinates", - "type":"blockcoordinates" - } - ] - ], - "packet_animate":[ - "container", - [ - { - "name":"action_id", - "type":"varint" - }, - { - "name":"entity_id", - "type":"varint" - } - ] - ], - "packet_respawn":[ - "container", - [ - { - "name":"x", - "type":"lf32" - }, - { - "name":"y", - "type":"lf32" - }, - { - "name":"z", - "type":"lf32" - } - ] - ], - "packet_drop_item":[ - "container", - [ - { - "name":"itemtype", - "type":"u8" - }, - { - "name":"item", - "type":"slot" - } - ] - ], - "packet_inventory_action":[ - "container", - [ - { - "name":"unknown", - "type":"varint" - }, - { - "name":"item", - "type":"slot" - } - ] - ], - "packet_container_open":[ - "container", - [ - { - "name":"window_id", - "type":"u8" - }, - { - "name":"type", - "type":"u8" - }, - { - "name":"slot_count", - "type":"varint" - }, - { - "name":"coordinates", - "type":"blockcoordinates" - }, - { - "name":"unown_entity_id", - "type":"varint" - } - ] - ], - "packet_container_close":[ - "container", - [ - { - "name":"window_id", - "type":"u8" - } - ] - ], - "packet_container_set_slot":[ - "container", - [ - { - "name":"window_id", - "type":"u8" - }, - { - "name":"slot", - "type":"varint" - }, - { - "name":"hotbarslot", - "type":"varint" - }, - { - "name":"item", - "type":"slot" - }, - { - "name":"unknown2", - "type":"u8" - } - ] - ], - "packet_container_set_data":[ - "container", - [ - { - "name":"window_id", - "type":"u8" - }, - { - "name":"property", - "type":"varint" - }, - { - "name":"value", - "type":"varint" - } - ] - ], - "packet_container_set_content":[ - "container", - [ - { - "name":"windowId", - "type":"i8" - }, - { - "name":"slotData", - "type":"itemstacks" - }, - { - "name":"hotbarData", - "type":[ - "switch", - { - "compareTo":"windowId", - "fields":{ - "0":[ - "array", - { - "countType":"i16", - "type":[ - "container", - [ - { - "name":"slot", - "type":"i32" - } - ] - ] - } - ] - }, - "default":"i16" - } - ] - } - ] - ], - "packet_crafting_data":[ - "container", - [ - { - "name":"recipes", - "type":[ + ], + "vector3": [ "container", [ - { - "name":"entryType", - "type":"i32" - }, - { - "name":"recipe", - "type":[ - "array", - { - "countType":"i32", - "type":[ - "switch", - { - "compareTo":"entryType", - "fields":{ - "0":"shapelessRecipe", - "1":"shapedRecipe", - "2":"furnaceRecipe", - "3":"furnaceRecipeData", - "4":"enchantList" - }, - "default":"void" - } - ] - } - ] - } + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } ] - ] - }, - { - "name":"cleanRecipes", - "type":"i8" - } - ] - ], - "packet_crafting_event":[ - "container", - [ - { - "name":"window_id", - "type":"u8" - }, - { - "name":"recipe_type", - "type":"varint" - }, - { - "name":"recipe_id", - "type":"uuid" - }, - { - "name":"input", - "type":"itemstacks" - }, - { - "name":"result", - "type":"itemstacks" - } - ] - ], - "packet_adventure_settings":[ - "container", - [ - { - "name":"flags", - "type":"varint" - }, - { - "name":"user_permission", - "type":"varint" - } - ] - ], - "packet_block_entity_data":[ - "container", - [ - { - "name":"coordinates", - "type":"blockcoordinates" - }, - { - "name":"nbtData", - "type":[ - "buffer", - { - "countType":"varint" - } - ] - } - ] - ], - "packet_player_input":[ - "container", - [ - { - "name":"motion_x", - "type":"lf32" - }, - { - "name":"motion_z", - "type":"lf32" - }, - { - "name":"flag1", - "type":"bool" - }, - { - "name":"flag2", - "type":"bool" - } - ] - ], - "packet_full_chunk_data":[ - "container", - [ - { - "name":"chunk_x", - "type":"varint" - }, - { - "name":"chunk_z", - "type":"varint" - }, - { - "name":"chunk_data", - "type":[ - "buffer", - { - "countType":"varint", - "type":"i8" - } - ] - } - ] - ], - "packet_set_commands_enabled":[ - "container", - [ - { - "name":"enabled", - "type":"bool" - } - ] - ], - "packet_set_difficulty":[ - "container", - [ - { - "name":"difficulty", - "type":"varint" - } - ] - ], - "packet_change_dimension":[ - "container", - [ - { - "name":"dimension", - "type":"varint" - }, - { - "name":"position", - "type":"vector3" - }, - { - "name":"unknown", - "type":"bool" - } - ] - ], - "packet_set_player_game_type":[ - "container", - [ - { - "name":"unknown", - "type":"varint" - } - ] - ], - "packet_player_list":[ - "container", - [ - { - "name":"type", - "type":"i8" - }, - { - "name":"entries", - "type":[ + ], + "vector2": [ + "container", + [ + { + "name": "x", + "type": "f32" + }, + { + "name": "y", + "type": "f32" + } + ] + ], + "playerlocation": [ "array", { - "countType":"i32", - "type":[ - "switch", - { - "compareTo":"type", - "fields":{ - "0":[ - "container", - [ + "countType": "i16", + "type": [ + "container", + [ { - "name":"clientUuid", - "type":"uuid" + "name": "x", + "type": "lf32" }, { - "name":"entityId", - "type":"i64" + "name": "y", + "type": "lf32" }, { - "name":"displayName", - "type":"string" + "name": "z", + "type": "lf32" }, { - "name":"skin", - "type":"skin" + "name": "yaw", + "type": "f32" + }, + { + "name": "pitch", + "type": "f32" + }, + { + "name": "headYaw", + "type": "f32" + } + ] + ] + } + ], + "encapsulated_packet": [ + "container", + [ + { + "name": "name", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0xfe": "mcpe" + } + } + ] + }, + { + "name": "params", + "type": [ + "switch", + { + "compareTo": "name", + "fields": { + "mcpe": "mcpe_packet" + } } - ] - ], - "1":[ - "container", - [ - { - "name":"clientUuid", - "type":"uuid" - } - ] ] - } } - ] - } - ] - } - ] - ], - "packet_event":[ - "container", - [ - - ] - ], - "packet_spawn_experience_orb":[ - "container", - [ - { - "name":"position", - "type":"vector3" - }, - { - "name":"count", - "type":"varint" - } - ] - ], - "packet_request_chunk_radius":[ - "container", - [ - { - "name":"chunk_radius", - "type":"varint" - } - ] - ], - "packet_chunk_radius_update":[ - "container", - [ - { - "name":"chunk_radius", - "type":"varint" - } - ] - ], - "packet_item_frame_drop_item":[ - "container", - [ - { - "name":"coordinates", - "type":"blockcoordinatesk" - }, - { - "name":"item", - "type":"slot" - } - ] - ], - "packet_replace_selected_item":[ - "container", - [ - - ] - ], - "packet_game_rules_changed":[ - "container", - [ - { - "name":"rules", - "type":"rules" - } - ] - ], - "packet_camera":[ - "container", - [ - - ] - ], - "packet_add_item":[ - "container", - [ - - ] - ], - "packet_boss_event":[ - "container", - [ - - ] - ], - "packet_available_commands":[ - "container", - [ - { - "name":"commands", - "type":"string" - }, - { - "name":"unknown", - "type":"string" - } - ] - ], - "packet_command_step":[ - "container", - [ - { - "name":"command_name", - "type":"string" - }, - { - "name":"command_overload", - "type":"string" - }, - { - "name":"unknown_1", - "type":"varint" - }, - { - "name":"unknown_2", - "type":"varint" - }, - { - "name":"is_output", - "type":"bool" - }, - { - "name":"unknown_5", - "type":"varint" - }, - { - "name":"command_input_json", - "type":"string" - }, - { - "name":"command_output_json", - "type":"string" - }, - { - "name":"unknown_7", - "type":"u8" - }, - { - "name":"unknown_8", - "type":"u8" - }, - { - "name":"entity_id", - "type":"varint" - } - ] - ], - "packet_resource_pack_data_info":[ - "container", - [ - { - "name":"package_id", - "type":"string" - }, - { - "name":"unknown1", - "type":"u32" - }, - { - "name":"unknown2", - "type":"u32" - }, - { - "name":"unknown3", - "type":"u64" - }, - { - "name":"unknown4", - "type":"string" - } - ] - ], - "packet_resource_pack_chunk_data":[ - "container", - [ - { - "name":"package_id", - "type":"string" - }, - { - "name":"unknown1", - "type":"u32" - }, - { - "name":"unknown3", - "type":"u64" - }, - { - "name":"length", - "type":"u32" - }, - { - "name":"payload", - "type":[ - "buffer", - { - "countType":"varint", - "type":"i8" - } - ] - } - ] - ], - "packet_resource_pack_chunk_request":[ - "container", - [ - { - "name":"package_id", - "type":"string" - }, - { - "name":"chunk_index", - "type":"i32" - } - ] - ] - } -} \ No newline at end of file + ] + ], + "mcpe_packet": [ + "container", + [ + { + "name": "name", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0x01": "game_login", + "0x02": "play_status", + "0x03": "server_to_client_handshake", + "0x04": "client_to_server_handshake", + "0x05": "disconnect", + "0x06": "resource_packs_info", + "0x07": "resource_pack_stack", + "0x08": "resource_pack_client_response", + "0x09": "text", + "0x0a": "set_time", + "0x0b": "start_game", + "0x0c": "add_player", + "0x0d": "add_entity", + "0x0e": "remove_entity", + "0x0f": "add_item_entity", + "0x10": "add_hanging_entity", + "0x11": "take_item_entity", + "0x12": "move_entity", + "0x13": "move_player", + "0x14": "rider_jump", + "0x15": "remove_block", + "0x16": "update_block", + "0x17": "add_painting", + "0x18": "explode", + "0x19": "level_sound_event", + "0x1a": "level_event", + "0x1b": "block_event", + "0x1c": "entity_event", + "0x1d": "mob_effect", + "0x1e": "update_attributes", + "0x1f": "mob_equipment", + "0x20": "mob_armor_equipment", + "0x21": "interact", + "0x22": "block_pick_request", + "0x23": "use_item", + "0x24": "player_action", + "0x25": "entity_fall", + "0x26": "hurt_armor", + "0x27": "set_entity_data", + "0x28": "set_entity_motion", + "0x29": "set_entity_link", + "0x2a": "set_health", + "0x2b": "set_spawn_position", + "0x2c": "animate", + "0x2d": "respawn", + "0x2e": "drop_item", + "0x2f": "inventory_action", + "0x30": "container_open", + "0x31": "container_close", + "0x32": "container_set_slot", + "0x33": "container_set_data", + "0x34": "container_set_content", + "0x35": "crafting_data", + "0x36": "crafting_event", + "0x37": "adventure_settings", + "0x38": "block_entity_data", + "0x39": "player_input", + "0x3a": "full_chunk_data", + "0x3b": "set_commands_enabled", + "0x3c": "set_difficulty", + "0x3d": "change_dimension", + "0x3e": "set_player_game_type", + "0x3f": "player_list", + "0x40": "simple_event", + "0x41": "event", + "0x42": "spawn_experience_orb", + "0x43": "clientbound_map_item_data_", + "0x44": "map_info_request", + "0x45": "request_chunk_radius", + "0x46": "chunk_radius_update", + "0x47": "item_frame_drop_item", + "0x48": "replace_selected_item", + "0x49": "game_rules_changed", + "0x4a": "camera", + "0x4b": "add_item", + "0x4c": "boss_event", + "0x4d": "show_credits", + "0x4e": "available_commands", + "0x4f": "command_step", + "0x50": "command_block_update", + "0x51": "update_trade", + "0x52": "update_equip", + "0x53": "resource_pack_data_info", + "0x54": "resource_pack_chunk_data", + "0x55": "resource_pack_chunk_request", + "0x56": "transfer", + "0x57": "play_sound", + "0x58": "stop_sound", + "0x59": "set_title", + "0x5a": "add_behavior_tree_packet", + "0x5b": "structure_block_update_packet" + } + } + ] + }, + { + "name": "params", + "type": [ + "switch", + { + "compareTo": "name", + "fields": { + "game_login": "packet_game_login", + "play_status": "packet_play_status", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", + "disconnect": "packet_disconnect", + "resource_packs_info": "packet_resource_packs_info", + "resource_pack_stack": "packet_resource_pack_stack", + "resource_pack_client_response": "packet_resource_pack_client_response", + "text": "packet_text", + "set_time": "packet_set_time", + "start_game": "packet_start_game", + "add_player": "packet_add_player", + "add_entity": "packet_add_entity", + "remove_entity": "packet_remove_entity", + "add_item_entity": "packet_add_item_entity", + "add_hanging_entity": "packet_add_hanging_entity", + "take_item_entity": "packet_take_item_entity", + "move_entity": "packet_move_entity", + "move_player": "packet_move_player", + "rider_jump": "packet_rider_jump", + "remove_block": "packet_remove_block", + "update_block": "packet_update_block", + "add_painting": "packet_add_painting", + "explode": "packet_explode", + "level_sound_event": "packet_level_sound_event", + "level_event": "packet_level_event", + "block_event": "packet_block_event", + "entity_event": "packet_entity_event", + "mob_effect": "packet_mob_effect", + "update_attributes": "packet_update_attributes", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", + "interact": "packet_interact", + "block_pick_request": "packet_block_pick_request", + "use_item": "packet_use_item", + "player_action": "packet_player_action", + "entity_fall": "packet_entity_fall", + "hurt_armor": "packet_hurt_armor", + "set_entity_data": "packet_set_entity_data", + "set_entity_motion": "packet_set_entity_motion", + "set_entity_link": "packet_set_entity_link", + "set_health": "packet_set_health", + "set_spawn_position": "packet_set_spawn_position", + "animate": "packet_animate", + "respawn": "packet_respawn", + "drop_item": "packet_drop_item", + "inventory_action": "packet_inventory_action", + "container_open": "packet_container_open", + "container_close": "packet_container_close", + "container_set_slot": "packet_container_set_slot", + "container_set_data": "packet_container_set_data", + "container_set_content": "packet_container_set_content", + "crafting_data": "packet_crafting_data", + "crafting_event": "packet_crafting_event", + "adventure_settings": "packet_adventure_settings", + "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", + "full_chunk_data": "packet_full_chunk_data", + "set_commands_enabled": "packet_set_commands_enabled", + "set_difficulty": "packet_set_difficulty", + "change_dimension": "packet_change_dimension", + "set_player_game_type": "packet_set_player_game_type", + "player_list": "packet_player_list", + "simple_event": "packet_simple_event", + "event": "packet_event", + "spawn_experience_orb": "packet_spawn_experience_orb", + "clientbound_map_item_data_": "packet_clientbound_map_item_data_", + "map_info_request": "packet_map_info_request", + "request_chunk_radius": "packet_request_chunk_radius", + "chunk_radius_update": "packet_chunk_radius_update", + "item_frame_drop_item": "packet_item_frame_drop_item", + "replace_selected_item": "packet_replace_selected_item", + "game_rules_changed": "packet_game_rules_changed", + "camera": "packet_camera", + "add_item": "packet_add_item", + "boss_event": "packet_boss_event", + "show_credits": "packet_show_credits", + "available_commands": "packet_available_commands", + "command_step": "packet_command_step", + "command_block_update": "packet_command_block_update", + "update_trade": "packet_update_trade", + "update_equip": "packet_update_equip", + "resource_pack_data_info": "packet_resource_pack_data_info", + "resource_pack_chunk_data": "packet_resource_pack_chunk_data", + "resource_pack_chunk_request": "packet_resource_pack_chunk_request", + "transfer": "packet_transfer", + "play_sound": "packet_play_sound", + "stop_sound": "packet_stop_sound", + "set_title": "packet_set_title", + "add_behavior_tree_packet": "packet_add_behavior_tree_packet", + "structure_block_update_packet": "packet_structure_block_update_packet" + } + } + ] + } + ] + ], + "packet_game_login": [ + "container", + [ + { + "name": "protocol", + "type": "i32" + }, + { + "name": "edition", + "type": "i8" + }, + { + "name": "body", + "type": [ + "buffer", + { + "countType": "varint" + } + ] + } + ] + ], + "packet_play_status": [ + "container", + [ + { + "name": "status", + "type": "i32" + } + ] + ], + "packet_server_to_client_handshake": [ + "container", + [ + { + "name": "server_public_key", + "type": "string" + }, + { + "name": "token_length", + "type": "u32" + }, + { + "name": "token", + "type": [ + "buffer", + { + "countType": "varint", + "type": "i8" + } + ] + } + ] + ], + "packet_client_to_server_handshake": [ + "container", + [] + ], + "packet_disconnect": [ + "container", + [ + { + "name": "hide_disconnect_reason", + "type": "bool" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "packet_resource_packs_info": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behahaviorpackinfos", + "type": "varint" + }, + { + "name": "resourcepackinfos", + "type": "varint" + } + ] + ], + "packet_resource_pack_stack": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behaviorpackidversions", + "type": "varint" + }, + { + "name": "resourcepackidversions", + "type": "varint" + } + ] + ], + "packet_resource_pack_client_response": [ + "container", + [ + { + "name": "response_status", + "type": "u8" + }, + { + "name": "resourcepackids", + "type": "resourcepackids" + } + ] + ], + "packet_text": [ + "container", + [ + { + "name": "type", + "type": "i8" + }, + { + "name": "source", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "1": "string", + "3": "string" + }, + "default": "void" + } + ] + }, + { + "name": "message", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "0": "string", + "1": "string", + "2": "string", + "3": "string", + "4": "string", + "5": "string" + }, + "default": "void" + } + ] + } + ] + ], + "packet_set_time": [ + "container", + [ + { + "name": "time", + "type": "varint" + } + ] + ], + "packet_start_game": [ + "container", + [ + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "player_gamemode", + "type": "varint" + }, + { + "name": "spawn", + "type": "vector3" + }, + { + "name": "unknown_1", + "type": "vector2" + }, + { + "name": "seed", + "type": "varint" + }, + { + "name": "dimension", + "type": "varint" + }, + { + "name": "generator", + "type": "varint" + }, + { + "name": "gamemode", + "type": "varint" + }, + { + "name": "difficulty", + "type": "varint" + }, + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + }, + { + "name": "has_achievements_disabled", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", + "type": "varint" + }, + { + "name": "edu_mode", + "type": "bool" + }, + { + "name": "rain_level", + "type": "lf32" + }, + { + "name": "lightnig_level", + "type": "lf32" + }, + { + "name": "enable_commands", + "type": "bool" + }, + { + "name": "is_texturepacks_required", + "type": "bool" + }, + { + "name": "gamerules", + "type": "gamerules" + }, + { + "name": "level_id", + "type": "string" + }, + { + "name": "world_name", + "type": "string" + }, + { + "name": "premium_world_template_id", + "type": "string" + }, + { + "name": "unknown0", + "type": "bool" + }, + { + "name": "current_tick", + "type": "i64" + } + ] + ], + "packet_add_player": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "item", + "type": "varint" + }, + { + "name": "metadata", + "type": "varint" + } + ] + ], + "packet_add_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "entity_type", + "type": "varint" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "attributes", + "type": "varint" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "links", + "type": "links" + } + ] + ], + "packet_remove_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "varint" + } + ] + ], + "packet_add_item_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "item", + "type": "varint" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "metadata", + "type": "varint" + } + ] + ], + "packet_add_hanging_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_take_item_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "target", + "type": "varint" + } + ] + ], + "packet_move_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "position", + "type": "playerlocation" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "teleport", + "type": "bool" + } + ] + ], + "packet_move_player": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "mode", + "type": "u8" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "other_runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_rider_jump": [ + "container", + [ + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_remove_block": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + } + ] + ], + "packet_update_block": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "block_id", + "type": "varint" + }, + { + "name": "block_meta_and_priority", + "type": "varint" + } + ] + ], + "packet_add_painting": [ + "container", + [ + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "direction", + "type": "varint" + }, + { + "name": "title", + "type": "string" + } + ] + ], + "packet_explode": [ + "container", + [ + { + "name": "position", + "type": "vector3" + }, + { + "name": "radius", + "type": "varint" + }, + { + "name": "records", + "type": "varint" + } + ] + ], + "packet_level_sound_event": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vector3" + }, + { + "name": "extra_data", + "type": "varint" + }, + { + "name": "pitch", + "type": "varint" + }, + { + "name": "unknown1", + "type": "bool" + }, + { + "name": "disable_relative_volume", + "type": "bool" + } + ] + ], + "packet_level_event": [ + "container", + [ + { + "name": "event_id", + "type": "varint" + }, + { + "name": "position", + "type": "vector3" + }, + { + "name": "data", + "type": "varint" + } + ] + ], + "packet_block_event": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "case_1", + "type": "varint" + }, + { + "name": "case_2", + "type": "varint" + } + ] + ], + "packet_entity_event": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_mob_effect": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "effect_id", + "type": "varint" + }, + { + "name": "amplifier", + "type": "varint" + }, + { + "name": "particles", + "type": "bool" + }, + { + "name": "duration", + "type": "varint" + } + ] + ], + "packet_update_attributes": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "attributes", + "type": "varint" + } + ] + ], + "packet_mob_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "item", + "type": "varint" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "selected_slot", + "type": "u8" + }, + { + "name": "unknown", + "type": "u8" + } + ] + ], + "packet_mob_armor_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "helmet", + "type": "varint" + }, + { + "name": "chestplate", + "type": "varint" + }, + { + "name": "leggings", + "type": "varint" + }, + { + "name": "boots", + "type": "varint" + } + ] + ], + "packet_interact": [ + "container", + [ + { + "name": "action_id", + "type": "u8" + }, + { + "name": "target_runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_block_pick_request": [ + "container", + [ + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_use_item": [ + "container", + [ + { + "name": "blockcoordinates", + "type": "varint" + }, + { + "name": "block_id", + "type": "varint" + }, + { + "name": "face", + "type": "varint" + }, + { + "name": "facecoordinates", + "type": "vector3" + }, + { + "name": "playerposition", + "type": "vector3" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "item", + "type": "varint" + } + ] + ], + "packet_player_action": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "action_id", + "type": "varint" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "face", + "type": "varint" + } + ] + ], + "packet_entity_fall": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "fall_distance", + "type": "lf32" + }, + { + "name": "unknown", + "type": "bool" + } + ] + ], + "packet_hurt_armor": [ + "container", + [ + { + "name": "health", + "type": "varint" + } + ] + ], + "packet_set_entity_data": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "metadata", + "type": "varint" + } + ] + ], + "packet_set_entity_motion": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "velocity", + "type": "vector3" + } + ] + ], + "packet_set_entity_link": [ + "container", + [ + { + "name": "rider_id", + "type": "varint" + }, + { + "name": "ridden_id", + "type": "varint" + }, + { + "name": "link_type", + "type": "u8" + } + ] + ], + "packet_set_health": [ + "container", + [ + { + "name": "health", + "type": "varint" + } + ] + ], + "packet_set_spawn_position": [ + "container", + [ + { + "name": "spawn_type", + "type": "varint" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "forced", + "type": "bool" + } + ] + ], + "packet_animate": [ + "container", + [ + { + "name": "action_id", + "type": "varint" + }, + { + "name": "runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_respawn": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "packet_drop_item": [ + "container", + [ + { + "name": "itemtype", + "type": "u8" + }, + { + "name": "item", + "type": "varint" + } + ] + ], + "packet_inventory_action": [ + "container", + [ + { + "name": "action_id", + "type": "varint" + }, + { + "name": "item", + "type": "varint" + }, + { + "name": "enchantment_id", + "type": "varint" + }, + { + "name": "enchantment_level", + "type": "varint" + } + ] + ], + "packet_container_open": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "unknown_runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_container_close": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + } + ] + ], + "packet_container_set_slot": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "hotbarslot", + "type": "varint" + }, + { + "name": "item", + "type": "varint" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_container_set_data": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "property", + "type": "varint" + }, + { + "name": "value", + "type": "varint" + } + ] + ], + "packet_container_set_content": [ + "container", + [ + { + "name": "window_id", + "type": "varint" + }, + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "slot_data", + "type": "varint" + }, + { + "name": "hotbar_data", + "type": "varint" + } + ] + ], + "packet_crafting_data": [ + "container", + [ + { + "name": "recipes", + "type": "varint" + } + ] + ], + "packet_crafting_event": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "recipe_type", + "type": "varint" + }, + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": "varint" + }, + { + "name": "result", + "type": "varint" + } + ] + ], + "packet_adventure_settings": [ + "container", + [ + { + "name": "flags", + "type": "varint" + }, + { + "name": "user_permission", + "type": "varint" + } + ] + ], + "packet_block_entity_data": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "namedtag", + "type": "varint" + } + ] + ], + "packet_player_input": [ + "container", + [ + { + "name": "motion_x", + "type": "lf32" + }, + { + "name": "motion_z", + "type": "lf32" + }, + { + "name": "flag1", + "type": "bool" + }, + { + "name": "flag2", + "type": "bool" + } + ] + ], + "packet_full_chunk_data": [ + "container", + [ + { + "name": "chunk_x", + "type": "varint" + }, + { + "name": "chunk_z", + "type": "varint" + }, + { + "name": "chunk_data", + "type": [ + "buffer", + { + "countType": "varint", + "type": "i8" + } + ] + } + ] + ], + "packet_set_commands_enabled": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_set_difficulty": [ + "container", + [ + { + "name": "difficulty", + "type": "varint" + } + ] + ], + "packet_change_dimension": [ + "container", + [ + { + "name": "dimension", + "type": "varint" + }, + { + "name": "position", + "type": "vector3" + }, + { + "name": "unknown", + "type": "bool" + } + ] + ], + "packet_set_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "varint" + } + ] + ], + "packet_player_list": [ + "container", + [ + { + "name": "records", + "type": "varint" + } + ] + ], + "packet_simple_event": [ + "container", + [] + ], + "packet_event": [ + "container", + [] + ], + "packet_spawn_experience_orb": [ + "container", + [ + { + "name": "position", + "type": "vector3" + }, + { + "name": "count", + "type": "varint" + } + ] + ], + "packet_clientbound_map_item_data_": [ + "container", + [ + { + "name": "mapinfo", + "type": "varint" + } + ] + ], + "packet_map_info_request": [ + "container", + [ + { + "name": "map_id", + "type": "varint" + } + ] + ], + "packet_request_chunk_radius": [ + "container", + [ + { + "name": "chunk_radius", + "type": "varint" + } + ] + ], + "packet_chunk_radius_update": [ + "container", + [ + { + "name": "chunk_radius", + "type": "varint" + } + ] + ], + "packet_item_frame_drop_item": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + } + ] + ], + "packet_replace_selected_item": [ + "container", + [ + { + "name": "item", + "type": "varint" + } + ] + ], + "packet_game_rules_changed": [ + "container", + [ + { + "name": "rules", + "type": "gamerules" + } + ] + ], + "packet_camera": [ + "container", + [] + ], + "packet_add_item": [ + "container", + [ + { + "name": "item", + "type": "varint" + } + ] + ], + "packet_boss_event": [ + "container", + [ + { + "name": "boss_entity_id", + "type": "varint" + }, + { + "name": "event_type", + "type": "varint" + } + ] + ], + "packet_show_credits": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "status", + "type": "varint" + } + ] + ], + "packet_available_commands": [ + "container", + [ + { + "name": "commands", + "type": "string" + }, + { + "name": "unknown", + "type": "string" + } + ] + ], + "packet_command_step": [ + "container", + [ + { + "name": "command_name", + "type": "string" + }, + { + "name": "command_overload", + "type": "string" + }, + { + "name": "unknown_1", + "type": "varint" + }, + { + "name": "current_step_", + "type": "varint" + }, + { + "name": "is_output", + "type": "bool" + }, + { + "name": "client_id", + "type": "varint" + }, + { + "name": "command_input_json", + "type": "string" + }, + { + "name": "command_output_json", + "type": "string" + }, + { + "name": "unknown_7", + "type": "u8" + }, + { + "name": "unknown_8", + "type": "u8" + }, + { + "name": "entity_id_self", + "type": "varint" + } + ] + ], + "packet_command_block_update": [ + "container", + [] + ], + "packet_update_trade": [ + "container", + [] + ], + "packet_update_equip": [ + "container", + [] + ], + "packet_resource_pack_data_info": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "max_chunk_size_", + "type": "u32" + }, + { + "name": "chunk_count_", + "type": "u32" + }, + { + "name": "compressed_package_size_", + "type": "u64" + }, + { + "name": "hash_", + "type": "string" + } + ] + ], + "packet_resource_pack_chunk_data": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "u32" + }, + { + "name": "progress", + "type": "u64" + }, + { + "name": "length", + "type": "u32" + }, + { + "name": "payload", + "type": [ + "buffer", + { + "countType": "varint", + "type": "i8" + } + ] + } + ] + ], + "packet_resource_pack_chunk_request": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "u32" + } + ] + ], + "packet_transfer": [ + "container", + [ + { + "name": "server_address", + "type": "string" + }, + { + "name": "port", + "type": "ushort" + } + ] + ], + "packet_play_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "volume", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + } + ] + ], + "packet_stop_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "stop_all", + "type": "bool" + } + ] + ], + "packet_set_title": [ + "container", + [ + { + "name": "type", + "type": "varint" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "fade_in_time", + "type": "varint" + }, + { + "name": "stay_time", + "type": "varint" + }, + { + "name": "fade_out_time", + "type": "varint" + } + ] + ], + "packet_add_behavior_tree_packet": [ + "container", + [] + ], + "packet_structure_block_update_packet": [ + "container", + [] + ] + } +} From 8d735acbf90ba96b88b7133a532b639809a1fa6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Fri, 23 Jun 2017 08:03:29 +0200 Subject: [PATCH 070/458] Read error for params.mcpe.name : 120 is not in the mappings value --- data/protocol.json | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index a0c118d..1128943 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -429,7 +429,7 @@ }, { "name": "resourcepackids", - "type": "resourcepackids" + "type": "varint" } ] ], @@ -1624,7 +1624,20 @@ ], "packet_event": [ "container", - [] + [ + { + "name": "entity_id_self", + "type": "varint" + }, + { + "name": "unk1", + "type": "varint" + }, + { + "name": "unk2", + "type": "u8" + } + ] ], "packet_spawn_experience_orb": [ "container", From bb13b9c719be333f13fef775e893e768c7b17e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Fri, 23 Jun 2017 19:56:52 +0200 Subject: [PATCH 071/458] Fix indention. --- src/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index 008d666..b02489a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ module.exports = { - createSerializer: require("./transforms/serializer").createSerializer, - createDeserializer: require("./transforms/serializer").createDeserializer, - createProtocol: require('./transforms/serializer').createProtocol, - createServer: require("./createServer"), - createClient: require("./createClient") + createSerializer: require("./transforms/serializer").createSerializer, + createDeserializer: require("./transforms/serializer").createDeserializer, + createProtocol: require('./transforms/serializer').createProtocol, + createServer: require("./createServer"), + createClient: require("./createClient") }; From 894f2c949e3c713e058534915c4493bd8432ee87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sat, 1 Jul 2017 02:12:50 +0200 Subject: [PATCH 072/458] Updated link to convertor. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 54f647e..a3edda2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/mhsjlw/pocket-minecraft-protocol](https://badges.gitter.im/mhsjlw/pocket-minecraft-protocol.svg)](https://gitter.im/mhsjlw/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Parse and serialize Minecraft PE packets (use [this](https://gist.github.com/filfat/eb6cd08e1e789b5924f7f733babc4a25) to generate the protocol data). +Parse and serialize Minecraft PE packets (use [this](https://github.com/filfat/MiNET-protocol-converter) to generate the protocol data). ## Features From 7038f7a0f0b697c5b7930828546bc151746e9d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 22 Apr 2018 18:47:47 +0200 Subject: [PATCH 073/458] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f73a761..90c1141 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "lodash.merge": "^4.4.0", "prismarine-nbt": "^1.0.0", "protodef": "^1.2.3", - "raknet": "git+https://github.com/filfat/node-raknet.git", + "raknet": "git+https://github.com/mhsjlw/node-raknet.git#master", "uuid-1345": "^0.99.6" }, "devDependencies": { From 9c4dec74ca81701aaa221a28664bc04069f145a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Fri, 12 Jul 2019 02:55:50 +0200 Subject: [PATCH 074/458] Update protocol.json --- data/protocol.json | 1234 +++++++++++++++++++++++++++++++++----------- 1 file changed, 935 insertions(+), 299 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index 1128943..ffb2876 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -45,7 +45,7 @@ "playerlocation": [ "array", { - "countType": "i16", + "countType": "li16", "type": [ "container", [ @@ -131,26 +131,25 @@ "0x0d": "add_entity", "0x0e": "remove_entity", "0x0f": "add_item_entity", - "0x10": "add_hanging_entity", "0x11": "take_item_entity", "0x12": "move_entity", "0x13": "move_player", "0x14": "rider_jump", - "0x15": "remove_block", - "0x16": "update_block", - "0x17": "add_painting", - "0x18": "explode", - "0x19": "level_sound_event", - "0x1a": "level_event", - "0x1b": "block_event", - "0x1c": "entity_event", - "0x1d": "mob_effect", - "0x1e": "update_attributes", + "0x15": "update_block", + "0x16": "add_painting", + "0x17": "explode", + "0x18": "level_sound_event_old", + "0x19": "level_event", + "0x1a": "block_event", + "0x1b": "entity_event", + "0x1c": "mob_effect", + "0x1d": "update_attributes", + "0x1e": "inventory_transaction", "0x1f": "mob_equipment", "0x20": "mob_armor_equipment", "0x21": "interact", "0x22": "block_pick_request", - "0x23": "use_item", + "0x23": "entity_pick_request", "0x24": "player_action", "0x25": "entity_fall", "0x26": "hurt_armor", @@ -161,15 +160,15 @@ "0x2b": "set_spawn_position", "0x2c": "animate", "0x2d": "respawn", - "0x2e": "drop_item", - "0x2f": "inventory_action", - "0x30": "container_open", - "0x31": "container_close", - "0x32": "container_set_slot", + "0x2e": "container_open", + "0x2f": "container_close", + "0x30": "player_hotbar", + "0x31": "inventory_content", + "0x32": "inventory_slot", "0x33": "container_set_data", - "0x34": "container_set_content", - "0x35": "crafting_data", - "0x36": "crafting_event", + "0x34": "crafting_data", + "0x35": "crafting_event", + "0x36": "gui_data_pick_item", "0x37": "adventure_settings", "0x38": "block_entity_data", "0x39": "player_input", @@ -180,33 +179,64 @@ "0x3e": "set_player_game_type", "0x3f": "player_list", "0x40": "simple_event", - "0x41": "event", + "0x41": "telemetry_event", "0x42": "spawn_experience_orb", "0x43": "clientbound_map_item_data_", "0x44": "map_info_request", "0x45": "request_chunk_radius", "0x46": "chunk_radius_update", "0x47": "item_frame_drop_item", - "0x48": "replace_selected_item", - "0x49": "game_rules_changed", - "0x4a": "camera", - "0x4b": "add_item", - "0x4c": "boss_event", - "0x4d": "show_credits", - "0x4e": "available_commands", - "0x4f": "command_step", - "0x50": "command_block_update", - "0x51": "update_trade", - "0x52": "update_equip", - "0x53": "resource_pack_data_info", - "0x54": "resource_pack_chunk_data", - "0x55": "resource_pack_chunk_request", - "0x56": "transfer", - "0x57": "play_sound", - "0x58": "stop_sound", - "0x59": "set_title", - "0x5a": "add_behavior_tree_packet", - "0x5b": "structure_block_update_packet" + "0x48": "game_rules_changed", + "0x49": "camera", + "0x4a": "boss_event", + "0x4b": "show_credits", + "0x4c": "available_commands", + "0x4d": "command_request", + "0x4e": "command_block_update", + "0x4f": "command_output", + "0x50": "update_trade", + "0x51": "update_equipment", + "0x52": "resource_pack_data_info", + "0x53": "resource_pack_chunk_data", + "0x54": "resource_pack_chunk_request", + "0x55": "transfer", + "0x56": "play_sound", + "0x57": "stop_sound", + "0x58": "set_title", + "0x59": "add_behavior_tree", + "0x5a": "structure_block_update", + "0x5b": "show_store_offer", + "0x5c": "purchase_receipt", + "0x5d": "player_skin", + "0x5e": "sub_client_login", + "0x5f": "initiate_web_socket_connection", + "0x60": "set_last_hurt_by", + "0x61": "book_edit", + "0x62": "npc_request", + "0x63": "photo_transfer", + "0x64": "modal_form_request", + "0x65": "modal_form_response", + "0x66": "server_settings_request", + "0x67": "server_settings_response", + "0x68": "show_profile", + "0x69": "set_default_game_type", + "0x6a": "remove_objective", + "0x6b": "set_display_objective", + "0x6c": "set_score", + "0x6d": "lab_table", + "0x6e": "update_block_synced", + "0x6f": "move_entity_delta", + "0x70": "set_scoreboard_identity_packet", + "0x71": "set_local_player_as_initialized_packet", + "0x72": "update_soft_enum_packet", + "0x73": "network_stack_latency_packet", + "0x75": "script_custom_event_packet", + "0x76": "spawn_particle_effect", + "0x77": "available_entity_identifiers", + "0x78": "level_sound_event_v2", + "0x79": "network_chunk_publisher_update", + "0x7a": "biome_definition_list", + "0x7b": "level_sound_event" } } ] @@ -233,26 +263,25 @@ "add_entity": "packet_add_entity", "remove_entity": "packet_remove_entity", "add_item_entity": "packet_add_item_entity", - "add_hanging_entity": "packet_add_hanging_entity", "take_item_entity": "packet_take_item_entity", "move_entity": "packet_move_entity", "move_player": "packet_move_player", "rider_jump": "packet_rider_jump", - "remove_block": "packet_remove_block", "update_block": "packet_update_block", "add_painting": "packet_add_painting", "explode": "packet_explode", - "level_sound_event": "packet_level_sound_event", + "level_sound_event_old": "packet_level_sound_event_old", "level_event": "packet_level_event", "block_event": "packet_block_event", "entity_event": "packet_entity_event", "mob_effect": "packet_mob_effect", "update_attributes": "packet_update_attributes", + "inventory_transaction": "packet_inventory_transaction", "mob_equipment": "packet_mob_equipment", "mob_armor_equipment": "packet_mob_armor_equipment", "interact": "packet_interact", "block_pick_request": "packet_block_pick_request", - "use_item": "packet_use_item", + "entity_pick_request": "packet_entity_pick_request", "player_action": "packet_player_action", "entity_fall": "packet_entity_fall", "hurt_armor": "packet_hurt_armor", @@ -263,15 +292,15 @@ "set_spawn_position": "packet_set_spawn_position", "animate": "packet_animate", "respawn": "packet_respawn", - "drop_item": "packet_drop_item", - "inventory_action": "packet_inventory_action", "container_open": "packet_container_open", "container_close": "packet_container_close", - "container_set_slot": "packet_container_set_slot", + "player_hotbar": "packet_player_hotbar", + "inventory_content": "packet_inventory_content", + "inventory_slot": "packet_inventory_slot", "container_set_data": "packet_container_set_data", - "container_set_content": "packet_container_set_content", "crafting_data": "packet_crafting_data", "crafting_event": "packet_crafting_event", + "gui_data_pick_item": "packet_gui_data_pick_item", "adventure_settings": "packet_adventure_settings", "block_entity_data": "packet_block_entity_data", "player_input": "packet_player_input", @@ -282,24 +311,23 @@ "set_player_game_type": "packet_set_player_game_type", "player_list": "packet_player_list", "simple_event": "packet_simple_event", - "event": "packet_event", + "telemetry_event": "packet_telemetry_event", "spawn_experience_orb": "packet_spawn_experience_orb", "clientbound_map_item_data_": "packet_clientbound_map_item_data_", "map_info_request": "packet_map_info_request", "request_chunk_radius": "packet_request_chunk_radius", "chunk_radius_update": "packet_chunk_radius_update", "item_frame_drop_item": "packet_item_frame_drop_item", - "replace_selected_item": "packet_replace_selected_item", "game_rules_changed": "packet_game_rules_changed", "camera": "packet_camera", - "add_item": "packet_add_item", "boss_event": "packet_boss_event", "show_credits": "packet_show_credits", "available_commands": "packet_available_commands", - "command_step": "packet_command_step", + "command_request": "packet_command_request", "command_block_update": "packet_command_block_update", + "command_output": "packet_command_output", "update_trade": "packet_update_trade", - "update_equip": "packet_update_equip", + "update_equipment": "packet_update_equipment", "resource_pack_data_info": "packet_resource_pack_data_info", "resource_pack_chunk_data": "packet_resource_pack_chunk_data", "resource_pack_chunk_request": "packet_resource_pack_chunk_request", @@ -307,8 +335,40 @@ "play_sound": "packet_play_sound", "stop_sound": "packet_stop_sound", "set_title": "packet_set_title", - "add_behavior_tree_packet": "packet_add_behavior_tree_packet", - "structure_block_update_packet": "packet_structure_block_update_packet" + "add_behavior_tree": "packet_add_behavior_tree", + "structure_block_update": "packet_structure_block_update", + "show_store_offer": "packet_show_store_offer", + "purchase_receipt": "packet_purchase_receipt", + "player_skin": "packet_player_skin", + "sub_client_login": "packet_sub_client_login", + "initiate_web_socket_connection": "packet_initiate_web_socket_connection", + "set_last_hurt_by": "packet_set_last_hurt_by", + "book_edit": "packet_book_edit", + "npc_request": "packet_npc_request", + "photo_transfer": "packet_photo_transfer", + "modal_form_request": "packet_modal_form_request", + "modal_form_response": "packet_modal_form_response", + "server_settings_request": "packet_server_settings_request", + "server_settings_response": "packet_server_settings_response", + "show_profile": "packet_show_profile", + "set_default_game_type": "packet_set_default_game_type", + "remove_objective": "packet_remove_objective", + "set_display_objective": "packet_set_display_objective", + "set_score": "packet_set_score", + "lab_table": "packet_lab_table", + "update_block_synced": "packet_update_block_synced", + "move_entity_delta": "packet_move_entity_delta", + "set_scoreboard_identity_packet": "packet_set_scoreboard_identity_packet", + "set_local_player_as_initialized_packet": "packet_set_local_player_as_initialized_packet", + "update_soft_enum_packet": "packet_update_soft_enum_packet", + "network_stack_latency_packet": "packet_network_stack_latency_packet", + "script_custom_event_packet": "packet_script_custom_event_packet", + "spawn_particle_effect": "packet_spawn_particle_effect", + "available_entity_identifiers": "packet_available_entity_identifiers", + "level_sound_event_v2": "packet_level_sound_event_v2", + "network_chunk_publisher_update": "packet_network_chunk_publisher_update", + "biome_definition_list": "packet_biome_definition_list", + "level_sound_event": "packet_level_sound_event" } } ] @@ -349,23 +409,9 @@ "packet_server_to_client_handshake": [ "container", [ - { - "name": "server_public_key", - "type": "string" - }, - { - "name": "token_length", - "type": "u32" - }, { "name": "token", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] + "type": "string" } ] ], @@ -393,6 +439,10 @@ "name": "must_accept", "type": "bool" }, + { + "name": "has_scripts", + "type": "bool" + }, { "name": "behahaviorpackinfos", "type": "varint" @@ -417,6 +467,10 @@ { "name": "resourcepackidversions", "type": "varint" + }, + { + "name": "is_experimental", + "type": "bool" } ] ], @@ -550,14 +604,38 @@ "name": "edu_mode", "type": "bool" }, + { + "name": "has_edu_features_enabled", + "type": "bool" + }, { "name": "rain_level", "type": "lf32" }, { - "name": "lightnig_level", + "name": "lightning_level", "type": "lf32" }, + { + "name": "has_confirmed_platform_locked_content", + "type": "bool" + }, + { + "name": "is_multiplayer", + "type": "bool" + }, + { + "name": "broadcast_to_lan", + "type": "bool" + }, + { + "name": "xbox_live_broadcast_mode", + "type": "varint" + }, + { + "name": "platform_broadcast_mode", + "type": "varint" + }, { "name": "enable_commands", "type": "bool" @@ -570,6 +648,46 @@ "name": "gamerules", "type": "gamerules" }, + { + "name": "bonus_chest", + "type": "bool" + }, + { + "name": "map_enabled", + "type": "bool" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "server_chunk_tick_range", + "type": "i32" + }, + { + "name": "has_locked_behavior_pack", + "type": "bool" + }, + { + "name": "has_locked_resource_pack", + "type": "bool" + }, + { + "name": "is_from_locked_world_template", + "type": "bool" + }, + { + "name": "use_msa_gamertags_only", + "type": "bool" + }, + { + "name": "is_from_world_template", + "type": "bool" + }, + { + "name": "is_world_template_option_locked", + "type": "bool" + }, { "name": "level_id", "type": "string" @@ -583,12 +701,28 @@ "type": "string" }, { - "name": "unknown0", + "name": "is_trial", "type": "bool" }, { "name": "current_tick", "type": "i64" + }, + { + "name": "enchantment_seed", + "type": "varint" + }, + { + "name": "blockstates", + "type": "blockstates" + }, + { + "name": "multiplayer_correlation_id", + "type": "string" + }, + { + "name": "unknown2", + "type": "u8" } ] ], @@ -611,6 +745,10 @@ "name": "runtime_entity_id", "type": "varint" }, + { + "name": "platform_chat_id", + "type": "string" + }, { "name": "x", "type": "lf32" @@ -640,11 +778,11 @@ "type": "lf32" }, { - "name": "head_yaw", + "name": "yaw", "type": "lf32" }, { - "name": "yaw", + "name": "head_yaw", "type": "lf32" }, { @@ -654,6 +792,38 @@ { "name": "metadata", "type": "varint" + }, + { + "name": "flags", + "type": "varint" + }, + { + "name": "command_permission", + "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "i64" + }, + { + "name": "links", + "type": "links" + }, + { + "name": "device_id", + "type": "string" } ] ], @@ -670,7 +840,7 @@ }, { "name": "entity_type", - "type": "varint" + "type": "string" }, { "name": "x", @@ -704,6 +874,10 @@ "name": "yaw", "type": "lf32" }, + { + "name": "head_yaw", + "type": "lf32" + }, { "name": "attributes", "type": "varint" @@ -769,27 +943,10 @@ { "name": "metadata", "type": "varint" - } - ] - ], - "packet_add_hanging_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" }, { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "unknown", - "type": "varint" + "name": "is_from_fishing", + "type": "bool" } ] ], @@ -813,17 +970,13 @@ "name": "runtime_entity_id", "type": "varint" }, + { + "name": "flags", + "type": "u8" + }, { "name": "position", "type": "playerlocation" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "teleport", - "type": "bool" } ] ], @@ -851,11 +1004,11 @@ "type": "lf32" }, { - "name": "head_yaw", + "name": "yaw", "type": "lf32" }, { - "name": "yaw", + "name": "head_yaw", "type": "lf32" }, { @@ -881,15 +1034,6 @@ } ] ], - "packet_remove_block": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - } - ] - ], "packet_update_block": [ "container", [ @@ -898,11 +1042,15 @@ "type": "varint" }, { - "name": "block_id", + "name": "block_runtime_id", "type": "varint" }, { - "name": "block_meta_and_priority", + "name": "block_priority", + "type": "varint" + }, + { + "name": "storage", "type": "varint" } ] @@ -949,7 +1097,7 @@ } ] ], - "packet_level_sound_event": [ + "packet_level_sound_event_old": [ "container", [ { @@ -961,19 +1109,19 @@ "type": "vector3" }, { - "name": "extra_data", + "name": "block_id", "type": "varint" }, { - "name": "pitch", + "name": "entity_type", "type": "varint" }, { - "name": "unknown1", + "name": "is_baby_mob", "type": "bool" }, { - "name": "disable_relative_volume", + "name": "is_global", "type": "bool" } ] @@ -1024,7 +1172,7 @@ "type": "u8" }, { - "name": "unknown", + "name": "data", "type": "varint" } ] @@ -1071,6 +1219,15 @@ } ] ], + "packet_inventory_transaction": [ + "container", + [ + { + "name": "transaction", + "type": "transaction" + } + ] + ], "packet_mob_equipment": [ "container", [ @@ -1091,7 +1248,7 @@ "type": "u8" }, { - "name": "unknown", + "name": "windows_id", "type": "u8" } ] @@ -1149,42 +1306,26 @@ "name": "z", "type": "varint" }, + { + "name": "add_user_data", + "type": "bool" + }, { "name": "selected_slot", "type": "u8" } ] ], - "packet_use_item": [ + "packet_entity_pick_request": [ "container", [ { - "name": "blockcoordinates", - "type": "varint" + "name": "runtime_entity_id", + "type": "u64" }, { - "name": "block_id", - "type": "varint" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "facecoordinates", - "type": "vector3" - }, - { - "name": "playerposition", - "type": "vector3" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "varint" + "name": "selected_slot", + "type": "u8" } ] ], @@ -1221,7 +1362,7 @@ "type": "lf32" }, { - "name": "unknown", + "name": "is_in_void", "type": "bool" } ] @@ -1264,17 +1405,21 @@ "packet_set_entity_link": [ "container", [ - { - "name": "rider_id", - "type": "varint" - }, { "name": "ridden_id", "type": "varint" }, + { + "name": "rider_id", + "type": "varint" + }, { "name": "link_type", "type": "u8" + }, + { + "name": "unknown", + "type": "u8" } ] ], @@ -1334,40 +1479,6 @@ } ] ], - "packet_drop_item": [ - "container", - [ - { - "name": "itemtype", - "type": "u8" - }, - { - "name": "item", - "type": "varint" - } - ] - ], - "packet_inventory_action": [ - "container", - [ - { - "name": "action_id", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "enchantment_id", - "type": "varint" - }, - { - "name": "enchantment_level", - "type": "varint" - } - ] - ], "packet_container_open": [ "container", [ @@ -1384,7 +1495,7 @@ "type": "varint" }, { - "name": "unknown_runtime_entity_id", + "name": "runtime_entity_id", "type": "varint" } ] @@ -1398,28 +1509,50 @@ } ] ], - "packet_container_set_slot": [ + "packet_player_hotbar": [ "container", [ + { + "name": "selected_slot", + "type": "varint" + }, { "name": "window_id", "type": "u8" }, + { + "name": "select_slot_", + "type": "bool" + } + ] + ], + "packet_inventory_content": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + }, + { + "name": "input", + "type": "varint" + } + ] + ], + "packet_inventory_slot": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + }, { "name": "slot", "type": "varint" }, - { - "name": "hotbarslot", - "type": "varint" - }, { "name": "item", "type": "varint" - }, - { - "name": "selected_slot", - "type": "u8" } ] ], @@ -1440,27 +1573,6 @@ } ] ], - "packet_container_set_content": [ - "container", - [ - { - "name": "window_id", - "type": "varint" - }, - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "slot_data", - "type": "varint" - }, - { - "name": "hotbar_data", - "type": "varint" - } - ] - ], "packet_crafting_data": [ "container", [ @@ -1495,6 +1607,10 @@ } ] ], + "packet_gui_data_pick_item": [ + "container", + [] + ], "packet_adventure_settings": [ "container", [ @@ -1503,8 +1619,24 @@ "type": "varint" }, { - "name": "user_permission", + "name": "command_permission", "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "i64" } ] ], @@ -1533,11 +1665,11 @@ "type": "lf32" }, { - "name": "flag1", + "name": "jumping", "type": "bool" }, { - "name": "flag2", + "name": "sneaking", "type": "bool" } ] @@ -1595,7 +1727,7 @@ "type": "vector3" }, { - "name": "unknown", + "name": "respawn", "type": "bool" } ] @@ -1620,9 +1752,14 @@ ], "packet_simple_event": [ "container", - [] + [ + { + "name": "event_type", + "type": "ushort" + } + ] ], - "packet_event": [ + "packet_telemetry_event": [ "container", [ { @@ -1697,15 +1834,6 @@ } ] ], - "packet_replace_selected_item": [ - "container", - [ - { - "name": "item", - "type": "varint" - } - ] - ], "packet_game_rules_changed": [ "container", [ @@ -1716,14 +1844,14 @@ ] ], "packet_camera": [ - "container", - [] - ], - "packet_add_item": [ "container", [ { - "name": "item", + "name": "unknown1", + "type": "varint" + }, + { + "name": "unknown2", "type": "varint" } ] @@ -1755,78 +1883,116 @@ ] ], "packet_available_commands": [ + "container", + [] + ], + "packet_command_request": [ "container", [ { - "name": "commands", + "name": "command", + "type": "string" + }, + { + "name": "command_type", + "type": "varint" + }, + { + "name": "unknown_uuid", + "type": "string" + }, + { + "name": "request_id", "type": "string" }, { "name": "unknown", - "type": "string" - } - ] - ], - "packet_command_step": [ - "container", - [ - { - "name": "command_name", - "type": "string" - }, - { - "name": "command_overload", - "type": "string" - }, - { - "name": "unknown_1", - "type": "varint" - }, - { - "name": "current_step_", - "type": "varint" - }, - { - "name": "is_output", "type": "bool" - }, - { - "name": "client_id", - "type": "varint" - }, - { - "name": "command_input_json", - "type": "string" - }, - { - "name": "command_output_json", - "type": "string" - }, - { - "name": "unknown_7", - "type": "u8" - }, - { - "name": "unknown_8", - "type": "u8" - }, - { - "name": "entity_id_self", - "type": "varint" } ] ], "packet_command_block_update": [ + "container", + [ + { + "name": "is_block", + "type": "bool" + } + ] + ], + "packet_command_output": [ "container", [] ], "packet_update_trade": [ "container", - [] + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "window_type", + "type": "u8" + }, + { + "name": "unknown0", + "type": "varint" + }, + { + "name": "unknown1", + "type": "varint" + }, + { + "name": "unknown2", + "type": "varint" + }, + { + "name": "is_willing", + "type": "bool" + }, + { + "name": "trader_entity_id", + "type": "varint" + }, + { + "name": "player_entity_id", + "type": "varint" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "namedtag", + "type": "varint" + } + ] ], - "packet_update_equip": [ + "packet_update_equipment": [ "container", - [] + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "window_type", + "type": "u8" + }, + { + "name": "unknown", + "type": "u8" + }, + { + "name": "entity_id", + "type": "varint" + }, + { + "name": "namedtag", + "type": "varint" + } + ] ], "packet_resource_pack_data_info": [ "container", @@ -1836,20 +2002,26 @@ "type": "string" }, { - "name": "max_chunk_size_", + "name": "max_chunk_size", "type": "u32" }, { - "name": "chunk_count_", + "name": "chunk_count", "type": "u32" }, { - "name": "compressed_package_size_", + "name": "compressed_package_size", "type": "u64" }, { - "name": "hash_", - "type": "string" + "name": "hash", + "type": [ + "buffer", + { + "countType": "varint", + "type": "i8" + } + ] } ] ], @@ -1969,13 +2141,477 @@ } ] ], - "packet_add_behavior_tree_packet": [ + "packet_add_behavior_tree": [ + "container", + [ + { + "name": "behaviortree", + "type": "string" + } + ] + ], + "packet_structure_block_update": [ "container", [] ], - "packet_structure_block_update_packet": [ + "packet_show_store_offer": [ + "container", + [ + { + "name": "unknown0", + "type": "string" + }, + { + "name": "unknown1", + "type": "bool" + } + ] + ], + "packet_purchase_receipt": [ "container", [] + ], + "packet_player_skin": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "skin_id", + "type": "string" + }, + { + "name": "skin_name", + "type": "string" + }, + { + "name": "old_skin_name", + "type": "string" + }, + { + "name": "skin_data", + "type": [ + "buffer", + { + "countType": "varint", + "type": "i8" + } + ] + }, + { + "name": "cape_data", + "type": [ + "buffer", + { + "countType": "varint", + "type": "i8" + } + ] + }, + { + "name": "geometry_model", + "type": "string" + }, + { + "name": "geometry_data", + "type": "string" + } + ] + ], + "packet_sub_client_login": [ + "container", + [] + ], + "packet_initiate_web_socket_connection": [ + "container", + [ + { + "name": "server", + "type": "string" + } + ] + ], + "packet_set_last_hurt_by": [ + "container", + [ + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_book_edit": [ + "container", + [] + ], + "packet_npc_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "unknown0", + "type": "u8" + }, + { + "name": "unknown1", + "type": "string" + }, + { + "name": "unknown2", + "type": "u8" + } + ] + ], + "packet_photo_transfer": [ + "container", + [ + { + "name": "file_name", + "type": "string" + }, + { + "name": "image_data", + "type": "string" + }, + { + "name": "unknown2", + "type": "string" + } + ] + ], + "packet_modal_form_request": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_modal_form_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_server_settings_request": [ + "container", + [] + ], + "packet_server_settings_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_show_profile": [ + "container", + [ + { + "name": "xuid", + "type": "string" + } + ] + ], + "packet_set_default_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "varint" + } + ] + ], + "packet_remove_objective": [ + "container", + [ + { + "name": "objective_name", + "type": "string" + } + ] + ], + "packet_set_display_objective": [ + "container", + [ + { + "name": "display_slot", + "type": "string" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "criteria_name", + "type": "string" + }, + { + "name": "sort_order", + "type": "varint" + } + ] + ], + "packet_set_score": [ + "container", + [ + { + "name": "entries", + "type": "scoreentries" + } + ] + ], + "packet_lab_table": [ + "container", + [ + { + "name": "useless_byte", + "type": "u8" + }, + { + "name": "lab_table_x", + "type": "varint" + }, + { + "name": "lab_table_y", + "type": "varint" + }, + { + "name": "lab_table_z", + "type": "varint" + }, + { + "name": "reaction_type", + "type": "u8" + } + ] + ], + "packet_update_block_synced": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "block_priority", + "type": "varint" + }, + { + "name": "data_layer_id", + "type": "varint" + }, + { + "name": "unknown0", + "type": "varint" + }, + { + "name": "unknown1", + "type": "varint" + } + ] + ], + "packet_move_entity_delta": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "flags", + "type": "u8" + } + ] + ], + "packet_set_scoreboard_identity_packet": [ + "container", + [ + { + "name": "entries", + "type": "scoreboardidentityentries" + } + ] + ], + "packet_set_local_player_as_initialized_packet": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_update_soft_enum_packet": [ + "container", + [] + ], + "packet_network_stack_latency_packet": [ + "container", + [ + { + "name": "timestamp", + "type": "i64" + }, + { + "name": "need_response", + "type": "bool" + } + ] + ], + "packet_script_custom_event_packet": [ + "container", + [ + { + "name": "event_name", + "type": "string" + }, + { + "name": "event_data", + "type": "string" + } + ] + ], + "packet_spawn_particle_effect": [ + "container", + [ + { + "name": "dimension_id", + "type": "u8" + }, + { + "name": "entity_id", + "type": "varint" + }, + { + "name": "position", + "type": "vector3" + }, + { + "name": "particle_name", + "type": "string" + } + ] + ], + "packet_available_entity_identifiers": [ + "container", + [ + { + "name": "namedtag", + "type": "varint" + } + ] + ], + "packet_level_sound_event_v2": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vector3" + }, + { + "name": "block_id", + "type": "varint" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_network_chunk_publisher_update": [ + "container", + [ + { + "name": "coordinates", + "type": "varint" + }, + { + "name": "radius", + "type": "varint" + } + ] + ], + "packet_biome_definition_list": [ + "container", + [ + { + "name": "namedtag", + "type": "varint" + } + ] + ], + "packet_level_sound_event": [ + "container", + [ + { + "name": "sound_id", + "type": "varint" + }, + { + "name": "position", + "type": "vector3" + }, + { + "name": "block_id", + "type": "varint" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] ] } } From b7e39dec84b883db348425a6e4f53028a0ac8b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 14 Jul 2019 17:21:20 +0200 Subject: [PATCH 075/458] Add babel for esnext support. --- .babelrc | 7 + .eslintrc | 41 ++ AUTHORS.md | 3 + HISTORY.md | 4 + index.js | 13 + package.json | 10 +- src/createClient.js | 36 +- src/createServer.js | 62 +- yarn.lock | 1393 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1512 insertions(+), 57 deletions(-) create mode 100644 .babelrc create mode 100644 .eslintrc create mode 100644 AUTHORS.md create mode 100644 yarn.lock diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..f475336 --- /dev/null +++ b/.babelrc @@ -0,0 +1,7 @@ + +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-typescript" + ] +} diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..bb70c93 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,41 @@ +{ + "parser": "babel-eslint", + + "extends": [ + "eslint:recommended" + ], + + "plugins": [ + "@typescript-eslint", + "import" + ], + + "env": { + "es6": true, + "browser": true, + "node": true, + "jasmine": true + }, + + "parserOptions": { + "ecmaFeatures": { + "jsx": true, + "modules": true + } + }, + + "rules": { + "consistent-return": 2, + "no-mixed-operators": 0, + "no-useless-constructor": 0, + "standard/computed-property-even-spacing": 0, + "import/first": 0, + "no-unused-vars": 2, + "no-console": 2, + + "indent": ["error", 4, {"SwitchCase": 1}], + "semi": ["error", "always"], + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "radix": ["off"] + } +} diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..61487ad --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,3 @@ +mhsjlw @mhsjlw +Romain Beaumont @rom1504 +Filiph Sandström @filfat diff --git a/HISTORY.md b/HISTORY.md index 33fcd28..f8583b2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## 2.4.0 +* Update to version 1.12.0 +* Add option to provide protocol.json + ## 2.2.3 * fix the use item packet diff --git a/index.js b/index.js index 220c3fa..b4287e3 100644 --- a/index.js +++ b/index.js @@ -1 +1,14 @@ +'use strict'; + +const path = require('path'); +const register = require('@babel/register').default; +register({ + extends: path.resolve(__dirname, '.babelrc'), + ignore: [/node_modules/], + extensions: [ + ".js", + ".ts" + ] +}); + module.exports = require('./src/index.js'); diff --git a/package.json b/package.json index 90c1141..41167fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pocket-minecraft-protocol", - "version": "2.3.0", + "version": "2.4.0", "description": "Parse and serialize Minecraft Pocket Edition packets", "main": "index.js", "scripts": { @@ -11,12 +11,12 @@ "pocket-edition", "protocol" ], - "author": "mhsjlw ", - "contributors": [ - "rom1504" - ], "license": "MIT", "dependencies": { + "@babel/core": "^7.5.4", + "@babel/preset-env": "^7.5.4", + "@babel/preset-typescript": "^7.3.3", + "@babel/register": "^7.4.4", "asn1": "^0.2.3", "bn.js": "^4.11.4", "jwt-simple": "^0.5.0", diff --git a/src/createClient.js b/src/createClient.js index 55d8f08..4e87d1c 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -5,9 +5,9 @@ const fs = require('fs'); const path = require('path'); const zlib = require('zlib'); const ProtoDef = require('protodef').ProtoDef; -const batchProto=new ProtoDef(); +const batchProto = new ProtoDef(); batchProto.addTypes(require("./datatypes/minecraft")); -batchProto.addType("insideBatch",["endOfArray",{"type":["buffer",{"countType":"i32"}]}]); +batchProto.addType("insideBatch", ["endOfArray", { "type": ["buffer", { "countType": "i32" }] }]); function createClient(options) { return null; //FIXME @@ -18,43 +18,43 @@ function createClient(options) { assert.ok(options.username, 'username is required'); - options.customPackets=require('../data/protocol'); - options.customTypes=require('./datatypes/minecraft'); + options.customPackets = require('../data/protocol'); + options.customTypes = require('./datatypes/minecraft'); - var client=raknet.createClient(options); + var client = raknet.createClient(options); client.username = options.username; - client.on('mcpe',packet => client.emit(packet.name,packet.params)) - client.writeMCPE=(name,packet) => { - client.writeEncapsulated('mcpe',{ - name:name, - params:packet + client.on('mcpe', packet => client.emit(packet.name, packet.params)) + client.writeMCPE = (name, packet) => { + client.writeEncapsulated('mcpe', { + name: name, + params: packet }); }; - client.on('login', function() { + client.on('login', function () { client.writeMCPE('game_login', { username: client.username, protocol: 70, protocol2: 70, - clientId: [ -1, -697896776 ], + clientId: [-1, -697896776], clientUuid: '86372ed8-d055-b23a-9171-5e3ac594d766', - serverAddress: client.host+":"+client.port, - clientSecret: new Buffer('e8 88 db 7b 9f f2 f0 44 a3 51 08 18 4e 8c 7f 9a'.replace(/ /g,''),'hex'), + serverAddress: client.host + ":" + client.port, + clientSecret: new Buffer('e8 88 db 7b 9f f2 f0 44 a3 51 08 18 4e 8c 7f 9a'.replace(/ /g, ''), 'hex'), skin: { skinType: 'Standard_Steve', - texture: fs.readFileSync(path.join(__dirname,'texture')) + texture: fs.readFileSync(path.join(__dirname, 'texture')) } } ); }); - client.on('batch', function(packet) { + client.on('batch', function (packet) { var buf = zlib.inflateSync(packet.payload); - var packets=batchProto.parsePacketBuffer("insideBatch",buf).data; - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]),packet]))); + var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; + packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); }); return client; diff --git a/src/createServer.js b/src/createServer.js index 65c0a37..f83fb28 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,20 +1,11 @@ -'use strict'; -let raknet = require('raknet'), - zlib = require('zlib'), - ProtoDef = require('protodef').ProtoDef, - Parser = require('protodef').Parser, - Serializer = require('protodef').Serializer, - jwt = require('jwt-simple'); -var debug = require('debug')('raknet'); +import raknet from 'raknet'; +import zlib from 'zlib'; +import jwt from 'jwt-simple'; +import { ProtoDef, Parser, Serializer } from 'protodef'; + +let debug = require('debug')('raknet'); let batchProto = new ProtoDef(); -batchProto.addTypes(require('./datatypes/minecraft')); -batchProto.addType('insideBatch', ['endOfArray', { - 'type': ['buffer', { - 'countType': 'varint', - }] -}]); - const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; // createServer (object, boolean) @@ -24,33 +15,36 @@ const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7 // encryption: enable/disable encryption function createServer(options, encryption) { options = options || {}; - const port = options.port != null ? - options.port : - options['server-port'] != null ? - options['server-port'] : - 19132; + + const port = options.port || options['server-port'] || 19132; const host = options.host || '0.0.0.0'; - options.customPackets = require('../data/protocol'); - options.customTypes = require('./datatypes/minecraft'); - let server = raknet.createServer(options); + options.customPackets = (options.protocol ? options.protocol.packets : null) || require('../data/protocol'); + options.customTypes = (options.protocol ? options.protocol.types : null) || require('./datatypes/minecraft'); + batchProto.addTypes(options.customTypes); + batchProto.addType('insideBatch', ['endOfArray', { + 'type': ['buffer', { + 'countType': 'varint', + }] + }]); + + let server = raknet.createServer(options); server.name = options.name || 'Minecraft Server'; server.motd = options.motd || 'A Minecraft server'; //FIXME server.maxPlayers = options['max-players'] || 20; //FIXME server.playerCount = 0; //FIXME - - server.on('connection', function(client) { + server.on('connection', (client) => { client.receiveCounter = 0; client.sendCounter = 0; client.encryptionEnabled = encryption ? true : false; let proto = new ProtoDef(); - proto.addTypes(require('./datatypes/minecraft')); - proto.addTypes(require('../data/protocol').types); + proto.addTypes(options.customTypes); + proto.addTypes(options.customPackets.types); client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); - + client.on('mcpe', packet => { client.emit(packet.name, packet.params); client.emit('debug', packet.name); @@ -66,7 +60,7 @@ function createServer(options, encryption) { // // string: packet name // object: packet data - client.writeMCPE = function (name, params) { + client.writeMCPE = (name, params) => { if (client.encryptionEnabled) { client.mcpePacketSerializer.write({ name, params }); } else { @@ -79,7 +73,7 @@ function createServer(options, encryption) { // Send data to the client // // array: packets to send - client.writeBatch = function (packets) { + client.writeBatch = (packets) => { const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packet)))); @@ -94,12 +88,12 @@ function createServer(options, encryption) { // // string: packet name // object: packet data - client.writeAll = function (name, data) { + client.writeAll = (name, data) => { return; //TODO server._writeAll(name, data); }; - client.on('game_login', function (packet) { + client.on('game_login', (packet) => { try { let dataProto = new ProtoDef(); dataProto.addType('data_chain', ['container', [{ @@ -120,7 +114,7 @@ function createServer(options, encryption) { chain = null, decode = null, data = null; - + body.data.chain = JSON.parse(body.data.chain); chain = body.data.chain.chain[0]; @@ -136,7 +130,7 @@ function createServer(options, encryption) { skinId: data.SkinId }) } catch (err) { - console.log(err); + console.error(err); return null; } }); diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..f81af3d --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1393 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/core@^7.5.4": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.4.tgz#4c32df7ad5a58e9ea27ad025c11276324e0b4ddd" + integrity sha512-+DaeBEpYq6b2+ZmHx3tHspC+ZRflrvLqwfv8E3hNr5LVQoyBnL8RPKSBCg+rK2W2My9PWlujBiqd0ZPsR9Q6zQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/helpers" "^7.5.4" + "@babel/parser" "^7.5.0" + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.5.0" + "@babel/types" "^7.5.0" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.11" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a" + integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA== + dependencies: + "@babel/types" "^7.5.0" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" + integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-call-delegate@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" + integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== + dependencies: + "@babel/helper-hoist-variables" "^7.4.4" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/helper-create-class-features-plugin@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.0.tgz#02edb97f512d44ba23b3227f1bf2ed43454edac5" + integrity sha512-EAoMc3hE5vE5LNhMqDOwB1usHvmRjCDAnH8CD4PVkX9/Yr3W/tcz8xE8QvdZxfsFBDICwZnF2UTHIqslRpvxmA== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.4.4" + "@babel/helper-split-export-declaration" "^7.4.4" + +"@babel/helper-define-map@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a" + integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/types" "^7.4.4" + lodash "^4.17.11" + +"@babel/helper-explode-assignable-expression@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" + integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== + dependencies: + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-hoist-variables@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" + integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== + dependencies: + "@babel/types" "^7.4.4" + +"@babel/helper-member-expression-to-functions@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" + integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-imports@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8" + integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/template" "^7.4.4" + "@babel/types" "^7.4.4" + lodash "^4.17.11" + +"@babel/helper-optimise-call-expression@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" + integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + +"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" + integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q== + dependencies: + lodash "^4.17.11" + +"@babel/helper-remap-async-to-generator@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" + integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-wrap-function" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27" + integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/helper-simple-access@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" + integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== + dependencies: + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + +"@babel/helper-wrap-function@^7.1.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" + integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.2.0" + +"@babel/helpers@^7.5.4": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.4.tgz#2f00608aa10d460bde0ccf665d6dcf8477357cf0" + integrity sha512-6LJ6xwUEJP51w0sIgKyfvFMJvIb9mWAfohJp0+m6eHJigkFdcH8duZ1sfhn0ltJRzwUIT/yqqhdSfRpCpL7oow== + dependencies: + "@babel/template" "^7.4.4" + "@babel/traverse" "^7.5.0" + "@babel/types" "^7.5.0" + +"@babel/highlight@^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" + integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.4.4", "@babel/parser@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7" + integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA== + +"@babel/plugin-proposal-async-generator-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" + integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + +"@babel/plugin-proposal-dynamic-import@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506" + integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + +"@babel/plugin-proposal-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" + integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + +"@babel/plugin-proposal-object-rest-spread@^7.5.4": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331" + integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" + integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78" + integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.5.4" + +"@babel/plugin-syntax-async-generators@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" + integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-dynamic-import@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" + integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" + integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" + integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" + integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-typescript@^7.2.0": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" + integrity sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" + integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-async-to-generator@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" + integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + +"@babel/plugin-transform-block-scoped-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" + integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoping@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d" + integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.11" + +"@babel/plugin-transform-classes@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6" + integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-define-map" "^7.4.4" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.4.4" + "@babel/helper-split-export-declaration" "^7.4.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" + integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-destructuring@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a" + integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" + integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.5.4" + +"@babel/plugin-transform-duplicate-keys@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" + integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-exponentiation-operator@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" + integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-for-of@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" + integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-function-name@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" + integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" + integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-member-expression-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d" + integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-amd@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" + integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74" + integrity sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ== + dependencies: + "@babel/helper-module-transforms" "^7.4.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249" + integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg== + dependencies: + "@babel/helper-hoist-variables" "^7.4.4" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-umd@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" + integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.4.5": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz#9d269fd28a370258199b4294736813a60bbdd106" + integrity sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg== + dependencies: + regexp-tree "^0.1.6" + +"@babel/plugin-transform-new-target@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" + integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-object-super@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598" + integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + +"@babel/plugin-transform-parameters@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" + integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== + dependencies: + "@babel/helper-call-delegate" "^7.4.4" + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-property-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905" + integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-regenerator@^7.4.5": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f" + integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA== + dependencies: + regenerator-transform "^0.14.0" + +"@babel/plugin-transform-reserved-words@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" + integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-shorthand-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" + integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-spread@^7.2.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" + integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-sticky-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" + integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + +"@babel/plugin-transform-template-literals@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" + integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typeof-symbol@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" + integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typescript@^7.3.2": + version "7.5.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.5.2.tgz#ea7da440d29b8ccdb1bd02e18f6cfdc7ce6c16f5" + integrity sha512-r4zJOMbKY5puETm8+cIpaa0RQZG/sSASW1u0pj8qYklcERgVIbxVbP2wyJA7zI1//h7lEagQmXi9IL9iI5rfsA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.5.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.2.0" + +"@babel/plugin-transform-unicode-regex@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" + integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.5.4" + +"@babel/preset-env@^7.5.4": + version "7.5.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.4.tgz#64bc15041a3cbb0798930319917e70fcca57713d" + integrity sha512-hFnFnouyRNiH1rL8YkX1ANCNAUVC8Djwdqfev8i1415tnAG+7hlA5zhZ0Q/3Q5gkop4HioIPbCEWAalqcbxRoQ== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.2.0" + "@babel/plugin-proposal-dynamic-import" "^7.5.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.5.4" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.5.0" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.4.4" + "@babel/plugin-transform-classes" "^7.4.4" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.5.0" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/plugin-transform-duplicate-keys" "^7.5.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.4.4" + "@babel/plugin-transform-function-name" "^7.4.4" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-member-expression-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.5.0" + "@babel/plugin-transform-modules-commonjs" "^7.5.0" + "@babel/plugin-transform-modules-systemjs" "^7.5.0" + "@babel/plugin-transform-modules-umd" "^7.2.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5" + "@babel/plugin-transform-new-target" "^7.4.4" + "@babel/plugin-transform-object-super" "^7.2.0" + "@babel/plugin-transform-parameters" "^7.4.4" + "@babel/plugin-transform-property-literals" "^7.2.0" + "@babel/plugin-transform-regenerator" "^7.4.5" + "@babel/plugin-transform-reserved-words" "^7.2.0" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.2.0" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.4.4" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.4.4" + "@babel/types" "^7.5.0" + browserslist "^4.6.0" + core-js-compat "^3.1.1" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.5.0" + +"@babel/preset-typescript@^7.3.3": + version "7.3.3" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz#88669911053fa16b2b276ea2ede2ca603b3f307a" + integrity sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.3.2" + +"@babel/register@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.4.4.tgz#370a68ba36f08f015a8b35d4864176c6b65d7a23" + integrity sha512-sn51H88GRa00+ZoMqCVgOphmswG4b7mhf9VOB0LUBAieykq2GnRFerlN+JQkO/ntT7wz4jaHNSRPg9IdMPEUkA== + dependencies: + core-js "^3.0.0" + find-cache-dir "^2.0.0" + lodash "^4.17.11" + mkdirp "^0.5.1" + pirates "^4.0.0" + source-map-support "^0.5.9" + +"@babel/template@^7.1.0", "@babel/template@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485" + integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.5.0" + "@babel/types" "^7.5.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab" + integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + +ajv@^6.5.4: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +asn1@^0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +bn.js@^4.11.4: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +browserslist@^4.6.0, browserslist@^4.6.2: + version "4.6.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453" + integrity sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA== + dependencies: + caniuse-lite "^1.0.30000984" + electron-to-chromium "^1.3.191" + node-releases "^1.1.25" + +buffer-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" + integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +caniuse-lite@^1.0.30000984: + version "1.0.30000984" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000984.tgz#dc96c3c469e9bcfc6ad5bdd24c77ec918ea76fe0" + integrity sha512-n5tKOjMaZ1fksIpQbjERuqCyfgec/m9pferkFQbLmWtqLUdmt12hNhjSwsmPdqeiG2NkITOQhr1VYIwWSAceiA== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +commander@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + integrity sha1-+mihT2qUXVTbvlDYzbMyDp47GgY= + +commander@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM= + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +convert-source-map@^1.1.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + +core-js-compat@^3.1.1: + version "3.1.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.1.4.tgz#e4d0c40fbd01e65b1d457980fe4112d4358a7408" + integrity sha512-Z5zbO9f1d0YrJdoaQhphVAnKPimX92D6z8lCGphH89MNRxlL1prI9ExJPqVwP0/kgkQCv8c4GJGT8X16yUncOg== + dependencies: + browserslist "^4.6.2" + core-js-pure "3.1.4" + semver "^6.1.1" + +core-js-pure@3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.4.tgz#5fa17dc77002a169a3566cc48dc774d2e13e3769" + integrity sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA== + +core-js@^3.0.0: + version "3.1.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07" + integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ== + +debug@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + integrity sha1-+HBX6ZWxofauaklgZkE3vFbwOdo= + dependencies: + ms "0.7.1" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +define-properties@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +diff@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + integrity sha1-fyjS657nsVqX79ic5j3P2qPMur8= + +electron-to-chromium@^1.3.191: + version "1.3.191" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.191.tgz#c451b422cd8b2eab84dedabab5abcae1eaefb6f0" + integrity sha512-jasjtY5RUy/TOyiUYM2fb4BDaPZfm6CXRFeJDMfFsXYADGxUN49RBqtgB7EL2RmJXeIRUk9lM1U6A5yk2YJMPQ== + +escape-string-regexp@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + integrity sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +glob@3.2.11: + version "3.2.11" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" + integrity sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0= + dependencies: + inherits "2" + minimatch "0.3" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +growl@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +inherits@2, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +jade@0.26.3: + version "0.26.3" + resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + integrity sha1-jxDXl32NefL2/4YqgbBRPMslaGw= + dependencies: + commander "0.6.1" + mkdirp "0.3.0" + +js-levenshtein@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" + integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" + +jwt-simple@^0.5.0: + version "0.5.6" + resolved "https://registry.yarnpkg.com/jwt-simple/-/jwt-simple-0.5.6.tgz#3357adec55b26547114157be66748995b75b333a" + integrity sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg== + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.merge@^4.4.0, lodash.merge@^4.6.1: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.reduce@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= + +lodash@^4.17.11: + version "4.17.14" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" + integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= + +macaddress@^0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.9.tgz#3579b8b9acd5b96b4553abf0f394185a86813cb3" + integrity sha512-k4F1JUof6cQXxNFzx3thLby4oJzXTXQueAOOts944Vqizn+Rjc2QNFenT9FJSLU1CH3PmrHRSyZs2E+Cqw+P2w== + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +minimatch@0.3: + version "0.3.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" + integrity sha1-J12O2qxPG7MyZHIInnlJyDlGmd0= + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4= + +mkdirp@0.5.1, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mocha@^2.5.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" + integrity sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg= + dependencies: + commander "2.3.0" + debug "2.2.0" + diff "1.4.0" + escape-string-regexp "1.0.2" + glob "3.2.11" + growl "1.9.2" + jade "0.26.3" + mkdirp "0.5.1" + supports-color "1.2.0" + to-iso-string "0.0.2" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + integrity sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg= + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-releases@^1.1.25: + version "1.1.25" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3" + integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ== + dependencies: + semver "^5.3.0" + +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +p-limit@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pirates@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +prismarine-nbt@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prismarine-nbt/-/prismarine-nbt-1.2.1.tgz#4b0e50e538a4676ee259ae0588120360ab39110d" + integrity sha512-E2bBd2XzmcynT67zrkucgrC2MIgjmUtUathJ9sfjTswT+ou+7kbHbbLHO3nHLb6TKGiWFH79OfUmBTHJFULpbw== + dependencies: + protodef "^1.2.1" + +private@^0.1.6: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +protodef-validator@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/protodef-validator/-/protodef-validator-1.2.2.tgz#68fae789170e60c5a0a72686f56daee8f791f659" + integrity sha512-EnfcF1v/FGPtkwQr6SAbCM+9IoMCXlhtUVQKgeavUXoJ4FLNk3dZ0jIg/KDnTmaVgvDdHXhg1foH/qTae9vfhw== + dependencies: + ajv "^6.5.4" + +protodef@^1.2.1, protodef@^1.2.3, protodef@^1.6.6: + version "1.6.9" + resolved "https://registry.yarnpkg.com/protodef/-/protodef-1.6.9.tgz#3e913264757e1cf8489589552ec04263a44401f2" + integrity sha512-evAmLjdHgQ3B+wYyCgEijQxSBW049psaXCQlvg6PeJGhgTGEcMrn3M7idHbYvpGNKVIqwnIx8dpFpz1CJNm1wQ== + dependencies: + lodash.get "^4.4.2" + lodash.reduce "^4.6.0" + protodef-validator "^1.2.2" + readable-stream "^3.0.3" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +"raknet@git+https://github.com/mhsjlw/node-raknet.git#master": + version "1.8.0" + resolved "git+https://github.com/mhsjlw/node-raknet.git#c017e4625e87a25e5fef1bb2fbb01e3fc5f91b00" + dependencies: + debug "^3.1.0" + lodash.merge "^4.6.1" + protodef "^1.6.6" + split-buffer "^1.0.0" + +readable-stream@^3.0.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +regenerate-unicode-properties@^8.0.2: + version "8.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" + integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-transform@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf" + integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w== + dependencies: + private "^0.1.6" + +regexp-tree@^0.1.6: + version "0.1.11" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.11.tgz#c9c7f00fcf722e0a56c7390983a7a63dd6c272f3" + integrity sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg== + +regexpu-core@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae" + integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.0.2" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.1.0" + +regjsgen@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" + integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== + +regjsparser@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" + integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== + dependencies: + jsesc "~0.5.0" + +resolve@^1.3.2: + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== + dependencies: + path-parse "^1.0.6" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +semver@^6.1.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" + integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= + +source-map-support@^0.5.9: + version "0.5.12" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/split-buffer/-/split-buffer-1.0.0.tgz#b7e8e0ab51345158b72c1f6dbef2406d51f1d027" + integrity sha1-t+jgq1E0UVi3LB9tvvJAbVHx0Cc= + +string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +supports-color@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + integrity sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-iso-string@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" + integrity sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE= + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" + integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" + integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +uuid-1345@^0.99.6: + version "0.99.7" + resolved "https://registry.yarnpkg.com/uuid-1345/-/uuid-1345-0.99.7.tgz#e52845074352feaae72ce7b31ae1f53b486ceea1" + integrity sha512-A70cwvqH95zULri1/t00/r6Bd97hKpNvS9SoSLP9Bupn95sX/01JkOuH9YjJrmNul7ZAjyX3Y3ZMlDrCjuoNPQ== + dependencies: + macaddress "^0.2.9" From 06c77c3668003bd159555e9ead15786a8005fe8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 14 Jul 2019 17:53:52 +0200 Subject: [PATCH 076/458] Manually fix packets for 1.12 --- data/protocol.json | 206 ++++++++++---------------------------- examples/server_simple.js | 2 +- src/createServer.js | 3 - 3 files changed, 54 insertions(+), 157 deletions(-) diff --git a/data/protocol.json b/data/protocol.json index ffb2876..f3affcd 100644 --- a/data/protocol.json +++ b/data/protocol.json @@ -552,14 +552,21 @@ "name": "player_gamemode", "type": "varint" }, + { "name": "spawn", "type": "vector3" }, + { - "name": "unknown_1", - "type": "vector2" + "name": "pitch", + "type": "lf32" }, + { + "name": "yaw", + "type": "lf32" + }, + { "name": "seed", "type": "varint" @@ -580,6 +587,7 @@ "name": "difficulty", "type": "varint" }, + { "name": "x", "type": "varint" @@ -592,12 +600,13 @@ "name": "z", "type": "varint" }, + { "name": "has_achievements_disabled", "type": "bool" }, { - "name": "day_cycle_stop_time", + "name": "time", "type": "varint" }, { @@ -644,10 +653,12 @@ "name": "is_texturepacks_required", "type": "bool" }, + { - "name": "gamerules", - "type": "gamerules" + "name": "u8", + "type": "u8" }, + { "name": "bonus_chest", "type": "bool" @@ -660,10 +671,12 @@ "name": "permission_level", "type": "varint" }, + { "name": "server_chunk_tick_range", "type": "i32" }, + { "name": "has_locked_behavior_pack", "type": "bool" @@ -672,6 +685,7 @@ "name": "has_locked_resource_pack", "type": "bool" }, + { "name": "is_from_locked_world_template", "type": "bool" @@ -688,6 +702,11 @@ "name": "is_world_template_option_locked", "type": "bool" }, + { + "name": "use_v1_villagers", + "type": "bool" + }, + { "name": "level_id", "type": "string" @@ -712,17 +731,18 @@ "name": "enchantment_seed", "type": "varint" }, + { "name": "blockstates", - "type": "blockstates" + "type": "u8" + }, + { + "name": "itemtable", + "type": "u8" }, { "name": "multiplayer_correlation_id", "type": "string" - }, - { - "name": "unknown2", - "type": "u8" } ] ], @@ -737,6 +757,7 @@ "name": "username", "type": "string" }, + { "name": "entity_id_self", "type": "varint" @@ -749,30 +770,16 @@ "name": "platform_chat_id", "type": "string" }, + { - "name": "x", - "type": "lf32" + "name": "position", + "type": "vector3" }, { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" + "name": "motion", + "type": "vector3" }, + { "name": "pitch", "type": "lf32" @@ -785,14 +792,16 @@ "name": "head_yaw", "type": "lf32" }, + { "name": "item", - "type": "varint" + "type": "u8" }, { "name": "metadata", - "type": "varint" + "type": "u8" }, + { "name": "flags", "type": "varint" @@ -813,13 +822,14 @@ "name": "custom_stored_permissions", "type": "varint" }, + { "name": "user_id", "type": "i64" }, { "name": "links", - "type": "links" + "type": "u8" }, { "name": "device_id", @@ -833,62 +843,6 @@ { "name": "entity_id_self", "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "attributes", - "type": "varint" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "links", - "type": "links" } ] ], @@ -1222,9 +1176,13 @@ "packet_inventory_transaction": [ "container", [ + { + "name": "transaction_type", + "type": "varint" + }, { "name": "transaction", - "type": "transaction" + "type": "varint" } ] ], @@ -1684,16 +1642,6 @@ { "name": "chunk_z", "type": "varint" - }, - { - "name": "chunk_data", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] } ] ], @@ -1755,7 +1703,7 @@ [ { "name": "event_type", - "type": "ushort" + "type": "u8" } ] ], @@ -1839,7 +1787,7 @@ [ { "name": "rules", - "type": "gamerules" + "type": "u8" } ] ], @@ -2012,16 +1960,6 @@ { "name": "compressed_package_size", "type": "u64" - }, - { - "name": "hash", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] } ] ], @@ -2043,16 +1981,6 @@ { "name": "length", "type": "u32" - }, - { - "name": "payload", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] } ] ], @@ -2078,7 +2006,7 @@ }, { "name": "port", - "type": "ushort" + "type": "u8" } ] ], @@ -2189,34 +2117,6 @@ { "name": "old_skin_name", "type": "string" - }, - { - "name": "skin_data", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] - }, - { - "name": "cape_data", - "type": [ - "buffer", - { - "countType": "varint", - "type": "i8" - } - ] - }, - { - "name": "geometry_model", - "type": "string" - }, - { - "name": "geometry_data", - "type": "string" } ] ], @@ -2384,7 +2284,7 @@ [ { "name": "entries", - "type": "scoreentries" + "type": "u8" } ] ], @@ -2460,7 +2360,7 @@ [ { "name": "entries", - "type": "scoreboardidentityentries" + "type": "u8" } ] ], diff --git a/examples/server_simple.js b/examples/server_simple.js index 1cf2e15..846666e 100644 --- a/examples/server_simple.js +++ b/examples/server_simple.js @@ -22,7 +22,7 @@ server.on('connection', function(client) { }); client.on('error', err => { - console.log(err.stack); + console.error(err); }); client.on('end', () => { diff --git a/src/createServer.js b/src/createServer.js index f83fb28..cbca2d9 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -3,8 +3,6 @@ import zlib from 'zlib'; import jwt from 'jwt-simple'; import { ProtoDef, Parser, Serializer } from 'protodef'; -let debug = require('debug')('raknet'); - let batchProto = new ProtoDef(); const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; @@ -89,7 +87,6 @@ function createServer(options, encryption) { // string: packet name // object: packet data client.writeAll = (name, data) => { - return; //TODO server._writeAll(name, data); }; From c75a661a480a5dd685d527268aefb97a942f6fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filiph=20Sandstr=C3=B6m?= Date: Sun, 14 Jul 2019 18:22:34 +0200 Subject: [PATCH 077/458] Build package before commit. --- dist/createClient.js | 70 ++ dist/createServer.js | 147 ++++ dist/datatypes/minecraft.js | 139 ++++ dist/index.js | 9 + dist/transforms/serializer.js | 32 + index.js | 13 +- package.json | 10 +- yarn.lock | 1299 ++++++++++++++++++++++++++++++++- 8 files changed, 1699 insertions(+), 20 deletions(-) create mode 100644 dist/createClient.js create mode 100644 dist/createServer.js create mode 100644 dist/datatypes/minecraft.js create mode 100644 dist/index.js create mode 100644 dist/transforms/serializer.js diff --git a/dist/createClient.js b/dist/createClient.js new file mode 100644 index 0000000..13d4cd8 --- /dev/null +++ b/dist/createClient.js @@ -0,0 +1,70 @@ +'use strict'; + +var assert = require('assert'); + +var raknet = require('raknet'); + +var fs = require('fs'); + +var path = require('path'); + +var zlib = require('zlib'); + +var ProtoDef = require('protodef').ProtoDef; + +var batchProto = new ProtoDef(); +batchProto.addTypes(require("./datatypes/minecraft")); +batchProto.addType("insideBatch", ["endOfArray", { + "type": ["buffer", { + "countType": "i32" + }] +}]); + +function createClient(options) { + return null; //FIXME + + assert.ok(options, 'options is required'); + var port = options.port || 19132; + var host = options.host || 'localhost'; + assert.ok(options.username, 'username is required'); + options.customPackets = require('../data/protocol'); + options.customTypes = require('./datatypes/minecraft'); + var client = raknet.createClient(options); + client.username = options.username; + client.on('mcpe', function (packet) { + return client.emit(packet.name, packet.params); + }); + + client.writeMCPE = function (name, packet) { + client.writeEncapsulated('mcpe', { + name: name, + params: packet + }); + }; + + client.on('login', function () { + client.writeMCPE('game_login', { + username: client.username, + protocol: 70, + protocol2: 70, + clientId: [-1, -697896776], + clientUuid: '86372ed8-d055-b23a-9171-5e3ac594d766', + serverAddress: client.host + ":" + client.port, + clientSecret: new Buffer('e8 88 db 7b 9f f2 f0 44 a3 51 08 18 4e 8c 7f 9a'.replace(/ /g, ''), 'hex'), + skin: { + skinType: 'Standard_Steve', + texture: fs.readFileSync(path.join(__dirname, 'texture')) + } + }); + }); + client.on('batch', function (packet) { + var buf = zlib.inflateSync(packet.payload); + var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; + packets.forEach(function (packet) { + return client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet])); + }); + }); + return client; +} + +module.exports = createClient; \ No newline at end of file diff --git a/dist/createServer.js b/dist/createServer.js new file mode 100644 index 0000000..e808cc9 --- /dev/null +++ b/dist/createServer.js @@ -0,0 +1,147 @@ +"use strict"; + +var _raknet = _interopRequireDefault(require("raknet")); + +var _zlib = _interopRequireDefault(require("zlib")); + +var _jwtSimple = _interopRequireDefault(require("jwt-simple")); + +var _protodef = require("protodef"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } + +var batchProto = new _protodef.ProtoDef(); +var PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; // createServer (object, boolean) +// +// Create & launch a MCPE raknet-based server. +// object: raknet options +// encryption: enable/disable encryption + +function createServer(options, encryption) { + options = options || {}; + var port = options.port || options['server-port'] || 19132; + var host = options.host || '0.0.0.0'; + options.customPackets = (options.protocol ? options.protocol.packets : null) || require('../data/protocol'); + options.customTypes = (options.protocol ? options.protocol.types : null) || require('./datatypes/minecraft'); + batchProto.addTypes(options.customTypes); + batchProto.addType('insideBatch', ['endOfArray', { + 'type': ['buffer', { + 'countType': 'varint' + }] + }]); + + var server = _raknet["default"].createServer(options); + + server.name = options.name || 'Minecraft Server'; + server.motd = options.motd || 'A Minecraft server'; //FIXME + + server.maxPlayers = options['max-players'] || 20; //FIXME + + server.playerCount = 0; //FIXME + + server.on('connection', function (client) { + client.receiveCounter = 0; + client.sendCounter = 0; + client.encryptionEnabled = encryption ? true : false; + var proto = new _protodef.ProtoDef(); + proto.addTypes(options.customTypes); + proto.addTypes(options.customPackets.types); + client.mcpePacketSerializer = new _protodef.Serializer(proto, 'mcpe_packet'); + client.on('mcpe', function (packet) { + client.emit(packet.name, packet.params); + client.emit('debug', packet.name); + }); + client.on('batch', function (packets) { + var buf = _zlib["default"].inflateSync(packets.payload); + + var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; + packets.forEach(function (packet) { + return client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet])); + }); + }); // client.writePacket (string, object) + // Send data to the client + // + // string: packet name + // object: packet data + + client.writeMCPE = function (name, params) { + if (client.encryptionEnabled) { + client.mcpePacketSerializer.write({ + name: name, + params: params + }); + } else { + client.writeEncapsulated('mcpe', { + name: name, + params: params + }); + } + }; + + client.writePacket = client.writeMCPE; // client.writeData (array) + // Send data to the client + // + // array: packets to send + + client.writeBatch = function (packets) { + var payload = _zlib["default"].deflateSync(batchProto.createPacketBuffer('insideBatch', packets.map(function (packet) { + return client.mcpePacketSerializer.createPacketBuffer(packet); + }))); + + client.writePacket('batch', { + payload: payload + }); + }; + + client.writeData = client.writeBatch; // client.writeAll (string, object) + // Send data to the client + // + // string: packet name + // object: packet data + + client.writeAll = function (name, data) { + server._writeAll(name, data); + }; + + client.on('game_login', function (packet) { + try { + var dataProto = new _protodef.ProtoDef(); + dataProto.addType('data_chain', ['container', [{ + 'name': 'chain', + 'type': ['pstring', { + 'countType': 'li32' + }] + }, { + 'name': 'clientData', + 'type': ['pstring', { + 'countType': 'li32' + }] + }]]); //FIXME: Xbox & Non-Xbox support + + console.log(packet); + var body = dataProto.parsePacketBuffer('data_chain', _zlib["default"].inflateSync(packet.body)), + chain = null, + decode = null, + data = null; + body.data.chain = JSON.parse(body.data.chain); + chain = body.data.chain.chain[0]; + decode = _jwtSimple["default"].decode(chain, PUBLIC_KEY, 'ES384'); + data = _jwtSimple["default"].decode(body.data.clientData, decode.identityPublicKey, 'ES384'); + client.emit('mcpe_login', { + protocol: packet.protocol, + uuid: decode.extraData != null ? decode.extraData.identity : null, + id: decode.extraData != null ? decode.extraData.identityPublicKey : null, + username: decode.extraData != null ? decode.extraData.displayName : null, + skinData: data.SkinData, + skinId: data.SkinId + }); + } catch (err) { + console.error(err); + return null; + } + }); + }); + return server; +} + +module.exports = createServer; \ No newline at end of file diff --git a/dist/datatypes/minecraft.js b/dist/datatypes/minecraft.js new file mode 100644 index 0000000..9a1fcb8 --- /dev/null +++ b/dist/datatypes/minecraft.js @@ -0,0 +1,139 @@ +'use strict'; + +var nbt = require('prismarine-nbt'); + +var UUID = require('uuid-1345'); + +function readUUID(buffer, offset) { + if (offset + 16 > buffer.length) throw new PartialReadError(); + return { + value: UUID.stringify(buffer.slice(offset, 16 + offset)), + size: 16 + }; +} + +function writeUUID(value, buffer, offset) { + var buf = UUID.parse(value); + buf.copy(buffer, offset); + return offset + 16; +} + +function readNbt(buffer, offset) { + return nbt.protoLE.read(buffer, offset, "nbt"); +} + +function writeNbt(value, buffer, offset) { + return nbt.protoLE.write(value, buffer, offset, "nbt"); +} + +function sizeOfNbt(value) { + return nbt.protoLE.sizeOf(value, "nbt"); +} + +function readEntityMetadata(buffer, offset, _ref) { + var type = _ref.type; + var endVal = _ref.endVal; + var cursor = offset; + var metadata = []; + var item = undefined; + + while (true) { + if (offset + 1 > buffer.length) throw new PartialReadError(); + item = buffer.readUInt8(cursor); + + if (item === endVal) { + return { + value: metadata, + size: cursor + 1 - offset + }; + } + + var results = this.read(buffer, cursor, type, {}); + metadata.push(results.value); + cursor += results.size; + } +} + +function writeEntityMetadata(value, buffer, offset, _ref2) { + var type = _ref2.type; + var endVal = _ref2.endVal; + var self = this; + value.forEach(function (item) { + offset = self.write(item, buffer, offset, type, {}); + }); + buffer.writeUInt8(endVal, offset); + return offset + 1; +} + +function sizeOfEntityMetadata(value, _ref3) { + var type = _ref3.type; + var size = 1; + + for (var i = 0; i < value.length; ++i) { + size += this.sizeOf(value[i], type, {}); + } + + return size; +} + +function readIpAddress(buffer, offset) { + var address = buffer[offset] + '.' + buffer[offset + 1] + '.' + buffer[offset + 2] + '.' + buffer[offset + 3]; + return { + size: 4, + value: address + }; +} + +function writeIpAddress(value, buffer, offset) { + var address = value.split('.'); + address.forEach(function (b) { + buffer[offset] = parseInt(b); + offset++; + }); + return offset; +} + +function readEndOfArray(buffer, offset, typeArgs) { + var type = typeArgs.type; + var cursor = offset; + var elements = []; + + while (cursor < buffer.length) { + var results = this.read(buffer, cursor, type, {}); + elements.push(results.value); + cursor += results.size; + } + + return { + value: elements, + size: cursor - offset + }; +} + +function writeEndOfArray(value, buffer, offset, typeArgs) { + var type = typeArgs.type; + var self = this; + value.forEach(function (item) { + offset = self.write(item, buffer, offset, type, {}); + }); + return offset; +} + +function sizeOfEndOfArray(value, typeArgs) { + var type = typeArgs.type; + var size = 0; + + for (var i = 0; i < value.length; ++i) { + size += this.sizeOf(value[i], type, {}); + } + + return size; +} + +module.exports = { + 'uuid': [readUUID, writeUUID, 16], + 'nbt': [readNbt, writeNbt, sizeOfNbt], + 'entityMetadataLoop': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata], + 'ipAddress': [readIpAddress, writeIpAddress, 4], + 'endOfArray': [readEndOfArray, writeEndOfArray, sizeOfEndOfArray] +}; \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..9db82d4 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,9 @@ +"use strict"; + +module.exports = { + createSerializer: require("./transforms/serializer").createSerializer, + createDeserializer: require("./transforms/serializer").createDeserializer, + createProtocol: require('./transforms/serializer').createProtocol, + createServer: require("./createServer"), + createClient: require("./createClient") +}; \ No newline at end of file diff --git a/dist/transforms/serializer.js b/dist/transforms/serializer.js new file mode 100644 index 0000000..a1b0965 --- /dev/null +++ b/dist/transforms/serializer.js @@ -0,0 +1,32 @@ +'use strict'; + +var ProtoDef = require('protodef').ProtoDef; + +var Serializer = require('protodef').Serializer; + +var Parser = require('protodef').Parser; + +var protocol = require('../../data/protocol.json').types; + +function createProtocol() { + var proto = new ProtoDef(); + proto.addTypes(require('../datatypes/minecraft')); + proto.addTypes(protocol); + return proto; +} + +function createSerializer() { + var proto = createProtocol(); + return new Serializer(proto, 'packet'); +} + +function createDeserializer() { + var proto = createProtocol(); + return new Parser(proto, 'packet'); +} + +module.exports = { + createDeserializer: createDeserializer, + createSerializer: createSerializer, + createProtocol: createProtocol +}; \ No newline at end of file diff --git a/index.js b/index.js index b4287e3..b3da4d2 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,3 @@ 'use strict'; -const path = require('path'); -const register = require('@babel/register').default; -register({ - extends: path.resolve(__dirname, '.babelrc'), - ignore: [/node_modules/], - extensions: [ - ".js", - ".ts" - ] -}); - -module.exports = require('./src/index.js'); +module.exports = require('./dist/index.js'); diff --git a/package.json b/package.json index 41167fd..480db34 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Parse and serialize Minecraft Pocket Edition packets", "main": "index.js", "scripts": { + "build": "babel src --out-dir dist", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ @@ -27,8 +28,10 @@ "uuid-1345": "^0.99.6" }, "devDependencies": { + "@babel/cli": "^7.5.0", "buffer-equal": "^1.0.0", - "mocha": "^2.5.3" + "mocha": "^2.5.3", + "pre-commit": "^1.2.2" }, "repository": { "type": "git", @@ -37,5 +40,8 @@ "bugs": { "url": "https://github.com/mhsjlw/pocket-minecraft-protocol/issues" }, - "homepage": "https://github.com/mhsjlw/pocket-minecraft-protocol#readme" + "homepage": "https://github.com/mhsjlw/pocket-minecraft-protocol#readme", + "pre-commit": [ + "build" + ] } diff --git a/yarn.lock b/yarn.lock index f81af3d..a2e8df3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,23 @@ # yarn lockfile v1 +"@babel/cli@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.5.0.tgz#f403c930692e28ecfa3bf02a9e7562b474f38271" + integrity sha512-qNH55fWbKrEsCwID+Qc/3JDPnsSGpIIiMDbppnR8Z6PxLAqMQCFNqBctkIkBrMH49Nx+qqVTrHRWUR+ho2k+qQ== + dependencies: + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.1.0" + glob "^7.0.0" + lodash "^4.17.11" + mkdirp "^0.5.1" + output-file-sync "^2.0.0" + slash "^2.0.0" + source-map "^0.5.0" + optionalDependencies: + chokidar "^2.0.4" + "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" @@ -686,6 +703,11 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + ajv@^6.5.4: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" @@ -696,6 +718,16 @@ ajv@^6.5.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -703,6 +735,47 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + asn1@^0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -710,6 +783,21 @@ asn1@^0.2.3: dependencies: safer-buffer "~2.1.0" +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + babel-plugin-dynamic-import-node@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" @@ -717,11 +805,58 @@ babel-plugin-dynamic-import-node@^2.3.0: dependencies: object.assign "^4.1.0" +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + bn.js@^4.11.4: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + browserslist@^4.6.0, browserslist@^4.6.2: version "4.6.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453" @@ -741,6 +876,21 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + caniuse-lite@^1.0.30000984: version "1.0.30000984" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000984.tgz#dc96c3c469e9bcfc6ad5bdd24c77ec918ea76fe0" @@ -755,6 +905,53 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chokidar@^2.0.4: + version "2.1.6" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" + integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" + integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -777,11 +974,41 @@ commander@2.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM= +commander@^2.8.1: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.4.7: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + convert-source-map@^1.1.0: version "1.6.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" @@ -789,6 +1016,11 @@ convert-source-map@^1.1.0: dependencies: safe-buffer "~5.1.1" +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + core-js-compat@^3.1.1: version "3.1.4" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.1.4.tgz#e4d0c40fbd01e65b1d457980fe4112d4358a7408" @@ -808,6 +1040,20 @@ core-js@^3.0.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07" integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ== +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + debug@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" @@ -815,7 +1061,14 @@ debug@2.2.0: dependencies: ms "0.7.1" -debug@^3.1.0: +debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -829,6 +1082,16 @@ debug@^4.1.0: dependencies: ms "^2.1.1" +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + define-properties@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -836,6 +1099,38 @@ define-properties@^1.1.2: dependencies: object-keys "^1.0.12" +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + diff@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" @@ -861,6 +1156,48 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -871,6 +1208,16 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + find-cache-dir@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" @@ -887,11 +1234,75 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fs-minipass@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" + integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== + dependencies: + minipass "^2.2.1" + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + dependencies: + nan "^2.12.1" + node-pre-gyp "^0.12.0" + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + glob@3.2.11: version "3.2.11" resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" @@ -900,11 +1311,28 @@ glob@3.2.11: inherits "2" minimatch "0.3" +glob@^7.0.0, glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +graceful-fs@^4.1.11: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + growl@1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" @@ -920,11 +1348,74 @@ has-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= -inherits@2, inherits@^2.0.3: +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -932,6 +1423,153 @@ invariant@^2.2.2: dependencies: loose-envify "^1.0.0" +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + jade@0.26.3: version "0.26.3" resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" @@ -977,6 +1615,30 @@ jwt-simple@^0.5.0: resolved "https://registry.yarnpkg.com/jwt-simple/-/jwt-simple-0.5.6.tgz#3357adec55b26547114157be66748995b75b333a" integrity sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg== +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -1017,6 +1679,14 @@ lru-cache@2: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + macaddress@^0.2.9: version "0.2.9" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.9.tgz#3579b8b9acd5b96b4553abf0f394185a86813cb3" @@ -1030,6 +1700,37 @@ make-dir@^2.0.0: pify "^4.0.1" semver "^5.6.0" +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + minimatch@0.3: version "0.3.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" @@ -1038,6 +1739,13 @@ minimatch@0.3: lru-cache "2" sigmund "~1.0.0" +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -1048,12 +1756,35 @@ minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minipass@^2.2.1, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + mkdirp@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4= -mkdirp@0.5.1, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -1081,16 +1812,68 @@ ms@0.7.1: resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" integrity sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg= +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + node-releases@^1.1.25: version "1.1.25" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3" @@ -1098,11 +1881,80 @@ node-releases@^1.1.25: dependencies: semver "^5.3.0" +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + object-keys@^1.0.11, object-keys@^1.0.12: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + object.assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" @@ -1113,6 +1965,52 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc= + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-2.0.1.tgz#f53118282f5f553c2799541792b723a4c71430c0" + integrity sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ== + dependencies: + graceful-fs "^4.1.11" + is-plain-obj "^1.1.0" + mkdirp "^0.5.1" + p-limit@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" @@ -1132,11 +2030,26 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" @@ -1161,6 +2074,20 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +pre-commit@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" + integrity sha1-287g7p3nI15X95xW186UZBpp7sY= + dependencies: + cross-spawn "^5.0.1" + spawn-sync "^1.0.15" + which "1.2.x" + prismarine-nbt@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/prismarine-nbt/-/prismarine-nbt-1.2.1.tgz#4b0e50e538a4676ee259ae0588120360ab39110d" @@ -1173,6 +2100,11 @@ private@^0.1.6: resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + protodef-validator@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/protodef-validator/-/protodef-validator-1.2.2.tgz#68fae789170e60c5a0a72686f56daee8f791f659" @@ -1190,6 +2122,11 @@ protodef@^1.2.1, protodef@^1.2.3, protodef@^1.6.6: protodef-validator "^1.2.2" readable-stream "^3.0.3" +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -1204,6 +2141,29 @@ punycode@^2.1.0: protodef "^1.6.6" split-buffer "^1.0.0" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readable-stream@^3.0.3: version "3.4.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" @@ -1213,6 +2173,15 @@ readable-stream@^3.0.3: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + regenerate-unicode-properties@^8.0.2: version "8.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" @@ -1232,6 +2201,14 @@ regenerator-transform@^0.14.0: dependencies: private "^0.1.6" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + regexp-tree@^0.1.6: version "0.1.11" resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.11.tgz#c9c7f00fcf722e0a56c7390983a7a63dd6c272f3" @@ -1261,6 +2238,26 @@ regjsparser@^0.6.0: dependencies: jsesc "~0.5.0" +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + resolve@^1.3.2: version "1.11.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" @@ -1268,16 +2265,45 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.6" +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safer-buffer@~2.1.0: +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" @@ -1288,11 +2314,89 @@ semver@^6.1.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + sigmund@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + source-map-support@^0.5.9: version "0.5.12" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" @@ -1301,7 +2405,12 @@ source-map-support@^0.5.9: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.5.0: +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -1311,11 +2420,51 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY= + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + split-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/split-buffer/-/split-buffer-1.0.0.tgz#b7e8e0ab51345158b72c1f6dbef2406d51f1d027" integrity sha1-t+jgq1E0UVi3LB9tvvJAbVHx0Cc= +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string_decoder@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" @@ -1323,6 +2472,32 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.1.0" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + supports-color@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" @@ -1335,6 +2510,19 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +tar@^4: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -1345,11 +2533,41 @@ to-iso-string@0.0.2: resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" integrity sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE= +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -1373,6 +2591,29 @@ unicode-property-aliases-ecmascript@^1.0.4: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -1380,7 +2621,17 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@^1.0.1: +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -1391,3 +2642,39 @@ uuid-1345@^0.99.6: integrity sha512-A70cwvqH95zULri1/t00/r6Bd97hKpNvS9SoSLP9Bupn95sX/01JkOuH9YjJrmNul7ZAjyX3Y3ZMlDrCjuoNPQ== dependencies: macaddress "^0.2.9" + +which@1.2.x: + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU= + dependencies: + isexe "^2.0.0" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== From 2fa2d2b92905bd5ef256a6be5608695dc87e6448 Mon Sep 17 00:00:00 2001 From: mhsjlw Date: Sun, 14 Jul 2019 13:19:25 -0400 Subject: [PATCH 078/458] Add NOTICE regarding current state --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45885e7..0dbd617 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/mhsjlw/pocket-minecraft-protocol](https://badges.gitter.im/mhsjlw/pocket-minecraft-protocol.svg)](https://gitter.im/mhsjlw/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/PrismarineJS/pocket-minecraft-protocol](https://badges.gitter.im/PrismarineJS/pocket-minecraft-protocol.svg)](https://gitter.im/PrismarineJS/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ========================= -> Note: If you're looking for experimental encryption or 1.0.\* support, please see the [1.0](https://github.com/mhsjlw/pocket-minecraft-protocol/tree/1.0) branch +> Note: **THIS IS NOT USABLE SOFTWARE!** If you're looking for experimental encryption or current support, please see the [1.1](https://github.com/PrismarineJS/pocket-minecraft-protocol/tree/1.1)+ branch Parse and serialize Minecraft: Pocket Edition packets From 595cfc29d402d720cbb33fd0936213c47e24042e Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Tue, 5 May 2020 10:45:20 +0200 Subject: [PATCH 079/458] fix: package.json to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-MACADDRESS-567156 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 64b98ca..f743b2f 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", "raknet": "^1.7.3", - "uuid-1345": "^0.99.6" + "uuid-1345": "^1.0.1" }, "devDependencies": {}, "repository": { From 93b4da32da0b8d8013f26816ce8d71b421715add Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 17 May 2020 09:56:09 +0000 Subject: [PATCH 080/458] Bump uuid-1345 from 0.99.7 to 1.0.1 Bumps [uuid-1345](https://github.com/scravy/uuid-1345) from 0.99.7 to 1.0.1. - [Release notes](https://github.com/scravy/uuid-1345/releases) - [Commits](https://github.com/scravy/uuid-1345/commits) Signed-off-by: dependabot-preview[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 64b98ca..f743b2f 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "prismarine-nbt": "^1.0.0", "protodef": "^1.2.0", "raknet": "^1.7.3", - "uuid-1345": "^0.99.6" + "uuid-1345": "^1.0.1" }, "devDependencies": {}, "repository": { From 902a57c7229de6221ad20c550d50b06e270b5bea Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 29 Jan 2021 00:50:26 -0500 Subject: [PATCH 081/458] working server --- data/newproto.json | 4707 ++++++++++++++++++++++++++++++++++ package.json | 15 +- src/BatchPacket.js | 86 + src/auth/constants.js | 4 + src/auth/encrypt.js | 232 ++ src/auth/encryptTest.js | 88 + src/auth/encryption.js | 102 + src/auth/jwt.js | 104 + src/auth/jwtTest.js | 49 + src/serverTest.js | 226 ++ src/transforms/encryption.js | 108 + 11 files changed, 5716 insertions(+), 5 deletions(-) create mode 100644 data/newproto.json create mode 100644 src/BatchPacket.js create mode 100644 src/auth/constants.js create mode 100644 src/auth/encrypt.js create mode 100644 src/auth/encryptTest.js create mode 100644 src/auth/encryption.js create mode 100644 src/auth/jwt.js create mode 100644 src/auth/jwtTest.js create mode 100644 src/serverTest.js create mode 100644 src/transforms/encryption.js diff --git a/data/newproto.json b/data/newproto.json new file mode 100644 index 0000000..ae404a4 --- /dev/null +++ b/data/newproto.json @@ -0,0 +1,4707 @@ +{ + "types": { + "string": [ + "pstring", + { + "countType": "varint" + } + ], + "ByteArray": [ + "buffer", + { + "countType": "varint" + } + ], + "varint32": "varint", + "varint64": "varint", + "bool": "i8", + "zigzag32": "native", + "zigzag64": "native", + "uuid": "native", + "byterot": "native", + "MapInfo": "native", + "nbt": "native", + "BehaviourPackInfos": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + } + ] + ], + "TexturePackInfos": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "rtx_enabled", + "type": "bool" + } + ] + ], + "ResourcePackIdVersions": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + ], + "ResourcePackIds": [ + "array", + { + "countType": "varint", + "type": "string" + } + ], + "Experiment": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "enabled", + "type": "bool" + } + ] + ], + "Experiments": [ + "array", + { + "countType": "varint", + "type": "Experiment" + } + ], + "GameRule": [ + "container", + [ + { + "name": "name", + "type": "varint" + }, + { + "name": "type", + "type": "varint" + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "1": "bool", + "2": "varint", + "3": "lf32" + } + } + ] + } + ] + ], + "GameRules": [ + "array", + { + "countType": "varint", + "type": "GameRule" + } + ], + "BlockPalette": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "state", + "type": "nbt" + } + ] + ] + } + ], + "Itemstates": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "runtime_id", + "type": "i16" + }, + { + "name": "component_based", + "type": "bool" + } + ] + ] + } + ], + "Item": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "auxiliary_value", + "type": "zigzag32" + }, + { + "name": "user_data_marker", + "type": "li16" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + } + ] + } + ] + ], + "vec3i": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "vec3u": [ + "container", + [ + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + } + ] + ], + "vec3f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "vec2f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "MetadataDictionary": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "key", + "type": "varint" + }, + { + "name": "type", + "type": "varint" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "0": [ + "container", + [ + { + "name": "value", + "type": "i8" + } + ] + ], + "1": [ + "container", + [ + { + "name": "value", + "type": "li16" + } + ] + ], + "2": [ + "container", + [ + { + "name": "value", + "type": "zigzag32" + } + ] + ], + "3": [ + "container", + [ + { + "name": "value", + "type": "lf32" + } + ] + ], + "4": [ + "container", + [ + { + "name": "value", + "type": "string" + } + ] + ], + "5": [ + "container", + [ + { + "name": "value", + "type": "nbt" + } + ] + ], + "6": [ + "container", + [ + { + "name": "value", + "type": "vec3i" + } + ] + ], + "7": [ + "container", + [ + { + "name": "value", + "type": "zigzag64" + } + ] + ], + "8": [ + "container", + [ + { + "name": "value", + "type": "li32" + } + ] + ] + } + } + ] + } + ] + ] + } + ], + "Links": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "ridden_entity_id", + "type": "zigzag64" + }, + { + "name": "rider_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "immediate", + "type": "bool" + }, + { + "name": "rider_initiated", + "type": "bool" + } + ] + ] + } + ], + "EntityAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "min", + "type": "lf32" + }, + { + "name": "value", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + } + ] + ] + } + ], + "Rotation": [ + "container", + [ + { + "name": "yaw", + "type": "byterot" + }, + { + "name": "pitch", + "type": "byterot" + }, + { + "name": "head_yaw", + "type": "byterot" + } + ] + ], + "BlockCoordinates": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "PlayerAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "min", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + }, + { + "name": "current", + "type": "lf32" + }, + { + "name": "default", + "type": "lf32" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "Transaction": [ + "container", + [ + { + "name": "legacy_request_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "legacy_request_id", + "fields": { + "0": "void" + }, + "default": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "changed_slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_id", + "type": "u8" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + }, + { + "name": "transaction_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "TYPE_NORMAL", + "1": "TYPE_INVENTORY_MISMATCH", + "2": "TYPE_ITEM_USE", + "3": "TYPE_ITEM_USE_ON_ENTITY", + "4": "TYPE_ITEM_RELEASE" + } + } + ] + }, + { + "name": "has_network_ids", + "type": "bool" + }, + { + "name": "inventory_actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "source_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "INV_SOURCE_TYPE_CONTAINER", + "1": "INV_SOURCE_TYPE_GLOBAL", + "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", + "3": "INV_SOURCE_TYPE_CREATIVE", + "100": "INV_SOURCE_TYPE_CRAFT_SLOT", + "99999": "INV_SOURCE_TYPE_CRAFT" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "INV_SOURCE_TYPE_CONTAINER": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_WORLD_INTERACTION": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CREATIVE": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT_SLOT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] + } + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "has_network_ids", + "fields": { + "true": [ + "container", + [ + { + "name": "new_item_stack_id", + "type": "zigzag32" + } + ] + ], + "false": "void" + } + } + ] + } + ] + ] + } + ] + }, + { + "name": "transactionMap", + "type": [ + "switch", + { + "compareTo": "transaction_type", + "fields": { + "TYPE_NORMAL": "void", + "TYPE_INVENTORY_MISMATCH": "void", + "TYPE_USE_ITEM": [ + "container", + [ + { + "name": "action_type", + "type": "varint" + }, + { + "name": "face", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "varint" + }, + { + "name": "item_in_hand", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + }, + { + "name": "block_runtime_id", + "type": "varint" + } + ] + ], + "TYPE_ITEM_USE_ON_ENTITY": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "action_type", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "item_in_hand", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + } + ] + ], + "TYPE_ITEM_RELEASE": [ + "container", + [ + { + "name": "action_type", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "item_in_hand", + "type": "Item" + }, + { + "name": "head_pos", + "type": "vec3f" + } + ] + ] + } + } + ] + } + ] + ], + "ItemStacks": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "name": "item", + "type": "Item" + } + ] + ] + } + ], + "RecipeIngredient": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "network_data", + "type": "zigzag32" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ], + "PotionTypeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "input_item_meta", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "ingredient_meta", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + }, + { + "name": "output_item_meta", + "type": "zigzag32" + } + ] + ] + } + ], + "PotionContainerChangeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + } + ] + ] + } + ], + "Recipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "shapeless", + "1": "shaped", + "2": "furnace", + "3": "furnace_with_metadata", + "4": "multi", + "5": "shapeless", + "6": "shapeless", + "7": "shaped" + } + } + ] + }, + { + "name": "recipe", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "shapeless": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "shaped": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "furnace": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "output", + "type": "Item" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "furnace_with_metadata": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "input_meta", + "type": "zigzag32" + }, + { + "name": "output", + "type": "Item" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "multi": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ] + } + } + ] + } + ] + ] + } + ], + "SkinImage": [ + "container", + [ + { + "name": "width", + "type": "li32" + }, + { + "name": "height", + "type": "li32" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "Skin": [ + "container", + [ + { + "name": "skin_id", + "type": "string" + }, + { + "name": "skin_resource_pach", + "type": "string" + }, + { + "name": "skin_data", + "type": "SkinImage" + }, + { + "name": "animations", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "skin_image", + "type": "SkinImage" + }, + { + "name": "animation_type", + "type": "li32" + }, + { + "name": "animation_frames", + "type": "lf32" + }, + { + "name": "expression_type", + "type": "lf32" + } + ] + ] + } + ] + }, + { + "name": "cape_data", + "type": "SkinImage" + }, + { + "name": "geometry_data", + "type": "string" + }, + { + "name": "animation_data", + "type": "string" + }, + { + "name": "premium", + "type": "string" + }, + { + "name": "persona", + "type": "bool" + }, + { + "name": "cape_on_classic", + "type": "bool" + }, + { + "name": "cape_id", + "type": "string" + }, + { + "name": "full_skin_id", + "type": "string" + }, + { + "name": "arm_size", + "type": "string" + }, + { + "name": "skin_color", + "type": "string" + }, + { + "name": "personal_pieces", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_id", + "type": "string" + }, + { + "name": "piece_type", + "type": "string" + }, + { + "name": "pack_id", + "type": "string" + }, + { + "name": "is_default_piece", + "type": "bool" + }, + { + "name": "product_id", + "type": "string" + } + ] + ] + } + ] + }, + { + "name": "piece_tint_colors", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_type", + "type": "string" + }, + { + "name": "colors", + "type": [ + "array", + { + "countType": "li32", + "type": "string" + } + ] + } + ] + ] + } + ] + } + ] + ], + "PlayerRecords": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "remove" + } + } + ] + }, + { + "name": "records_count", + "type": "varint" + }, + { + "name": "records", + "type": [ + "array", + { + "count": "records_count", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "xbox_user_id", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "build_platform", + "type": "li32" + }, + { + "name": "skin_data", + "type": "Skin" + }, + { + "name": "is_teacher", + "type": "bool" + }, + { + "name": "is_host", + "type": "bool" + } + ] + ], + "remove": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + } + ] + ] + } + } + ] + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + } + ] + ] + } + } + ] + }, + { + "name": "verified", + "type": [ + "array", + { + "count": "records_count", + "type": "bool" + } + ] + } + ] + ], + "ScoreEntries": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "change", + "1": "remove" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "li64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "remove": [ + "container", + [ + { + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": [ + "container", + [ + { + "name": "entity_unique_id", + "type": "zigzag64" + } + ] + ], + "entity": [ + "container", + [ + { + "name": "entity_unique_id", + "type": "zigzag64" + } + ] + ], + "fake_player": [ + "container", + [ + { + "name": "custom_name", + "type": "string" + } + ] + ] + } + } + ] + } + ] + ], + "change": "void" + } + } + ] + } + ] + ] + } + ] + } + ] + ], + "ScoreboardIdentityEntries": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "TYPE_REGISTER_IDENTITY", + "1": "TYPE_CLEAR_IDENTITY" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "TYPE_REGISTER_IDENTITY": [ + "container", + [ + { + "name": "entity_unique_id", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "Enchant": [ + "container", + [ + { + "name": "id", + "type": "u8" + }, + { + "name": "level", + "type": "u8" + } + ] + ], + "EnchantOptions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "cost", + "type": "varint" + }, + { + "name": "slot_flags", + "type": "li32" + }, + { + "name": "equip_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "held_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "self_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "name", + "type": "string" + }, + { + "name": "option_id", + "type": "zigzag32" + } + ] + ] + } + ], + "StackRequestSlotInfo": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "slot_id", + "type": "u8" + }, + { + "name": "stack_id", + "type": "zigzag32" + } + ] + ], + "ItemStackRequests": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "request_id", + "type": "zigzag32" + }, + { + "name": "actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "TAKE", + "1": "PLACE", + "2": "SWAP", + "3": "DROP", + "4": "DESTROY", + "5": "CRAFTING_CONSUME_INPUT", + "6": "create", + "7": "LAB_TABLE_COMBINE", + "8": "BEACON_PAYMENT", + "9": "CRAFTING_RECIPE", + "10": "CRAFTING_RECIPE_AUTO", + "11": "CREATIVE_CREATE", + "12": "CRAFTING_NON_IMPLEMENTED_DEPRECATED", + "13": "CRAFTING_RESULTS_DEPRECATED" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type_id", + "fields": { + "TAKE": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "PLACE": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "SWAP": [ + "container", + [ + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "DROP": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "randomly", + "type": "bool" + } + ] + ], + "DESTROY": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "CRAFTING_CONSUME_INPUT": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "create": [ + "container", + [ + { + "name": "result_slot_id", + "type": "u8" + } + ] + ], + "BEACON_PAYMENT": [ + "container", + [ + { + "name": "primary_effect", + "type": "varint" + }, + { + "name": "secondary_effect", + "type": "varint" + } + ] + ], + "CRAFTING_RECIPE": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint32" + } + ] + ], + "CRAFTING_RECIPE_AUTO": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint32" + } + ] + ], + "CREATIVE_CREATE": [ + "container", + [ + { + "name": "creative_item_network_id", + "type": "varint32" + } + ] + ], + "CRAFTING_NON_IMPLEMENTED_DEPRECATED": "void", + "CRAFTING_RESULTS_DEPRECATED": [ + "container", + [ + { + "name": "result_items", + "type": "ItemStacks" + }, + { + "name": "times_crafted", + "type": "u8" + } + ] + ] + } + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ], + "ItemStackResponses": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "result", + "type": "u8" + }, + { + "name": "request_id", + "type": "varint32" + }, + { + "name": "containers", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot", + "type": "u8" + }, + { + "name": "hotbar_slot", + "type": "u8" + }, + { + "name": "count", + "type": "u8" + }, + { + "name": "item_stack_id", + "type": "varint32" + }, + { + "name": "custom_name", + "type": "string" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ], + "ItemComponentList": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + } + ], + "mcpe_packet": [ + "container", + [ + { + "name": "name", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0x01": "login", + "0x02": "play_status", + "0x03": "server_to_client_handshake", + "0x04": "client_to_server_handshake", + "0x05": "disconnect", + "0x06": "resource_packs_info", + "0x07": "resource_pack_stack", + "0x08": "resource_pack_client_response", + "0x09": "text", + "0x0a": "set_time", + "0x0b": "start_game", + "0x0c": "add_player", + "0x0d": "add_entity", + "0x0e": "remove_entity", + "0x0f": "add_item_entity", + "0x11": "take_item_entity", + "0x12": "move_entity", + "0x13": "move_player", + "0x14": "rider_jump", + "0x15": "update_block", + "0x16": "add_painting", + "0x17": "tick_sync", + "0x18": "level_sound_event_old", + "0x19": "level_event", + "0x1a": "block_event", + "0x1b": "entity_event", + "0x1c": "mob_effect", + "0x1d": "update_attributes", + "0x1e": "inventory_transaction", + "0x1f": "mob_equipment", + "0x20": "mob_armor_equipment", + "0x21": "interact", + "0x22": "block_pick_request", + "0x23": "entity_pick_request", + "0x24": "player_action", + "0x26": "hurt_armor", + "0x27": "set_entity_data", + "0x28": "set_entity_motion", + "0x29": "set_entity_link", + "0x2a": "set_health", + "0x2b": "set_spawn_position", + "0x2c": "animate", + "0x2d": "respawn", + "0x2e": "container_open", + "0x2f": "container_close", + "0x30": "player_hotbar", + "0x31": "inventory_content", + "0x32": "inventory_slot", + "0x33": "container_set_data", + "0x34": "crafting_data", + "0x35": "crafting_event", + "0x36": "gui_data_pick_item", + "0x37": "adventure_settings", + "0x38": "block_entity_data", + "0x39": "player_input", + "0x3a": "level_chunk", + "0x3b": "set_commands_enabled", + "0x3c": "set_difficulty", + "0x3d": "change_dimension", + "0x3e": "set_player_game_type", + "0x3f": "player_list", + "0x40": "simple_event", + "0x42": "spawn_experience_orb", + "0x43": "clientbound_map_item_data_", + "0x44": "map_info_request", + "0x45": "request_chunk_radius", + "0x46": "chunk_radius_update", + "0x47": "item_frame_drop_item", + "0x48": "game_rules_changed", + "0x49": "camera", + "0x4a": "boss_event", + "0x4b": "show_credits", + "0x4c": "available_commands", + "0x4d": "command_request", + "0x4e": "command_block_update", + "0x4f": "command_output", + "0x50": "update_trade", + "0x51": "update_equipment", + "0x52": "resource_pack_data_info", + "0x53": "resource_pack_chunk_data", + "0x54": "resource_pack_chunk_request", + "0x55": "transfer", + "0x56": "play_sound", + "0x57": "stop_sound", + "0x58": "set_title", + "0x59": "add_behavior_tree", + "0x5a": "structure_block_update", + "0x5b": "show_store_offer", + "0x5c": "purchase_receipt", + "0x5d": "player_skin", + "0x5e": "sub_client_login", + "0x5f": "initiate_web_socket_connection", + "0x60": "set_last_hurt_by", + "0x61": "book_edit", + "0x62": "npc_request", + "0x63": "photo_transfer", + "0x64": "modal_form_request", + "0x65": "modal_form_response", + "0x66": "server_settings_request", + "0x67": "server_settings_response", + "0x68": "show_profile", + "0x69": "set_default_game_type", + "0x6a": "remove_objective", + "0x6b": "set_display_objective", + "0x6c": "set_score", + "0x6d": "lab_table", + "0x6e": "update_block_synced", + "0x6f": "move_entity_delta", + "0x70": "set_scoreboard_identity", + "0x71": "set_local_player_as_initialized", + "0x72": "update_soft_enum", + "0x73": "network_stack_latency", + "0x75": "script_custom_event", + "0x76": "spawn_particle_effect", + "0x77": "available_entity_identifiers", + "0x78": "level_sound_event_v2", + "0x79": "network_chunk_publisher_update", + "0x7a": "biome_definition_list", + "0x7b": "level_sound_event", + "0x7c": "level_event_generic", + "0x7d": "lectern_update", + "0x7e": "video_stream_connect", + "0x81": "client_cache_status", + "0x82": "on_screen_texture_animation", + "0x83": "map_create_locked_copy", + "0x84": "structure_template_data_export_request", + "0x85": "structure_template_data_export_response", + "0x86": "update_block_properties", + "0x87": "client_cache_blob_status", + "0x88": "client_cache_miss_response", + "0x8f": "network_settings", + "0x91": "creative_content", + "0x92": "player_enchant_options", + "0x93": "item_stack_request", + "0x94": "item_stack_response", + "0x97": "update_player_game_type", + "0x9c": "packet_violation_warning", + "0xa2": "item_component", + "0xa3": "filter_text_packet" + } + } + ] + }, + { + "name": "params", + "type": [ + "switch", + { + "compareTo": "name", + "fields": { + "login": "packet_login", + "play_status": "packet_play_status", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", + "disconnect": "packet_disconnect", + "resource_packs_info": "packet_resource_packs_info", + "resource_pack_stack": "packet_resource_pack_stack", + "resource_pack_client_response": "packet_resource_pack_client_response", + "text": "packet_text", + "set_time": "packet_set_time", + "start_game": "packet_start_game", + "add_player": "packet_add_player", + "add_entity": "packet_add_entity", + "remove_entity": "packet_remove_entity", + "add_item_entity": "packet_add_item_entity", + "take_item_entity": "packet_take_item_entity", + "move_entity": "packet_move_entity", + "move_player": "packet_move_player", + "rider_jump": "packet_rider_jump", + "update_block": "packet_update_block", + "add_painting": "packet_add_painting", + "tick_sync": "packet_tick_sync", + "level_sound_event_old": "packet_level_sound_event_old", + "level_event": "packet_level_event", + "block_event": "packet_block_event", + "entity_event": "packet_entity_event", + "mob_effect": "packet_mob_effect", + "update_attributes": "packet_update_attributes", + "inventory_transaction": "packet_inventory_transaction", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", + "interact": "packet_interact", + "block_pick_request": "packet_block_pick_request", + "entity_pick_request": "packet_entity_pick_request", + "player_action": "packet_player_action", + "hurt_armor": "packet_hurt_armor", + "set_entity_data": "packet_set_entity_data", + "set_entity_motion": "packet_set_entity_motion", + "set_entity_link": "packet_set_entity_link", + "set_health": "packet_set_health", + "set_spawn_position": "packet_set_spawn_position", + "animate": "packet_animate", + "respawn": "packet_respawn", + "container_open": "packet_container_open", + "container_close": "packet_container_close", + "player_hotbar": "packet_player_hotbar", + "inventory_content": "packet_inventory_content", + "inventory_slot": "packet_inventory_slot", + "container_set_data": "packet_container_set_data", + "crafting_data": "packet_crafting_data", + "crafting_event": "packet_crafting_event", + "gui_data_pick_item": "packet_gui_data_pick_item", + "adventure_settings": "packet_adventure_settings", + "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", + "level_chunk": "packet_level_chunk", + "set_commands_enabled": "packet_set_commands_enabled", + "set_difficulty": "packet_set_difficulty", + "change_dimension": "packet_change_dimension", + "set_player_game_type": "packet_set_player_game_type", + "player_list": "packet_player_list", + "simple_event": "packet_simple_event", + "spawn_experience_orb": "packet_spawn_experience_orb", + "clientbound_map_item_data_": "packet_clientbound_map_item_data_", + "map_info_request": "packet_map_info_request", + "request_chunk_radius": "packet_request_chunk_radius", + "chunk_radius_update": "packet_chunk_radius_update", + "item_frame_drop_item": "packet_item_frame_drop_item", + "game_rules_changed": "packet_game_rules_changed", + "camera": "packet_camera", + "boss_event": "packet_boss_event", + "show_credits": "packet_show_credits", + "available_commands": "packet_available_commands", + "command_request": "packet_command_request", + "command_block_update": "packet_command_block_update", + "command_output": "packet_command_output", + "update_trade": "packet_update_trade", + "update_equipment": "packet_update_equipment", + "resource_pack_data_info": "packet_resource_pack_data_info", + "resource_pack_chunk_data": "packet_resource_pack_chunk_data", + "resource_pack_chunk_request": "packet_resource_pack_chunk_request", + "transfer": "packet_transfer", + "play_sound": "packet_play_sound", + "stop_sound": "packet_stop_sound", + "set_title": "packet_set_title", + "add_behavior_tree": "packet_add_behavior_tree", + "structure_block_update": "packet_structure_block_update", + "show_store_offer": "packet_show_store_offer", + "purchase_receipt": "packet_purchase_receipt", + "player_skin": "packet_player_skin", + "sub_client_login": "packet_sub_client_login", + "initiate_web_socket_connection": "packet_initiate_web_socket_connection", + "set_last_hurt_by": "packet_set_last_hurt_by", + "book_edit": "packet_book_edit", + "npc_request": "packet_npc_request", + "photo_transfer": "packet_photo_transfer", + "modal_form_request": "packet_modal_form_request", + "modal_form_response": "packet_modal_form_response", + "server_settings_request": "packet_server_settings_request", + "server_settings_response": "packet_server_settings_response", + "show_profile": "packet_show_profile", + "set_default_game_type": "packet_set_default_game_type", + "remove_objective": "packet_remove_objective", + "set_display_objective": "packet_set_display_objective", + "set_score": "packet_set_score", + "lab_table": "packet_lab_table", + "update_block_synced": "packet_update_block_synced", + "move_entity_delta": "packet_move_entity_delta", + "set_scoreboard_identity": "packet_set_scoreboard_identity", + "set_local_player_as_initialized": "packet_set_local_player_as_initialized", + "update_soft_enum": "packet_update_soft_enum", + "network_stack_latency": "packet_network_stack_latency", + "script_custom_event": "packet_script_custom_event", + "spawn_particle_effect": "packet_spawn_particle_effect", + "available_entity_identifiers": "packet_available_entity_identifiers", + "level_sound_event_v2": "packet_level_sound_event_v2", + "network_chunk_publisher_update": "packet_network_chunk_publisher_update", + "biome_definition_list": "packet_biome_definition_list", + "level_sound_event": "packet_level_sound_event", + "level_event_generic": "packet_level_event_generic", + "lectern_update": "packet_lectern_update", + "video_stream_connect": "packet_video_stream_connect", + "client_cache_status": "packet_client_cache_status", + "on_screen_texture_animation": "packet_on_screen_texture_animation", + "map_create_locked_copy": "packet_map_create_locked_copy", + "structure_template_data_export_request": "packet_structure_template_data_export_request", + "structure_template_data_export_response": "packet_structure_template_data_export_response", + "update_block_properties": "packet_update_block_properties", + "client_cache_blob_status": "packet_client_cache_blob_status", + "client_cache_miss_response": "packet_client_cache_miss_response", + "network_settings": "packet_network_settings", + "creative_content": "packet_creative_content", + "player_enchant_options": "packet_player_enchant_options", + "item_stack_request": "packet_item_stack_request", + "item_stack_response": "packet_item_stack_response", + "update_player_game_type": "packet_update_player_game_type", + "packet_violation_warning": "packet_packet_violation_warning", + "item_component": "packet_item_component", + "filter_text_packet": "packet_filter_text_packet" + } + } + ] + } + ] + ], + "packet_login": [ + "container", + [ + { + "name": "protocol_version", + "type": "i32" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_play_status": [ + "container", + [ + { + "name": "status", + "type": "i32" + } + ] + ], + "packet_server_to_client_handshake": [ + "container", + [ + { + "name": "token", + "type": "string" + } + ] + ], + "packet_client_to_server_handshake": [ + "container", + [] + ], + "packet_disconnect": [ + "container", + [ + { + "name": "hide_disconnect_reason", + "type": "bool" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "packet_resource_packs_info": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "behahaviorpackinfos", + "type": "BehaviourPackInfos" + }, + { + "name": "texturepacks", + "type": "TexturePackInfos" + } + ] + ], + "packet_resource_pack_stack": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behaviorpackidversions", + "type": "ResourcePackIdVersions" + }, + { + "name": "resourcepackidversions", + "type": "ResourcePackIdVersions" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "experiments", + "type": "li32" + }, + { + "name": "experiments_previously_toggled", + "type": "bool" + } + ] + ], + "packet_resource_pack_client_response": [ + "container", + [ + { + "name": "response_status", + "type": "u8" + }, + { + "name": "resourcepackids", + "type": "ResourcePackIds" + } + ] + ], + "packet_text": [ + "container", + [ + { + "name": "type", + "type": "u8" + } + ] + ], + "packet_set_time": [ + "container", + [ + { + "name": "time", + "type": "zigzag32" + } + ] + ], + "packet_start_game": [ + "container", + [ + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "player_gamemode", + "type": "zigzag32" + }, + { + "name": "spawn", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "vec3f" + }, + { + "name": "seed", + "type": "zigzag32" + }, + { + "name": "biome_type", + "type": "li16" + }, + { + "name": "biome_name", + "type": "string" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "generator", + "type": "zigzag32" + }, + { + "name": "gamemode", + "type": "zigzag32" + }, + { + "name": "difficulty", + "type": "zigzag32" + }, + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "has_achievements_disabled", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", + "type": "zigzag32" + }, + { + "name": "edu_offer", + "type": "zigzag32" + }, + { + "name": "has_edu_features_enabled", + "type": "bool" + }, + { + "name": "edu_product_uuid_", + "type": "string" + }, + { + "name": "rain_level", + "type": "lf32" + }, + { + "name": "lightning_level", + "type": "lf32" + }, + { + "name": "has_confirmed_platform_locked_content", + "type": "bool" + }, + { + "name": "is_multiplayer", + "type": "bool" + }, + { + "name": "broadcast_to_lan", + "type": "bool" + }, + { + "name": "xbox_live_broadcast_mode", + "type": "varint" + }, + { + "name": "platform_broadcast_mode", + "type": "varint" + }, + { + "name": "enable_commands", + "type": "bool" + }, + { + "name": "is_texturepacks_required", + "type": "bool" + }, + { + "name": "gamerules", + "type": "GameRules" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_toggled", + "type": "bool" + }, + { + "name": "bonus_chest", + "type": "bool" + }, + { + "name": "map_enabled", + "type": "bool" + }, + { + "name": "permission_level", + "type": "zigzag32" + }, + { + "name": "server_chunk_tick_range", + "type": "li32" + }, + { + "name": "has_locked_behavior_pack", + "type": "bool" + }, + { + "name": "has_locked_resource_pack", + "type": "bool" + }, + { + "name": "is_from_locked_world_template", + "type": "bool" + }, + { + "name": "msa_gamertags_only", + "type": "bool" + }, + { + "name": "is_from_world_template", + "type": "bool" + }, + { + "name": "is_world_template_option_locked", + "type": "bool" + }, + { + "name": "only_spawn_v1_villagers", + "type": "bool" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "limited_world_width_", + "type": "li32" + }, + { + "name": "limited_world_length_", + "type": "li32" + }, + { + "name": "is_new_nether_", + "type": "bool" + }, + { + "name": "experimental_gameplay_override", + "type": "bool" + }, + { + "name": "level_id", + "type": "string" + }, + { + "name": "world_name", + "type": "string" + }, + { + "name": "premium_world_template_id", + "type": "string" + }, + { + "name": "is_trial", + "type": "bool" + }, + { + "name": "movement_type", + "type": "zigzag32" + }, + { + "name": "current_tick", + "type": "li64" + }, + { + "name": "enchantment_seed", + "type": "zigzag32" + }, + { + "name": "block_palette", + "type": "BlockPalette" + }, + { + "name": "itemstates", + "type": "Itemstates" + }, + { + "name": "multiplayer_correlation_id", + "type": "string" + }, + { + "name": "server_authoritative_inventory", + "type": "bool" + } + ] + ], + "packet_add_player": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "flags", + "type": "varint" + }, + { + "name": "command_permission", + "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + }, + { + "name": "links", + "type": "Links" + }, + { + "name": "device_id", + "type": "string" + }, + { + "name": "device_os", + "type": "li32" + } + ] + ], + "packet_add_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "attributes", + "type": "EntityAttributes" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "links", + "type": "Links" + } + ] + ], + "packet_remove_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + } + ] + ], + "packet_add_item_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "is_from_fishing", + "type": "bool" + } + ] + ], + "packet_take_item_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "target", + "type": "varint" + } + ] + ], + "packet_move_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "Rotation" + } + ] + ], + "packet_move_player": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "mode", + "type": "u8" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "other_runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_rider_jump": [ + "container", + [ + { + "name": "unknown", + "type": "zigzag32" + } + ] + ], + "packet_update_block": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "block_priority", + "type": "varint" + }, + { + "name": "storage", + "type": "varint" + } + ] + ], + "packet_add_painting": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "direction", + "type": "zigzag32" + }, + { + "name": "title", + "type": "string" + } + ] + ], + "packet_tick_sync": [ + "container", + [ + { + "name": "request_time", + "type": "li64" + }, + { + "name": "response_time", + "type": "li64" + } + ] + ], + "packet_level_sound_event_old": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "zigzag32" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event": [ + "container", + [ + { + "name": "event_id", + "type": "zigzag32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_block_event": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "case_1", + "type": "zigzag32" + }, + { + "name": "case_2", + "type": "zigzag32" + } + ] + ], + "packet_entity_event": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_mob_effect": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "effect_id", + "type": "zigzag32" + }, + { + "name": "amplifier", + "type": "zigzag32" + }, + { + "name": "particles", + "type": "bool" + }, + { + "name": "duration", + "type": "zigzag32" + } + ] + ], + "packet_update_attributes": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "attributes", + "type": "PlayerAttributes" + }, + { + "name": "tick", + "type": "varint" + } + ] + ], + "packet_inventory_transaction": [ + "container", + [ + { + "name": "transaction", + "type": "Transaction" + } + ] + ], + "packet_mob_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "selected_slot", + "type": "u8" + }, + { + "name": "windows_id", + "type": "u8" + } + ] + ], + "packet_mob_armor_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "helmet", + "type": "Item" + }, + { + "name": "chestplate", + "type": "Item" + }, + { + "name": "leggings", + "type": "Item" + }, + { + "name": "boots", + "type": "Item" + } + ] + ], + "packet_interact": [ + "container", + [ + { + "name": "action_id", + "type": "u8" + }, + { + "name": "target_runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_block_pick_request": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "add_user_data", + "type": "bool" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_entity_pick_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "lu64" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_player_action": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "action_id", + "type": "zigzag32" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "packet_hurt_armor": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_entity_data": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "tick", + "type": "varint" + } + ] + ], + "packet_set_entity_motion": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "velocity", + "type": "vec3f" + } + ] + ], + "packet_set_entity_link": [ + "container", + [ + { + "name": "ridden_id", + "type": "zigzag64" + }, + { + "name": "rider_id", + "type": "zigzag64" + }, + { + "name": "link_type", + "type": "u8" + }, + { + "name": "unknown", + "type": "u8" + } + ] + ], + "packet_set_health": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_spawn_position": [ + "container", + [ + { + "name": "spawn_type", + "type": "zigzag32" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "unknown_coordinates", + "type": "BlockCoordinates" + } + ] + ], + "packet_animate": [ + "container", + [ + { + "name": "action_id", + "type": "zigzag32" + }, + { + "name": "runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_respawn": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "state", + "type": "u8" + }, + { + "name": "runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_container_open": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "runtime_entity_id", + "type": "zigzag64" + } + ] + ], + "packet_container_close": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "server", + "type": "bool" + } + ] + ], + "packet_player_hotbar": [ + "container", + [ + { + "name": "selected_slot", + "type": "varint" + }, + { + "name": "window_id", + "type": "u8" + }, + { + "name": "select_slot_", + "type": "bool" + } + ] + ], + "packet_inventory_content": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + }, + { + "name": "input", + "type": "ItemStacks" + } + ] + ], + "packet_inventory_slot": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "uniqueid", + "type": "zigzag32" + }, + { + "name": "item", + "type": "Item" + } + ] + ], + "packet_container_set_data": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "property", + "type": "zigzag32" + }, + { + "name": "value", + "type": "zigzag32" + } + ] + ], + "packet_crafting_data": [ + "container", + [ + { + "name": "recipes", + "type": "Recipes" + }, + { + "name": "potion_type_recipes", + "type": "PotionTypeRecipes" + }, + { + "name": "potion_container_recipes", + "type": "PotionContainerChangeRecipes" + }, + { + "name": "is_clean", + "type": "bool" + } + ] + ], + "packet_crafting_event": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "recipe_type", + "type": "zigzag32" + }, + { + "name": "recipe_id", + "type": "uuid" + }, + { + "name": "input", + "type": "ItemStacks" + }, + { + "name": "result", + "type": "ItemStacks" + } + ] + ], + "packet_gui_data_pick_item": [ + "container", + [] + ], + "packet_adventure_settings": [ + "container", + [ + { + "name": "flags", + "type": "varint" + }, + { + "name": "command_permission", + "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + } + ] + ], + "packet_block_entity_data": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "namedtag", + "type": "nbt" + } + ] + ], + "packet_player_input": [ + "container", + [ + { + "name": "motion_x", + "type": "lf32" + }, + { + "name": "motion_z", + "type": "lf32" + }, + { + "name": "jumping", + "type": "bool" + }, + { + "name": "sneaking", + "type": "bool" + } + ] + ], + "packet_level_chunk": [ + "container", + [ + { + "name": "chunk_x", + "type": "zigzag32" + }, + { + "name": "chunk_z", + "type": "zigzag32" + }, + { + "name": "sub_chunk_count", + "type": "varint" + }, + { + "name": "cache_enabled", + "type": "bool" + } + ] + ], + "packet_set_commands_enabled": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_set_difficulty": [ + "container", + [ + { + "name": "difficulty", + "type": "varint" + } + ] + ], + "packet_change_dimension": [ + "container", + [ + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "respawn", + "type": "bool" + } + ] + ], + "packet_set_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "zigzag32" + } + ] + ], + "packet_player_list": [ + "container", + [ + { + "name": "records", + "type": "PlayerRecords" + } + ] + ], + "packet_simple_event": [ + "container", + [ + { + "name": "event_type", + "type": "lu16" + } + ] + ], + "packet_spawn_experience_orb": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ], + "packet_clientbound_map_item_data_": [ + "container", + [ + { + "name": "mapinfo", + "type": "MapInfo" + } + ] + ], + "packet_map_info_request": [ + "container", + [ + { + "name": "map_id", + "type": "zigzag64" + } + ] + ], + "packet_request_chunk_radius": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_chunk_radius_update": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_item_frame_drop_item": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + } + ] + ], + "packet_game_rules_changed": [ + "container", + [ + { + "name": "rules", + "type": "GameRules" + } + ] + ], + "packet_camera": [ + "container", + [ + { + "name": "unknown1", + "type": "zigzag64" + }, + { + "name": "unknown2", + "type": "zigzag64" + } + ] + ], + "packet_boss_event": [ + "container", + [ + { + "name": "boss_entity_id", + "type": "zigzag64" + }, + { + "name": "event_type", + "type": "varint" + } + ] + ], + "packet_show_credits": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "status", + "type": "zigzag32" + } + ] + ], + "packet_available_commands": [ + "container", + [] + ], + "packet_command_request": [ + "container", + [ + { + "name": "command", + "type": "string" + }, + { + "name": "command_type", + "type": "varint" + }, + { + "name": "unknown_uuid", + "type": "uuid" + }, + { + "name": "request_id", + "type": "string" + }, + { + "name": "unknown", + "type": "bool" + } + ] + ], + "packet_command_block_update": [ + "container", + [ + { + "name": "is_block", + "type": "bool" + } + ] + ], + "packet_command_output": [ + "container", + [] + ], + "packet_update_trade": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "window_type", + "type": "u8" + }, + { + "name": "unknown0", + "type": "varint" + }, + { + "name": "unknown1", + "type": "varint" + }, + { + "name": "unknown2", + "type": "varint" + }, + { + "name": "is_willing", + "type": "bool" + }, + { + "name": "trader_entity_id", + "type": "zigzag64" + }, + { + "name": "player_entity_id", + "type": "zigzag64" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "namedtag", + "type": "nbt" + } + ] + ], + "packet_update_equipment": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "window_type", + "type": "u8" + }, + { + "name": "unknown", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "namedtag", + "type": "nbt" + } + ] + ], + "packet_resource_pack_data_info": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "max_chunk_size", + "type": "lu32" + }, + { + "name": "chunk_count", + "type": "lu32" + }, + { + "name": "compressed_package_size", + "type": "lu64" + }, + { + "name": "hash", + "type": "ByteArray" + }, + { + "name": "is_premium", + "type": "bool" + }, + { + "name": "pack_type", + "type": "u8" + } + ] + ], + "packet_resource_pack_chunk_data": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + }, + { + "name": "progress", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_resource_pack_chunk_request": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + } + ] + ], + "packet_transfer": [ + "container", + [ + { + "name": "server_address", + "type": "string" + }, + { + "name": "port", + "type": "lu16" + } + ] + ], + "packet_play_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "volume", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + } + ] + ], + "packet_stop_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "stop_all", + "type": "bool" + } + ] + ], + "packet_set_title": [ + "container", + [ + { + "name": "type", + "type": "zigzag32" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "fade_in_time", + "type": "zigzag32" + }, + { + "name": "stay_time", + "type": "zigzag32" + }, + { + "name": "fade_out_time", + "type": "zigzag32" + } + ] + ], + "packet_add_behavior_tree": [ + "container", + [ + { + "name": "behaviortree", + "type": "string" + } + ] + ], + "packet_structure_block_update": [ + "container", + [] + ], + "packet_show_store_offer": [ + "container", + [ + { + "name": "unknown0", + "type": "string" + }, + { + "name": "unknown1", + "type": "bool" + } + ] + ], + "packet_purchase_receipt": [ + "container", + [] + ], + "packet_player_skin": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "skin", + "type": "Skin" + }, + { + "name": "skin_name", + "type": "string" + }, + { + "name": "old_skin_name", + "type": "string" + }, + { + "name": "is_verified", + "type": "bool" + } + ] + ], + "packet_sub_client_login": [ + "container", + [] + ], + "packet_initiate_web_socket_connection": [ + "container", + [ + { + "name": "server", + "type": "string" + } + ] + ], + "packet_set_last_hurt_by": [ + "container", + [ + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_book_edit": [ + "container", + [] + ], + "packet_npc_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "unknown0", + "type": "u8" + }, + { + "name": "unknown1", + "type": "string" + }, + { + "name": "unknown2", + "type": "u8" + } + ] + ], + "packet_photo_transfer": [ + "container", + [ + { + "name": "file_name", + "type": "string" + }, + { + "name": "image_data", + "type": "string" + }, + { + "name": "unknown2", + "type": "string" + } + ] + ], + "packet_modal_form_request": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_modal_form_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_server_settings_request": [ + "container", + [] + ], + "packet_server_settings_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_show_profile": [ + "container", + [ + { + "name": "xuid", + "type": "string" + } + ] + ], + "packet_set_default_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "varint" + } + ] + ], + "packet_remove_objective": [ + "container", + [ + { + "name": "objective_name", + "type": "string" + } + ] + ], + "packet_set_display_objective": [ + "container", + [ + { + "name": "display_slot", + "type": "string" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "criteria_name", + "type": "string" + }, + { + "name": "sort_order", + "type": "zigzag32" + } + ] + ], + "packet_set_score": [ + "container", + [ + { + "name": "entries", + "type": "ScoreEntries" + } + ] + ], + "packet_lab_table": [ + "container", + [ + { + "name": "useless_byte", + "type": "u8" + }, + { + "name": "lab_table_x", + "type": "varint" + }, + { + "name": "lab_table_y", + "type": "varint" + }, + { + "name": "lab_table_z", + "type": "varint" + }, + { + "name": "reaction_type", + "type": "u8" + } + ] + ], + "packet_update_block_synced": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "block_priority", + "type": "varint" + }, + { + "name": "data_layer_id", + "type": "varint" + }, + { + "name": "unknown0", + "type": "varint" + }, + { + "name": "unknown1", + "type": "varint" + } + ] + ], + "packet_move_entity_delta": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "flags", + "type": "lu16" + } + ] + ], + "packet_set_scoreboard_identity": [ + "container", + [ + { + "name": "entries", + "type": "ScoreboardIdentityEntries" + } + ] + ], + "packet_set_local_player_as_initialized": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_update_soft_enum": [ + "container", + [] + ], + "packet_network_stack_latency": [ + "container", + [ + { + "name": "timestamp", + "type": "lu64" + }, + { + "name": "unknown_flag", + "type": "u8" + } + ] + ], + "packet_script_custom_event": [ + "container", + [ + { + "name": "event_name", + "type": "string" + }, + { + "name": "event_data", + "type": "string" + } + ] + ], + "packet_spawn_particle_effect": [ + "container", + [ + { + "name": "dimension_id", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "particle_name", + "type": "string" + } + ] + ], + "packet_available_entity_identifiers": [ + "container", + [ + { + "name": "namedtag", + "type": "nbt" + } + ] + ], + "packet_level_sound_event_v2": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_network_chunk_publisher_update": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "radius", + "type": "varint" + } + ] + ], + "packet_biome_definition_list": [ + "container", + [ + { + "name": "namedtag", + "type": "nbt" + } + ] + ], + "packet_level_sound_event": [ + "container", + [ + { + "name": "sound_id", + "type": "varint" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event_generic": [ + "container", + [] + ], + "packet_lectern_update": [ + "container", + [] + ], + "packet_video_stream_connect": [ + "container", + [ + { + "name": "server_uri", + "type": "string" + }, + { + "name": "frame_send_frequency", + "type": "lf32" + }, + { + "name": "action", + "type": "u8" + }, + { + "name": "resolution_x", + "type": "li32" + }, + { + "name": "resolution_y", + "type": "li32" + } + ] + ], + "packet_client_cache_status": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_on_screen_texture_animation": [ + "container", + [] + ], + "packet_map_create_locked_copy": [ + "container", + [] + ], + "packet_structure_template_data_export_request": [ + "container", + [] + ], + "packet_structure_template_data_export_response": [ + "container", + [] + ], + "packet_update_block_properties": [ + "container", + [ + { + "name": "namedtag", + "type": "nbt" + } + ] + ], + "packet_client_cache_blob_status": [ + "container", + [] + ], + "packet_client_cache_miss_response": [ + "container", + [] + ], + "packet_network_settings": [ + "container", + [ + { + "name": "unknown", + "type": "u8" + }, + { + "name": "compression_threshold", + "type": "u8" + } + ] + ], + "packet_creative_content": [ + "container", + [ + { + "name": "input", + "type": "ItemStacks" + } + ] + ], + "packet_player_enchant_options": [ + "container", + [ + { + "name": "enchant_options", + "type": "EnchantOptions" + } + ] + ], + "packet_item_stack_request": [ + "container", + [ + { + "name": "requests", + "type": "ItemStackRequests" + } + ] + ], + "packet_item_stack_response": [ + "container", + [ + { + "name": "responses", + "type": "ItemStackResponses" + } + ] + ], + "packet_update_player_game_type": [ + "container", + [] + ], + "packet_packet_violation_warning": [ + "container", + [ + { + "name": "violation_type", + "type": "zigzag32" + }, + { + "name": "severity", + "type": "zigzag32" + }, + { + "name": "packet_id", + "type": "zigzag32" + }, + { + "name": "reason", + "type": "string" + } + ] + ], + "packet_item_component": [ + "container", + [ + { + "name": "entries", + "type": "ItemComponentList" + } + ] + ], + "packet_filter_text_packet": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "from_server", + "type": "bool" + } + ] + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json index 480db34..12fc42f 100644 --- a/package.json +++ b/package.json @@ -18,14 +18,19 @@ "@babel/preset-env": "^7.5.4", "@babel/preset-typescript": "^7.3.3", "@babel/register": "^7.4.4", - "asn1": "^0.2.3", + "@jsprismarine/jsbinaryutils": "^2.1.8", + "@jsprismarine/raknet": "github:extremeheat/raknet", + "aes-js": "^3.1.2", + "asn1": "^0.2.4", "bn.js": "^4.11.4", - "jwt-simple": "^0.5.0", + "ec-pem": "^0.18.0", + "jsonwebtoken": "^8.5.1", + "jwt-simple": "^0.5.6", "lodash.merge": "^4.4.0", - "prismarine-nbt": "^1.0.0", - "protodef": "^1.2.3", + "prismarine-nbt": "github:extremeheat/prismarine-nbt#le", + "protodef": "github:extremeheat/node-protodef#big", "raknet": "git+https://github.com/mhsjlw/node-raknet.git#master", - "uuid-1345": "^0.99.6" + "uuid-1345": "^0.99.7" }, "devDependencies": { "@babel/cli": "^7.5.0", diff --git a/src/BatchPacket.js b/src/BatchPacket.js new file mode 100644 index 0000000..5cffd28 --- /dev/null +++ b/src/BatchPacket.js @@ -0,0 +1,86 @@ +const BinaryStream = require('@jsprismarine/jsbinaryutils').default +const Zlib = require('zlib'); + +const NETWORK_ID = 0xfe + +// This is not a MCPE packet, it's a wrapper that contains compressed batched packets +class BatchPacket { + + constructor(stream) { + this.payload = Buffer.alloc(0) + this.stream = stream || new BinaryStream() + this.packets = [] + this.compressionLevel = 7 + } + + init() { + + } + + decode() { + // Read header + const pid = this.stream.readByte(); + if (!pid === NETWORK_ID) { + throw new Error(`Batch ID mismatch: is ${BatchPacket.NETWORK_ID}, got ${pid}`) // this is not a BatchPacket + } + + // Decode the payload + try { + this.payload = Zlib.inflateRawSync(this.stream.readRemaining(), { + chunkSize: 1024 * 1024 * 2 + }); + } catch (e) { + console.error(e) + console.debug(`[bp] Error decompressing packet ${pid}`) + } + } + + encode() { + const buf = this.stream.getBuffer() + console.log('Encoding payload', buf) + const def = Zlib.deflateRawSync(buf, { level: this.compressionLevel }) + const ret = Buffer.concat([Buffer.from([0xfe]), def]) + console.log('Compressed', ret) + return ret + } + + encodePayload() { + } + + addEncoded(packet) { + + } + + addEncodedPacket(packet) { + this.stream.writeUnsignedVarInt(packet.byteLength) + this.stream.append(packet) + // this.payload = Buffer.concat([this.payload, stream.getBuffer()]); + } + + getPackets() { + const stream = new BinaryStream() + stream.buffer = this.payload + const packets = [] + while (!stream.feof()) { + const length = stream.readUnsignedVarInt() + const buffer = stream.read(length) + packets.push(buffer) + } + + return packets + } + + static getPackets(stream) { + stream.buffer = this.payload + const packets = [] + while (!stream.feof()) { + const length = stream.readUnsignedVarInt() + const buffer = stream.read(length) + packets.push(buffer) + } + + return packets + } +} + +module.exports = BatchPacket \ No newline at end of file diff --git a/src/auth/constants.js b/src/auth/constants.js new file mode 100644 index 0000000..3d04d67 --- /dev/null +++ b/src/auth/constants.js @@ -0,0 +1,4 @@ +module.exports = { + PUBLIC_KEY: 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V', + secret_key: 'nwOn35gXIfEfgZPIrjNJ+cAxODD/XIpjs3YG7FO1pmwbzpRSlac', +} diff --git a/src/auth/encrypt.js b/src/auth/encrypt.js new file mode 100644 index 0000000..e5aca37 --- /dev/null +++ b/src/auth/encrypt.js @@ -0,0 +1,232 @@ +const crypto = require('crypto') +const JWT = require('jsonwebtoken') +const constants = require('./constants') +const { Ber } = require('asn1') +const ec_pem = require('ec-pem'); + +// function Encrypt(client, options) { +// this.startClientboundEncryption = (pubKeyBuf) => { + +// } +// client.on('start_encrypt', this.startClientboundEncryption) +// } + +// module.exports = Encrypt + + +// Server -> Client : sent right after the client sends us a LOGIN_PACKET so +// we can start the encryption process +// @param {key} - The key from the client Login Packet final JWT chain +function startClientboundEncryption(pubKeyBuf) { + // create our ecdh keypair + const type = 'secp256k1' + const alice = crypto.createECDH(type) + const aliceKey = alice.generateKeys() + const alicePublicKey = aliceKey.toString('base64') + const alicePrivateKey = mcPubKeyToPem(alice.getPrivateKey('base64')) + // get our secret key hex encoded + // const aliceSecret = alice.computeSecret(pubKeyBuf, null, 'hex') + + // (yawkat:) + // From the public key of the remote and the private key of the local, + // a shared secret is generated using ECDH. The secret key bytes are + // then computed as sha256(server_token + shared_secret). These secret + // key bytes are 32 bytes long. + const salt = Buffer.from('', 'utf-8') + let secret = crypto.createHash('sha256').update(Buffer.concat([salt, pubKeyBuf])).digest() + console.log('alice', alicePrivateKey) + const pem = mcPubKeyToPem(alice.getPrivateKey().toString('base64')) + console.log('pem', pem) + + const token = JWT.sign({ + salt, + signedToken: alicePublicKey + }, pem, { algorithm: 'ES384' }) + + console.log('Token', token) + + // get our Secret Bytes from the secret key + + + // alice.setPrivateKey( + // crypto.createHash('sha256').update('alice', 'utf8').digest() + // ) + + // using (var sha = SHA256.Create()) + // { + // secret = sha.ComputeHash(secretPrepend.Concat(agreement.CalculateAgreement(remotePublicKey).ToByteArrayUnsigned()).ToArray()); + // } + + + + const bob = crypto.createECDH('secp256k1'); + + + // URI x5u = URI.create(Base64.getEncoder().encodeToString(serverKeyPair.getPublic().getEncoded())); + + // JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().claim("salt", Base64.getEncoder().encodeToString(token)).build(); + // SignedJWT jwt = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.ES384).x509CertURL(x5u).build(), claimsSet); + + // signJwt(jwt, (ECPrivateKey) serverKeyPair.getPrivate()); + + // return jwt; +} + +function testECDH() { + const crypto = require('crypto') + const alice = crypto.createECDH('secp256k1') + const bob = crypto.createECDH('secp256k1') + + // Note: This is a shortcut way to specify one of Alice's previous private + // keys. It would be unwise to use such a predictable private key in a real + // application. + alice.setPrivateKey( + crypto.createHash('sha256').update('alice', 'utf8').digest() + ); + + // Bob uses a newly generated cryptographically strong + // pseudorandom key pair bob.generateKeys(); + + const alice_secret = alice.computeSecret(bob.getPublicKey(), null, 'hex') + const bob_secret = bob.computeSecret(alice.getPublicKey(), null, 'hex') + + // alice_secret and bob_secret should be the same shared secret value + console.log(alice_secret === bob_secret) +} + +function testECDH2() { + const type = 'secp256k1' + const alice = crypto.createECDH(type); + const aliceKey = alice.generateKeys(); + + // Generate Bob's keys... + const bob = crypto.createECDH(type); + const bobKey = bob.generateKeys(); + + console.log("\nAlice private key:\t", alice.getPrivateKey().toString('hex')); + console.log("Alice public key:\t", aliceKey.toString('hex')) + + console.log("\nBob private key:\t", bob.getPrivateKey().toString('hex')); + console.log("Bob public key:\t", bobKey.toString('hex')); + + + // Exchange and generate the secret... + const aliceSecret = alice.computeSecret(bobKey); + const bobSecret = bob.computeSecret(aliceKey); + + console.log("\nAlice shared key:\t", aliceSecret.toString('hex')) + console.log("Bob shared key:\t\t", bobSecret.toString('hex')); + //wow it actually works?! +} + +function mcPubKeyToPem(mcPubKeyBuffer) { + console.log(mcPubKeyBuffer) + if (mcPubKeyBuffer[0] == '-') return mcPubKeyBuffer + let pem = '-----BEGIN PUBLIC KEY-----\n' + let base64PubKey = mcPubKeyBuffer.toString('base64') + const maxLineLength = 65 + while (base64PubKey.length > 0) { + pem += base64PubKey.substring(0, maxLineLength) + '\n' + base64PubKey = base64PubKey.substring(maxLineLength) + } + pem += '-----END PUBLIC KEY-----\n' + return pem +} + +function readX509PublicKey(key) { + var reader = new Ber.Reader(Buffer.from(key, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); // Hey, I'm an elliptic curve + reader.readOID(); // This contains the curve type, could be useful + return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); +} + +function testMC() { + // const pubKeyBuf = Buffer.from(constants.PUBLIC_KEY, 'base64') + // const pem = mcPubKeyToPem(pubKeyBuf) + // console.log(mcPubKeyToPem(pubKeyBuf)) + // const publicKey = crypto.createPublicKey({ key: pem, format: 'der' }) + + const pubKeyBuf = readX509PublicKey(constants.PUBLIC_KEY) + + // console.log('Mojang pub key', pubKeyBuf.toString('hex'), publicKey) + startClientboundEncryption(pubKeyBuf) +} + +function testMC2() { + // const mojangPubKeyBuf = Buffer.from('MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V', 'base64') + // const pem = mcPubKeyToPem(mojangPubKeyBuf) + // const publicKey = crypto.createPublicKey({ key: pem }) + + const publicKey = readX509PublicKey(constants.PUBLIC_KEY) + + const curve = 'secp384r1' + const alice = crypto.createECDH(curve) + // const keys = crypto.generateKeyPair('ec',) + + // const bob = crypto.generateKeyPairSync('ec', { + // namedCurve: type + // }) + // alice.setPrivateKey(bob.privateKey.export({ type: 'pkcs8', format: 'pem' })) + // alice.setPublicKey(bob.publicKey.export({ type: 'spki', format: 'pem' })) + + // console.log(bob) + + const aliceKey = alice.generateKeys() + + const alicePEM = ec_pem(alice, curve) + + const alicePEMPrivate = alicePEM.encodePrivateKey() + const alicePEMPublic = alicePEM.encodePublicKey() + + // const alicePublicKey = aliceKey.toString('base64') + // const alicePrivateKey = alice.getPrivateKey().toString('base64') + const aliceSecret = alice.computeSecret(publicKey, null, 'hex') + + console.log('Alice private key PEM', alicePEMPrivate) + console.log('Alice public key PEM', alicePEMPublic) + console.log('Alice public key', alice.getPublicKey('base64')) + console.log('Alice secret key', aliceSecret) + + + var sign = crypto.createSign('RSA-SHA256') + sign.write('something') + sign.end() +// // const pem2 = +// // `-----BEGIN PRIVATE KEY----- +// // ${alice.getPrivateKey('base64')} +// // -----END PRIVATE KEY-----` + +// console.log('PEM', bob.privateKey) + const sig = sign.sign(alicePEMPrivate, 'hex') + console.log('Signature', sig) + + + + const token = JWT.sign({ + salt: 'HELLO', + signedToken: alice.getPublicKey('base64') + }, alicePEMPrivate, { algorithm: 'ES384' }) + console.log('Token', token) + + const verified = JWT.verify(token, alicePEMPublic, { algorithms: 'ES384' }) + console.log('Verified!', verified) +} + +function testMC3() { + var Ber = require('asn1').Ber; + var reader = new Ber.Reader(new Buffer(constants.PUBLIC_KEY, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); // Hey, I'm an elliptic curve + reader.readOID(); // This contains the curve type, could be useful + var pubKey = reader.readString(Ber.BitString, true).slice(1); + var server = crypto.createECDH('secp384r1'); + server.generateKeys(); + console.log(server.computeSecret(pubKey)); + +} + +// testECDH2() +testMC2() \ No newline at end of file diff --git a/src/auth/encryptTest.js b/src/auth/encryptTest.js new file mode 100644 index 0000000..d1d83ef --- /dev/null +++ b/src/auth/encryptTest.js @@ -0,0 +1,88 @@ +const crypto = require('crypto') +const JWT = require('jsonwebtoken') +const constants = require('./constants') +const { Ber } = require('asn1') +const ec_pem = require('ec-pem') + +function readX509PublicKey(key) { + var reader = new Ber.Reader(Buffer.from(key, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); // Hey, I'm an elliptic curve + reader.readOID(); // This contains the curve type, could be useful + return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); +} + +function writeX509PublicKey(key) { + var writer = new Ber.Writer(); + writer.startSequence(); + writer.startSequence(); + writer.writeOID("1.2.840.10045.2.1"); + writer.writeOID("1.3.132.0.34"); + writer.endSequence(); + writer.writeBuffer(Buffer.concat([Buffer.from([0x00]), key]), Ber.BitString); + writer.endSequence(); + return writer.buffer.toString("base64"); +} + +function test(pubKey = constants.PUBLIC_KEY) { + const publicKey = readX509PublicKey(pubKey) + const curve = 'secp384r1' + const alice = crypto.createECDH(curve) + const aliceKey = alice.generateKeys() + const alicePEM = ec_pem(alice, curve) + const alicePEMPrivate = alicePEM.encodePrivateKey() + const alicePEMPublic = alicePEM.encodePublicKey() + const aliceSecret = alice.computeSecret(publicKey, null, 'hex') + console.log('Alice private key PEM', alicePEMPrivate) + console.log('Alice public key PEM', alicePEMPublic) + console.log('Alice public key', alice.getPublicKey('hex')) + console.log('Alice secret key', aliceSecret) + + // Test signing manually + const sign = crypto.createSign('RSA-SHA256') + sign.write('🧂') + sign.end() + const sig = sign.sign(alicePEMPrivate, 'hex') + console.log('Signature', sig) + + // Test JWT sign+verify + const x509 = writeX509PublicKey(alice.getPublicKey()) + const token = JWT.sign({ + salt: 'HELLO', + signedToken: alice.getPublicKey('base64') + }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } }) + console.log('Encoded JWT', token) + // send the jwt to the client... + + const verified = JWT.verify(token, alicePEMPublic, { algorithms: 'ES384' }) + console.log('Decoded JWT', verified) + // Good +} + +/** + * Alice private key PEM -----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDBGgHZwH3BzieyJrdrVTVLmrEoUxpDUSqSzS98lobTXeUxJR/OmywPV +57I8YtnsJlCgBwYFK4EEACKhZANiAATjvTRgjsxKruO7XbduSQoHeR/6ouIm4Rmc +La9EkSpLFpuYZfsdtq9Vcf2t3Q3+jIbXjD/wNo97P4Hr5ghXG8sCVV7jpqadOF8j +SzyfajLGfX9mkS5WWLAg+dpi/KiEo/g= +-----END EC PRIVATE KEY----- + +Alice public key PEM -----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4700YI7MSq7ju123bkkKB3kf+qLiJuEZ +nC2vRJEqSxabmGX7HbavVXH9rd0N/oyG14w/8DaPez+B6+YIVxvLAlVe46amnThf +I0s8n2oyxn1/ZpEuVliwIPnaYvyohKP4 +-----END PUBLIC KEY----- + +Alice public key 04e3bd34608ecc4aaee3bb5db76e490a07791ffaa2e226e1199c2daf44912a4b169b9865fb1db6af5571fdaddd0dfe8c86d78c3ff0368f7b3f81ebe608571bcb02555ee3a6a69d385f234b3c9f6a32c67d7f66912e5658b020f9da62fca884a3f8 +Alice secret key 76feb5d420b33907c4841a74baa707b717a29c021b17b6662fd46dba3227cac3e256eee9e890edb0308f66a3119b4914 +Signature 3066023100d5ea70b8fc5e441c5e93d9f7dcde031f54291011c950a4aa8625ea9b27f7c798a8bc4de40baf35d487a05db6b5c628c6023100ae06cc2ea65db77138163c546ccf13933faae3d91bd6aa7108b99539cdb1c86f1e8a3704cb099f0b00eebed4ee75ccb2 +Encoded JWT eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzYWx0IjoiSEVMTE8iLCJzaWduZWRUb2tlbiI6IkJPTzlOR0NPekVxdTQ3dGR0MjVKQ2dkNUgvcWk0aWJoR1p3dHIwU1JLa3NXbTVobCt4MjJyMVZ4L2EzZERmNk1odGVNUC9BMmozcy9nZXZtQ0ZjYnl3SlZYdU9tcHAwNFh5TkxQSjlxTXNaOWYyYVJMbFpZc0NENTJtTDhxSVNqK0E9PSIsImlhdCI6MTYxMTc4MDYwNX0._g8k086U7nD-Tthn8jGWuuM3Q4EfhgqCfFA1Q5ePmjqhqMHOJvmrCz6tWsCytr2i-a2M51fb9K_YDAHbZ66Kos9ZkjF4Tqz5fPS880fM9woZ_1xjh7nGcOQ6sbY81zyi +Decoded JWT { + salt: 'HELLO', + signedToken: 'BOO9NGCOzEqu47tdt25JCgd5H/qi4ibhGZwtr0SRKksWm5hl+x22r1Vx/a3dDf6MhteMP/A2j3s/gevmCFcbywJVXuOmpp04XyNLPJ9qMsZ9f2aRLlZYsCD52mL8qISj+A==', + iat: 1611780605 +} + */ + +test() \ No newline at end of file diff --git a/src/auth/encryption.js b/src/auth/encryption.js new file mode 100644 index 0000000..9529fc0 --- /dev/null +++ b/src/auth/encryption.js @@ -0,0 +1,102 @@ +const JWT = require('jsonwebtoken') +const crypto = require('crypto') +const constants = require('./constants') +const { Ber } = require('asn1') +const ec_pem = require('ec-pem') + +const SALT = 'ABC' + +function Encrypt(client, options) { + function startClientboundEncryption(publicKey) { + console.warn('[encrypt] Pub key base64: ', publicKey) + const pubKeyBuf = readX509PublicKey(publicKey.key) + + const curve = 'secp384r1' + const alice = crypto.createECDH(curve) + alice.generateKeys() + const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 + const alicePEMPrivate = alicePEM.encodePrivateKey() + // Shared secret from bob's public key + our private key + client.sharedSecret = alice.computeSecret(pubKeyBuf) + + // Secret hash we use for packet encryption: + // From the public key of the remote and the private key + // of the local, a shared secret is generated using ECDH. + // The secret key bytes are then computed as + // sha256(server_token + shared_secret). These secret key + // bytes are 32 bytes long. + const secretHash = crypto.createHash('sha256') + secretHash.update(SALT) + secretHash.update(client.sharedSecret) + + client.secretKeyBytes = secretHash.digest() + + const x509 = writeX509PublicKey(alice.getPublicKey()) + const token = JWT.sign({ + salt: toBase64(SALT), + signedToken: alice.getPublicKey('base64') + }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } }) + + client.write('server_to_client_handshake', { + token: token + }) + + // The encryption scheme is AES/CFB8/NoPadding with the + // secret key being the result of the sha256 above and + // the IV being the first 16 bytes of this secret key. + const initial = client.secretKeyBytes.slice(0, 16) + client.startEncryption(initial) + } + + function startClientCiphers() { + + var decipher = crypto.createDecipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0, 16)) + + let customPackets = JSON.parse(JSON.stringify(require("../data/protocol"))) + + customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe_encrypted'] = 'restBuffer' + customPackets['types']['encapsulated_packet'][1][0]['type'][1]['mappings']['0xfe'] = 'mcpe_encrypted' + client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol, customPackets).types) + + client.encryptionEnabled = true + + client.on("mcpe_encrypted", packet => { + decipher.write(packet); + }); + + client.cipher = crypto.createCipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0, 16)); + } + + client.on('server.client_handshake', startClientboundEncryption) +} + +function toBase64(string) { + return Buffer.from(string).toString('base64') +} + +function readX509PublicKey(key) { + var reader = new Ber.Reader(Buffer.from(key, "base64")); + reader.readSequence(); + reader.readSequence(); + reader.readOID(); // Hey, I'm an elliptic curve + reader.readOID(); // This contains the curve type, could be useful + return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); +} + +function writeX509PublicKey(key) { + var writer = new Ber.Writer(); + writer.startSequence(); + writer.startSequence(); + writer.writeOID("1.2.840.10045.2.1"); + writer.writeOID("1.3.132.0.34"); + writer.endSequence(); + writer.writeBuffer(Buffer.concat([Buffer.from([0x00]), key]), Ber.BitString); + writer.endSequence(); + return writer.buffer.toString("base64"); +} + +module.exports = { + readX509PublicKey, + writeX509PublicKey, + Encrypt +} \ No newline at end of file diff --git a/src/auth/jwt.js b/src/auth/jwt.js new file mode 100644 index 0000000..155f7fb --- /dev/null +++ b/src/auth/jwt.js @@ -0,0 +1,104 @@ +const JWT = require('jsonwebtoken') +const constants = require('./constants') +const fs = require('fs') +const { decode } = require('jwt-simple') +// import jwt from 'jwt-simple'; +// const jwt = require('jwt-simple') + +// 💗 web archive +// https://web.archive.org/web/20180917171505if_/https://confluence.yawk.at/display/PEPROTOCOL/Game+Packets#GamePackets-Login + +function mcPubKeyToPem(mcPubKeyBuffer) { + console.log(mcPubKeyBuffer) + if (mcPubKeyBuffer[0] == '-') return mcPubKeyBuffer + let pem = '-----BEGIN PUBLIC KEY-----\n' + let base64PubKey = mcPubKeyBuffer.toString('base64') + const maxLineLength = 65 + while (base64PubKey.length > 0) { + pem += base64PubKey.substring(0, maxLineLength) + '\n' + base64PubKey = base64PubKey.substring(maxLineLength) + } + pem += '-----END PUBLIC KEY-----\n' + return pem +} + +function getX5U(token) { + const [header] = token.split('.') + const hdec = Buffer.from(header, 'base64').toString('utf-8') + const hjson = JSON.parse(hdec) + return hjson.x5u +} + +function verifyAuth(chain) { + let data = {} + + // There are three JWT tokens sent to us, one signed by the client + // one signed by Mojang with the Mojang token we have and another one + // from Xbox with addition user profile data + // We verify that at least one of the tokens in the chain has been properly + // signed by Mojang by checking the x509 public key in the JWT headers + let didVerify = false + + let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it + let finalKey = null + console.log(pubKey) + for (var token of chain) { + // const decoded = jwt.decode(token, pubKey, 'ES384') + // console.log('Decoding...', token) + const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + // console.log('Decoded...') + console.log('Decoded', decoded) + + // Check if signed by Mojang key + const x5u = getX5U(token) + if (x5u == constants.PUBLIC_KEY && !data.extraData?.XUID) { + didVerify = true + console.log('verified with mojang key!', x5u) + } + + pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u + finalKey = decoded.identityPublicKey || finalKey // non pem + data = { ...data, ...decoded } + } + // console.log('Result', data) + + return { key: finalKey, data } +} + +function verifySkin(publicKey, token) { + // console.log('token', token) + const pubKey = mcPubKeyToPem(publicKey) + + const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + + return decoded +} + +function decodeLoginJWT(authTokens, skinTokens) { + const { key, data } = verifyAuth(authTokens) + const skinData = verifySkin(key, skinTokens) + return { key, userData: data, skinData } +} + +function test() { + const loginPacket = require('./login.json') + + // console.log(loginPacket) + const authChains = JSON.parse(loginPacket.data.chain) + const skinChain = loginPacket.data.clientData + + try { + var { data, chain } = decodeLoginJWT(authChains.chain, skinChain) + } catch (e) { + console.error(e) + throw new Error('Failed to verify user') + } + + console.log('Authed') + + // console.log(loginPacket) +} + +module.exports = { decodeLoginJWT } + +// test() \ No newline at end of file diff --git a/src/auth/jwtTest.js b/src/auth/jwtTest.js new file mode 100644 index 0000000..acf5307 --- /dev/null +++ b/src/auth/jwtTest.js @@ -0,0 +1,49 @@ +function test() { + const chain = require('./sampleChain.json').chain + + let data = {} + + // There are three JWT tokens sent to us, one signed by the client + // one signed by Mojang with the Mojang token we have and another one + // from Xbox with addition user profile data + // We verify that at least one of the tokens in the chain has been properly + // signed by Mojang by checking the x509 public key in the JWT headers + let didVerify = false + + let pubKey = mcPubKeyToPem(constants.PUBLIC_KEY_NEW) + console.log(pubKey) + for (var token of chain) { + // const decoded = jwt.decode(token, pubKey, 'ES384') + console.log('Decoding...', token) + const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + console.log('Decoded...') + console.log('Decoded', decoded) + + // Check if signed by Mojang key + const [header] = token.split('.') + const hdec = Buffer.from(header, 'base64').toString('utf-8') + const hjson = JSON.parse(hdec) + if (hjson.x5u == constants.PUBLIC_KEY && !data.extraData?.XUID) { + didVerify = true + console.log('verified with mojang key!', hjson.x5u) + } + + pubKey = mcPubKeyToPem(decoded.identityPublicKey) + data = { ...data, ...decoded } + } + console.log('Result', data) +} + +function test2() { + const chain = require('./login.json') + const token = chain.data.clientData + // console.log(token) + + const pubKey = mcPubKeyToPem(constants.CDATA_PUBLIC_KEY) + + const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + + // console.log('Decoded', decoded) + + fs.writeFileSync('clientData.json', JSON.stringify(decoded)) +} diff --git a/src/serverTest.js b/src/serverTest.js new file mode 100644 index 0000000..df29724 --- /dev/null +++ b/src/serverTest.js @@ -0,0 +1,226 @@ +console.log('IMPORTING') +const BinaryStream = require('@jsprismarine/jsbinaryutils').default +const Listener = require('@jsprismarine/raknet/listener') +const { ProtoDef, Parser, Serializer } = require('protodef') +const BatchPacket = require('./BatchPacket') +const { EventEmitter } = require('events') +const fs = require('fs') +const cipher = require('./transforms/encryption') +const { Encrypt } = require('./auth/encryption') + +const { decodeLoginJWT } = require('./auth/jwt') +const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') +console.log('IMPORTED') +// const Zlib = require('zlib'); + +var protocol = require('../data/newproto.json').types; + +function createProtocol() { + var proto = new ProtoDef(); + proto.addTypes(require('./datatypes/minecraft')); + proto.addTypes(protocol); + + return proto; +} + +function createSerializer() { + var proto = createProtocol() + return new Serializer(proto, 'mcpe_packet'); +} + +function createDeserializer() { + var proto = createProtocol() + return new Parser(proto, 'mcpe_packet'); +} + +class Player extends EventEmitter { + constructor(server, connection, options) { + super() + this.server = server + this.connection = connection + Encrypt(this, server, options) + } + + // TODO: Move this to a protodef native type + onLogin(packet) { + let dataProto = new ProtoDef() + dataProto.addType('data_chain', ['container', [{ + 'name': 'chain', + 'type': ['pstring', { + 'countType': 'li32' + }] + }, { + 'name': 'clientData', + 'type': ['pstring', { + 'countType': 'li32' + }] + }]]) + + //FIXME: Xbox & Non-Xbox support + console.log(packet); + let pbody = packet.data.params.payload + let body = dataProto.parsePacketBuffer('data_chain', pbody) + console.log('Body', body) + + fs.writeFileSync('login.json', JSON.stringify(body)) + + // Parse login data + const authChain = JSON.parse(body.data.chain) + const skinChain = body.data.clientData + + try { + var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) + } catch (e) { + console.error(e) + throw new Error('Failed to verify user') + } + console.log('Verified user', 'got pub key', key, userData) + + this.emit('join', { + user: userData.extraData + }) + this.emit('server.client_handshake', { + key + }) + } + + startEncryption(iv) { + this.encryptionEnabled = true + + // this.cipher = cipher.createCipher(client.secretKeyBytes, iv) + // this.decipher = cipher.createDecipher(client.secretKeyBytes, iv) + + this.decrypt = cipher.createDecryptor(this, iv) + this.encrypt = cipher.createDecryptor(this, iv) + } + + write(name, params) { + console.log('Need to encode', name, params) + const batch = new BatchPacket() + const packet = this.server.serializer.createPacketBuffer({ name, params }) + batch.addEncodedPacket(packet) + const buf = batch.encode() + // send to raknet + const sendPacket = new EncapsulatedPacket(); + sendPacket.reliability = 0; + sendPacket.buffer = buf + + this.connection.addEncapsulatedToQueue(sendPacket, 1) + this.connection.sendQueue() + } + + sendDecryptedBatch(batch) { + + } + + sendEncryptedBatch(batch) { + + } + + onDecryptedPacket = (buf) => { + console.log('Decrypted', buf) + } + + readPacket(packet) { + console.log('packet', packet) + const des = this.server.deserializer.parsePacketBuffer(packet) + console.log(des) + switch (des.data.name) { + case 'login': + console.log(des) + this.onLogin(des) + default: + this.emit(des.data.name, des.data.params) + } + } + + handle(buffer) { // handle encapsulated + if (buffer[0] == 0xfe) { // wrapper + + if (this.encryptionEnabled) { + this.decrypt(buffer.slice(1)) + } else { + const stream = new BinaryStream(buffer) + const batch = new BatchPacket(stream) + batch.decode() + const packets = batch.getPackets() + console.log('Reading ', packets.length, 'packets') + for (var packet of packets) { + this.readPacket(packet) + } + } + } + } +} + +class Server extends EventEmitter { + constructor(options = {}) { + // const customTypes = require('./datatypes/minecraft') + // this.batchProto = new ProtoDef() + // this.batchProto.addTypes(customTypes) + // this.batchProto.addType('insideBatch', ['endOfArray', { + // 'type': ['buffer', { + // 'countType': 'varint', + // }] + // }]) + + super() + + this.serializer = createSerializer() + this.deserializer = createDeserializer() + + this.clients = {} + } + + getAddrHash(inetAddr) { + return inetAddr.address + '/' + inetAddr.port + } + + onOpenConnection = (conn) => { + console.log('Got connection', conn) + this.clients[this.getAddrHash(conn.address)] = new Player(this, conn) + } + + onCloseConnection = (inetAddr, reason) => { + console.log('Close connection', inetAddr, reason) + delete this.clients[this.getAddrHash(inetAddr)] + } + + onEncapsulated = (encapsulated, inetAddr) => { + console.log('Encapsulated', encapsulated, inetAddr) + const buffer = encapsulated.buffer + const client = this.clients[this.getAddrHash(inetAddr)] + if (!client) { + console.warn('packet from unknown inet addr', inetAddr.address, inetAddr.port) + return + } + client.handle(buffer) + } + + // write(name, params) { + // console.log('Need to encode', name, params) + // const batch = new BatchPacket() + // const packet = this.serializer.createPacketBuffer({ name, params }) + // batch.addEncodedPacket(packet) + // const buf = batch.encode() + // // send to raknet + // this.listener.sendBuffer() + // } + + async create(serverIp, port) { + this.listener = new Listener(this) + this.raknet = await this.listener.listen(serverIp, port) + console.log('Listening on', serverIp, port) + + this.raknet.on('openConnection', this.onOpenConnection) + this.raknet.on('closeConnection', this.onCloseConnection) + this.raknet.on('encapsulated', this.onEncapsulated) + + this.raknet.on('raw', (buffer, inetAddr) => { + console.log('Raw packet', buffer, inetAddr) + }) + } +} + +let server = new Server() +server.create('0.0.0.0', 19130) \ No newline at end of file diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js new file mode 100644 index 0000000..aa539f0 --- /dev/null +++ b/src/transforms/encryption.js @@ -0,0 +1,108 @@ +const Transform = require('readable-stream').Transform +const crypto = require('crypto') +const aesjs = require('aes-js') +const Zlib = require('zlib') + +const CIPHER = 'aes-256-cfb8' + +function createCipher(secret, initialValue) { + if (crypto.getCiphers().includes(CIPHER)) { + return crypto.createCipheriv(CIPHER, secret, initialValue) + } + return new Cipher(secret, initialValue) +} + +function createDecipher(secret, initialValue) { + if (crypto.getCiphers().includes(CIPHER)) { + return crypto.createDecipheriv(CIPHER, secret, initialValue) + } + return new Decipher(secret, initialValue) +} + +class Cipher extends Transform { + constructor(secret, iv) { + super() + this.aes = new aesjs.ModeOfOperation.cfb(secret, iv, 1) // eslint-disable-line new-cap + } + + _transform(chunk, enc, cb) { + try { + const res = this.aes.encrypt(chunk) + cb(null, res) + } catch (e) { + cb(e) + } + } +} + +class Decipher extends Transform { + constructor(secret, iv) { + super() + this.aes = new aesjs.ModeOfOperation.cfb(secret, iv, 1) // eslint-disable-line new-cap + } + + _transform(chunk, enc, cb) { + try { + const res = this.aes.decrypt(chunk) + cb(null, res) + } catch (e) { + cb(e) + } + } +} + +function computeCheckSum(packetPlaintext, sendCounter, secretKeyBytes) { + let digest = crypto.createHash('sha256'); + let counter = Buffer.alloc(8) + // writeLI64(sendCounter, counter, 0); + counter.writeBigInt64LE(sendCounter, 0) + console.log('Send counter' , counter) + digest.update(counter); + digest.update(packetPlaintext); + digest.update(secretKeyBytes); + let hash = digest.digest(); + + return hash.slice(0, 8); +} + +function createEncryptor(client, iv) { + client.cipher = createCipher(client.secretKeyBytes, iv) + +} + +function createDecryptor(client, iv) { + client.decipher = createDecipher(client.secretKeyBytes, iv) + client.receiveCounter = client.receiveCounter || 0n + + const decryptor = new Transform({ + transform(chunk, encoding, cb) { + console.log('Got transform', chunk) + const packet = chunk.slice(0, chunk.length - 8); + const checksum = chunk.slice(chunk.length - 8); + const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) + // const computedCheckSum1 = computeCheckSum(packet, 1n, client.secretKeyBytes) + // console.log('Checksums', checksum) + // console.log('Checksum1', computedCheckSum) + // console.log('Checksum2', computedCheckSum1) + console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') + client.receiveCounter++ + if (checksum.toString("hex") == computedCheckSum.toString("hex")) this.push(packet) + else console.log('FAILED', checksum.toString("hex"), computedCheckSum.toString("hex")) + // else process.exit(`Checksum mismatch ${checksum.toString("hex")} - ${computedCheckSum.toString("hex")}`) // TODO: remove + cb() + } + }) + + client.decipher.pipe(decryptor) + .pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 })) + .on('data', client.onDecryptedPacket) + // .on('end', () => console.log('Finished!')) + + return (blob) => { + client.decipher.write(blob) + } +} + +module.exports = { + createCipher, createDecipher, createEncryptor, createDecryptor +} From d578eae98f053e17a0507e2d016e67f470b22027 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 30 Jan 2021 01:40:34 -0500 Subject: [PATCH 082/458] add encryptor --- data/newproto.json | 166 +++++++++++++++++------------- package.json | 4 +- src/BatchPacket.js | 8 -- src/serverTest.js | 191 +++++++++++++++++++++++------------ src/transforms/encryption.js | 46 +++++++-- 5 files changed, 264 insertions(+), 151 deletions(-) diff --git a/data/newproto.json b/data/newproto.json index ae404a4..81d1621 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -12,6 +12,12 @@ "countType": "varint" } ], + "LittleString": [ + "pstring", + { + "countType": "li32" + } + ], "varint32": "varint", "varint64": "varint", "bool": "i8", @@ -22,74 +28,86 @@ "MapInfo": "native", "nbt": "native", "BehaviourPackInfos": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - } - ] + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + } + ] + ] + } ], "TexturePackInfos": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "rtx_enabled", - "type": "bool" - } - ] + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "rtx_enabled", + "type": "bool" + } + ] + ] + } ], "ResourcePackIdVersions": [ "container", @@ -2307,8 +2325,16 @@ "type": "i32" }, { - "name": "payload", - "type": "ByteArray" + "name": "payload_size", + "type": "varint" + }, + { + "name": "chain", + "type": "LittleString" + }, + { + "name": "client_data", + "type": "LittleString" } ] ], @@ -2359,11 +2385,11 @@ "type": "bool" }, { - "name": "behahaviorpackinfos", + "name": "behaviour_packs", "type": "BehaviourPackInfos" }, { - "name": "texturepacks", + "name": "texture_packs", "type": "TexturePackInfos" } ] diff --git a/package.json b/package.json index 12fc42f..6c7aa73 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pocket-minecraft-protocol", - "version": "2.4.0", - "description": "Parse and serialize Minecraft Pocket Edition packets", + "version": "3.0.0", + "description": "Parse and serialize Minecraft Bedrock Edition packets", "main": "index.js", "scripts": { "build": "babel src --out-dir dist", diff --git a/src/BatchPacket.js b/src/BatchPacket.js index 5cffd28..98de0c4 100644 --- a/src/BatchPacket.js +++ b/src/BatchPacket.js @@ -44,13 +44,6 @@ class BatchPacket { return ret } - encodePayload() { - } - - addEncoded(packet) { - - } - addEncodedPacket(packet) { this.stream.writeUnsignedVarInt(packet.byteLength) this.stream.append(packet) @@ -71,7 +64,6 @@ class BatchPacket { } static getPackets(stream) { - stream.buffer = this.payload const packets = [] while (!stream.feof()) { const length = stream.readUnsignedVarInt() diff --git a/src/serverTest.js b/src/serverTest.js index df29724..eece259 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -33,6 +33,17 @@ function createDeserializer() { return new Parser(proto, 'mcpe_packet'); } +const PLAY_STATUS = { + 'LoginSuccess': 0, + 'LoginFailedClient': 1, + 'LoginFailedServer': 2, + 'PlayerSpawn': 3, + 'LoginFailedInvalidTenant': 4, + 'LoginFailedVanillaEdu': 5, + 'LoginFailedEduVanilla': 6, + 'LoginFailedServerFull': 7 +} + class Player extends EventEmitter { constructor(server, connection, options) { super() @@ -41,32 +52,28 @@ class Player extends EventEmitter { Encrypt(this, server, options) } - // TODO: Move this to a protodef native type - onLogin(packet) { - let dataProto = new ProtoDef() - dataProto.addType('data_chain', ['container', [{ - 'name': 'chain', - 'type': ['pstring', { - 'countType': 'li32' - }] - }, { - 'name': 'clientData', - 'type': ['pstring', { - 'countType': 'li32' - }] - }]]) + getData() { + return this.userData + } - //FIXME: Xbox & Non-Xbox support - console.log(packet); - let pbody = packet.data.params.payload - let body = dataProto.parsePacketBuffer('data_chain', pbody) + onLogin(packet) { + let body = packet.data console.log('Body', body) - fs.writeFileSync('login.json', JSON.stringify(body)) + const clientVer = body.protocol_version + if (this.server.options.version) { + if (this.server.options.version < clientVer) { + this.sendDisconnectStatus(PLAY_STATUS.LoginFailedClient) + return + } + } else if (clientVer < MIN_VERSION) { + this.sendDisconnectStatus(PLAY_STATUS.LoginFailedClient) + return + } // Parse login data - const authChain = JSON.parse(body.data.chain) - const skinChain = body.data.clientData + const authChain = JSON.parse(body.params.chain) + const skinChain = body.params.client_data try { var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) @@ -76,29 +83,47 @@ class Player extends EventEmitter { } console.log('Verified user', 'got pub key', key, userData) - this.emit('join', { - user: userData.extraData - }) - this.emit('server.client_handshake', { - key - }) + this.emit('login', { user: userData.extraData }) // emit events for user + this.emit('server.client_handshake', { key }) // internal so we start encryption + + this.userData = userData.extraData + this.version = clientVer + } + + sendDisconnectStatus(play_status) { + this.write('play_status', { status: play_status }) + this.connection.close() + } + + // After sending Server to Client Handshake, this handles the client's + // Client to Server handshake response. This indicates successful encryption + onHandshake() { + // https://wiki.vg/Bedrock_Protocol#Play_Status + this.write('play_status', { status: PLAY_STATUS.LoginSuccess }) + this.emit('join') } startEncryption(iv) { this.encryptionEnabled = true - // this.cipher = cipher.createCipher(client.secretKeyBytes, iv) - // this.decipher = cipher.createDecipher(client.secretKeyBytes, iv) - this.decrypt = cipher.createDecryptor(this, iv) - this.encrypt = cipher.createDecryptor(this, iv) + this.encrypt = cipher.createEncryptor(this, iv) } - write(name, params) { + write(name, params) { // TODO: Batch console.log('Need to encode', name, params) const batch = new BatchPacket() const packet = this.server.serializer.createPacketBuffer({ name, params }) batch.addEncodedPacket(packet) + + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + + sendDecryptedBatch(batch) { const buf = batch.encode() // send to raknet const sendPacket = new EncapsulatedPacket(); @@ -109,29 +134,50 @@ class Player extends EventEmitter { this.connection.sendQueue() } - sendDecryptedBatch(batch) { - + sendEncryptedBatch(batch) { + const buf = batch.stream.getBuffer() + console.log('Sending encrypted batch', batch) + this.encrypt(buf) } - sendEncryptedBatch(batch) { - + // These are callbacks called from encryption.js + onEncryptedPacket = (buf) => { + console.log('ENC BUF', buf) + const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header + const sendPacket = new EncapsulatedPacket(); + sendPacket.reliability = 0 + sendPacket.buffer = packet + console.log('Sending wrapped encrypted batch', packet) + this.connection.addEncapsulatedToQueue(sendPacket) } onDecryptedPacket = (buf) => { console.log('Decrypted', buf) + + const stream = new BinaryStream(buf) + const packets = BatchPacket.getPackets(stream) + + for (const packet of packets) { + this.readPacket(packet) + } } readPacket(packet) { console.log('packet', packet) const des = this.server.deserializer.parsePacketBuffer(packet) - console.log(des) + console.log('->', des) switch (des.data.name) { case 'login': console.log(des) this.onLogin(des) + return + case 'client_to_server_handshake': + this.onHandshake() default: - this.emit(des.data.name, des.data.params) + console.log('ignoring, unhandled') } + this.emit(des.data.name, des.data.params) + } handle(buffer) { // handle encapsulated @@ -147,29 +193,36 @@ class Player extends EventEmitter { console.log('Reading ', packets.length, 'packets') for (var packet of packets) { this.readPacket(packet) - } + } } } } } +// Minimum supported version (< will be kicked) +const MIN_VERSION = 422 +// Currently supported verson +const CURRENT_VERSION = 422 + +const defaultServerOptions = { + // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 + version: CURRENT_VERSION, +} + class Server extends EventEmitter { - constructor(options = {}) { - // const customTypes = require('./datatypes/minecraft') - // this.batchProto = new ProtoDef() - // this.batchProto.addTypes(customTypes) - // this.batchProto.addType('insideBatch', ['endOfArray', { - // 'type': ['buffer', { - // 'countType': 'varint', - // }] - // }]) - + constructor(options) { super() - + this.options = { ...defaultServerOptions, options } this.serializer = createSerializer() this.deserializer = createDeserializer() - this.clients = {} + this.validateOptions() + } + + validateOptions() { + if (this.options.version < defaultServerOptions.version) { + throw new Error(`Unsupported protocol version < ${defaultServerOptions.version}: ${this.options.version}`) + } } getAddrHash(inetAddr) { @@ -178,7 +231,10 @@ class Server extends EventEmitter { onOpenConnection = (conn) => { console.log('Got connection', conn) - this.clients[this.getAddrHash(conn.address)] = new Player(this, conn) + const player = new Player(this, conn) + this.clients[this.getAddrHash(conn.address)] = player + + this.emit('connect', { client: player }) } onCloseConnection = (inetAddr, reason) => { @@ -197,16 +253,6 @@ class Server extends EventEmitter { client.handle(buffer) } - // write(name, params) { - // console.log('Need to encode', name, params) - // const batch = new BatchPacket() - // const packet = this.serializer.createPacketBuffer({ name, params }) - // batch.addEncodedPacket(packet) - // const buf = batch.encode() - // // send to raknet - // this.listener.sendBuffer() - // } - async create(serverIp, port) { this.listener = new Listener(this) this.raknet = await this.listener.listen(serverIp, port) @@ -222,5 +268,22 @@ class Server extends EventEmitter { } } -let server = new Server() -server.create('0.0.0.0', 19130) \ No newline at end of file +let server = new Server({ + +}) +server.create('0.0.0.0', 19130) + +server.on('connect', (data) => { + // TODO: send other packets needed to login... + const client = data.client + client.on('join', () => { + console.log('Client joined', client.getData()) + + client.write('resource_packs_info', { + 'must_accept': false, + 'has_scripts': false, + 'behaviour_packs': [], + 'texture_packs': [] + }) + }) +}) \ No newline at end of file diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index aa539f0..92acd20 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,4 +1,4 @@ -const Transform = require('readable-stream').Transform +const { PassThrough, Transform } = require('readable-stream') const crypto = require('crypto') const aesjs = require('aes-js') const Zlib = require('zlib') @@ -56,7 +56,7 @@ function computeCheckSum(packetPlaintext, sendCounter, secretKeyBytes) { let counter = Buffer.alloc(8) // writeLI64(sendCounter, counter, 0); counter.writeBigInt64LE(sendCounter, 0) - console.log('Send counter' , counter) + // console.log('Send counter', counter) digest.update(counter); digest.update(packetPlaintext); digest.update(secretKeyBytes); @@ -67,7 +67,43 @@ function computeCheckSum(packetPlaintext, sendCounter, secretKeyBytes) { function createEncryptor(client, iv) { client.cipher = createCipher(client.secretKeyBytes, iv) + client.sendCounter = client.sendCounter || 0n + // A packet is encrypted via AES256(plaintext + SHA256(send_counter + plaintext + secret_key)[0:8]). + // The send counter is represented as a little-endian 64-bit long and incremented after each packet. + + const encryptor = new Transform({ + transform(chunk, enc, cb) { + console.log('Encryptor called', chunk) + // Here we concat the payload + checksum before the encryption + const packet = Buffer.concat([chunk, computeCheckSum(chunk, client.sendCounter, client.secretKeyBytes)]) + client.sendCounter++ + this.push(packet) + cb() + } + }) + + // https://stackoverflow.com/q/25971715/11173996 + // TODO: Fix deflate stream - for some reason using .pipe() doesn't work here + // so we deflate it outside the pipe + const compressor = Zlib.createDeflateRaw({ level: 7, chunkSize: 1024 * 1024 * 2, flush: Zlib.Z_SYNC_FLUSH }) + const writableStream = new PassThrough() + + writableStream + // .pipe(compressor) + .pipe(encryptor).pipe(client.cipher).on('data', client.onEncryptedPacket) + + return (blob) => { + // console.log('ENCRYPTING') + Zlib.deflateRaw(blob, { level: 7 }, (err, res) => { + if (err) { + console.error(err) + throw new Error(`Failed to deflate stream`) + } + writableStream.write(res) + }) + // writableStream.write(blob) + } } function createDecryptor(client, iv) { @@ -80,10 +116,6 @@ function createDecryptor(client, iv) { const packet = chunk.slice(0, chunk.length - 8); const checksum = chunk.slice(chunk.length - 8); const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) - // const computedCheckSum1 = computeCheckSum(packet, 1n, client.secretKeyBytes) - // console.log('Checksums', checksum) - // console.log('Checksum1', computedCheckSum) - // console.log('Checksum2', computedCheckSum1) console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') client.receiveCounter++ if (checksum.toString("hex") == computedCheckSum.toString("hex")) this.push(packet) @@ -96,7 +128,7 @@ function createDecryptor(client, iv) { client.decipher.pipe(decryptor) .pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 })) .on('data', client.onDecryptedPacket) - // .on('end', () => console.log('Finished!')) + // .on('end', () => console.log('Finished!')) return (blob) => { client.decipher.write(blob) From 040887e9df372a9d2f99a350f87c52ba1ad81b77 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 30 Jan 2021 02:36:34 -0500 Subject: [PATCH 083/458] fix zlib decryption issue --- data/newproto.json | 8 ++-- src/serverTest.js | 9 ++-- src/transforms/encryption.js | 91 +++++++++++++++++++++++++----------- 3 files changed, 72 insertions(+), 36 deletions(-) diff --git a/data/newproto.json b/data/newproto.json index 81d1621..2af7f0b 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -30,7 +30,7 @@ "BehaviourPackInfos": [ "array", { - "countType": "varint", + "countType": "li16", "type": [ "container", [ @@ -69,7 +69,7 @@ "TexturePackInfos": [ "array", { - "countType": "varint", + "countType": "li16", "type": [ "container", [ @@ -2402,11 +2402,11 @@ "type": "bool" }, { - "name": "behaviorpackidversions", + "name": "behavior_pack_id_versions", "type": "ResourcePackIdVersions" }, { - "name": "resourcepackidversions", + "name": "resource_pack_id_versions", "type": "ResourcePackIdVersions" }, { diff --git a/src/serverTest.js b/src/serverTest.js index eece259..226cd22 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -184,6 +184,7 @@ class Player extends EventEmitter { if (buffer[0] == 0xfe) { // wrapper if (this.encryptionEnabled) { + // console.log('READING ENCRYPTED PACKET', buffer) this.decrypt(buffer.slice(1)) } else { const stream = new BinaryStream(buffer) @@ -247,8 +248,7 @@ class Server extends EventEmitter { const buffer = encapsulated.buffer const client = this.clients[this.getAddrHash(inetAddr)] if (!client) { - console.warn('packet from unknown inet addr', inetAddr.address, inetAddr.port) - return + throw new Error(`packet from unknown inet addr: ${inetAddr.address}/${inetAddr.port}`) } client.handle(buffer) } @@ -273,9 +273,8 @@ let server = new Server({ }) server.create('0.0.0.0', 19130) -server.on('connect', (data) => { - // TODO: send other packets needed to login... - const client = data.client +server.on('connect', ({ client }) => { + /** @type {Player} */ client.on('join', () => { console.log('Client joined', client.getData()) diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 92acd20..491fe09 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -72,9 +72,9 @@ function createEncryptor(client, iv) { // A packet is encrypted via AES256(plaintext + SHA256(send_counter + plaintext + secret_key)[0:8]). // The send counter is represented as a little-endian 64-bit long and incremented after each packet. - const encryptor = new Transform({ + const addChecksum = new Transform({ // append checksum transform(chunk, enc, cb) { - console.log('Encryptor called', chunk) + console.log('Encryptor: checking checksum', chunk) // Here we concat the payload + checksum before the encryption const packet = Buffer.concat([chunk, computeCheckSum(chunk, client.sendCounter, client.secretKeyBytes)]) client.sendCounter++ @@ -84,51 +84,74 @@ function createEncryptor(client, iv) { }) // https://stackoverflow.com/q/25971715/11173996 - // TODO: Fix deflate stream - for some reason using .pipe() doesn't work here - // so we deflate it outside the pipe - const compressor = Zlib.createDeflateRaw({ level: 7, chunkSize: 1024 * 1024 * 2, flush: Zlib.Z_SYNC_FLUSH }) - const writableStream = new PassThrough() + // TODO: Fix deflate stream - for some reason using .pipe() doesn't work using zlib.createDeflateRaw() + // so we define our own compressor transform + // const compressor = Zlib.createDeflateRaw({ level: 7, chunkSize: 1024 * 1024 * 2, flush: Zlib.Z_SYNC_FLUSH }) + const compressor = new Transform({ + transform(chunk, enc, cb) { + Zlib.deflateRaw(chunk, { level: 7 }, (err, res) => { + if (err) { + console.error(err) + throw new Error(`Failed to deflate stream`) + } + this.push(res) + cb() + }) + } + }) - writableStream - // .pipe(compressor) - .pipe(encryptor).pipe(client.cipher).on('data', client.onEncryptedPacket) + + const stream = new PassThrough() + + stream + .pipe(compressor) + .pipe(addChecksum).pipe(client.cipher).on('data', client.onEncryptedPacket) return (blob) => { - // console.log('ENCRYPTING') - Zlib.deflateRaw(blob, { level: 7 }, (err, res) => { - if (err) { - console.error(err) - throw new Error(`Failed to deflate stream`) - } - writableStream.write(res) - }) - // writableStream.write(blob) + stream.write(blob) } } + function createDecryptor(client, iv) { client.decipher = createDecipher(client.secretKeyBytes, iv) client.receiveCounter = client.receiveCounter || 0n - const decryptor = new Transform({ + const verifyChecksum = new Transform({ // verify checksum transform(chunk, encoding, cb) { - console.log('Got transform', chunk) + console.log('Decryptor: checking checksum', chunk) const packet = chunk.slice(0, chunk.length - 8); const checksum = chunk.slice(chunk.length - 8); const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') client.receiveCounter++ - if (checksum.toString("hex") == computedCheckSum.toString("hex")) this.push(packet) - else console.log('FAILED', checksum.toString("hex"), computedCheckSum.toString("hex")) - // else process.exit(`Checksum mismatch ${checksum.toString("hex")} - ${computedCheckSum.toString("hex")}`) // TODO: remove + if (checksum.toString("hex") == computedCheckSum.toString("hex")) { + this.push(packet) + } else { + throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) + } + // console.log('Calling cb') cb() } }) - client.decipher.pipe(decryptor) - .pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 })) - .on('data', client.onDecryptedPacket) - // .on('end', () => console.log('Finished!')) + const inflator = new Transform({ + transform(chunk, enc, cb) { + // console.log('INFLATING') + Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buf) => { + if (err) throw err + this.push(buf) + cb() + }) + } + }) + + client.decipher.pipe(verifyChecksum) + .pipe(inflator) + // .pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 })) + .on('data', (...args) => client.onDecryptedPacket(...args)) + .on('end', () => console.log('Decryptor: finish pipeline')) + return (blob) => { client.decipher.write(blob) @@ -138,3 +161,17 @@ function createDecryptor(client, iv) { module.exports = { createCipher, createDecipher, createEncryptor, createDecryptor } + +function testDecrypt() { + const client = { + secretKeyBytes: Buffer.from('ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=', 'base64'), + onDecryptedPacket: (...data) => console.log('Decrypted', data) + } + const iv = Buffer.from('ZOBpyzki/M8UZv5tiBih0w==', 'base64') + + const decrypt = createDecryptor(client, iv) + console.log('Dec', decrypt(Buffer.from('4B4FCA0C2A4114155D67F8092154AAA5EF', 'hex'))) + console.log('Dec 2', decrypt(Buffer.from('DF53B9764DB48252FA1AE3AEE4', 'hex'))) +} + +// testDecrypt() \ No newline at end of file From d92a38d3cd21a97c775f4a93a0ccd83251aa48d6 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 3 Feb 2021 13:01:51 -0500 Subject: [PATCH 084/458] add creativeitems, biome definitions --- data/biome_definitions.nbt | Bin 0 -> 37626 bytes data/creativeitems.json | 4898 ++++++++++++++++++++++++++++++++++++ src/datatypes/minecraft.js | 47 +- 3 files changed, 4924 insertions(+), 21 deletions(-) create mode 100644 data/biome_definitions.nbt create mode 100644 data/creativeitems.json diff --git a/data/biome_definitions.nbt b/data/biome_definitions.nbt new file mode 100644 index 0000000000000000000000000000000000000000..68705c5d4f97c43f712894fcf5f25cb07bcf5892 GIT binary patch literal 37626 zcmeHQ+m74D8CKVlEOF24-5!z_XoLX0F#^Zii`GEaet-gffFK|!X|!TOkqeUY)-eM3 z0eaE9*16~t^sW!!K7joceUbj0gE&Xdkdii9m(EQrYp9v;KOg3&*YOU=!D5^w{i zzvL*M!n4uz8u@t|#MvxKVQcUmZ*MT1B=IyX{_?Nx>k*v8PiCWMU%wtD_{WoU^z6&W zqii|;7ESWevnP*7Im+OFM)M%^$6>O7X9m}!$D@}4AOoKh#6~|nZvKd5f`S-7A&6hC zyB|1gv0-sPaEuy9nk3P5tq07*D9YA)!UA0f>pftZ12?XBjB%Jw=A$3Jf&aV*7r=i0 zO^{__eC@|5yq=GfG}{{Emq`vozCzaqoZ;rS@lQ| zL?3^bTP=&tunXLn4ZMC3gZM>#vbs-x`r#spvmB+vmAv$$wZssk_^ z26fOeNc4dy(LIde8gdN=J`1AUpQ0!aG8c(1%zZ-xk3EGd0}o$#AsYA>9q+T!z{e<` zqg1i(z2iJcuTk#9Ny2Vq_p_VeHukTi)%j50yzY7gEUqhK<3p~;8$ z@2?utq*yBRny|GG@BgGYUGf5IZotA7J67#W_cllu)~9+0*s}V>RdG4@k8gj~)Y&YS z%Eu6Ph`-Rx*}S0cCn}EOQx7=v_8#zNwo{sKi|s$-VUbP$@M3{o8k6I2E-WVBot8gs zVr!;n_QweM^I#l;+XS8nI6i$s9+k*;^fU*#&s44k{u2Rstfzfv_>ZWXH^NU8e-k29 z?8}81g*s@gYCw}zsejP3uBwIsB=DpN%0r6w`O3}Z42Qt1y5IG*f^!cMGO`e3o;7ju zim=dkHdQ~qecRMj6-z7m2YB-<(R~0{#VtQ@p3NaZHYri=jCR#Ytzfsng<)(6wX_>1 zKZb*U7j^^Jp{YO?ODh4zU)Z7z?3ZW`&(jdnH`Nrtpzv!Ps3xs38N7i&uO41ypqdsH zLbW^yuLBpVZPR0e{k>}_22P&KfTsX4Y^!7k%cqg7#R=987?iqx%Ne&+F`L5;iYxPU zF#XNW4WX>y!0BLCPJEApKLen3A(J`5wjouF$e`XMRDYH>YCbOwFpLW_lL1=o4DF zQdEWN5vFLg{0p=O(&kP+X_1ZPU3G#^uOC1yS8d+%YUGzIN=yv!e^xdQg zx?{-EZ=z)eDISD4wc?zkbJA~njH&y!mWl(yU3C)^M|7E*l=w|c;wS@_(~(#fFzRXd zsfaVv&1C_kRErus3iR7W9bq{0fT=Ys5=~AnvEV&CJ3DoCro+kthk|x-!C}kghbtw% z+M=EKw`eD{O@f!&4!;nTaM@Prlb*#@@8Xj$o<1Rep8oLreJXbO{Jz06zx?7! z(}uY-fyi>-oNIx{U_82}n!ND2P^Tc4%#iVRuy?kK{e^hmwd_pGBDl4(GS=A7@+3y2 zg2|i*SY_1Sq@_|+Jxre&>=)GeRL!8_>z&kKZoy}Dv7jEttCCFNDeHkAERtmmneey{ z;(E#2MbHh*$NG8om@s2n2NI*c+C@}c6I(=Ono7yP74>WBud3}imaw=PSBu1xDvpi# z+Ipg0B&LDIne11h)P&OyXHjws4F>MzupMc2^7sxO@f6JLSn$yHH&MoOVU4>6!d1@o zZI+vM=?)0T)Xfu!l(IV(Ot|Hr49125K29`%(U#$a>u#i^ zdcapFOAfVIJ;N%q!@O?Yjr|}lKe@0nBy_jg5~o%MH{l}J>M`uoVkV~%2s*qd;Ka7v zz1N+iC~^exZZqoJZU(_{)NKY?^#mNz?vF!y2jv!ScA)HtbaxatOVb64Ps>IS+Wx^` z1fl=R-2tIjL*%9rd-dV4Nba)`$o1OJM=lcsDiaR?8=D)g6%DVfm^cc^E+T43bcvTw zRxO;?Dv8KxoRP5HJ2@@EgzMblcYMXiQZN?uJ@<>%DTZ45ljjwV?3_BaDpK`;ZcOv0 zIn%tcc5Cl|Y4WHTaZATBZqX$gm7;w^Fs)N@nr+>tw2b@fXy>W<5 zI5?ma4lw4N{ogl(r!FJIz+f9eGBTkx*Tp@Xy zwS>HAyk6@8t)4N@G_VyuA90gW)Lgtx3v`QOkx>=cwSex|TW!!zI1zgv>iG<w|07j zC(dkoFriJBB`IFhL_eapCHTsui*!Touz6n9J_Vz3UbXtloaV4xzN9+etwX9@Y@!+~ z9NO-)ss}z|*X-JhkK&LE37C=wmO8p|or!jXP26-W(wH!+)_F|H_NG1IaXxZ+dW-Gy ze>U8zs&^dTQCcQAn zDNb7|*(>(zkJDEZRIakvW6Trfw@vKW$KO+hUtl`mnitAdFm6*WvVPaBXHb1CW*3gl zy!=x4*^hsKX#zKra}+Fh5dd$C&c}a6G1T7Gt0zzt$hCx0Bh~d1+_YBPIOddPZq3_# zVw2PAD)^r5D!8-_n|3+pIaxJib$po-O{|ZY196UCFIcPS$hB?DtnX7bJX+|jB$_bpXdfu*grliqxA%i7t3s(CdtAN zvnYtCZXj&0r@QDtPy$J}96|LgFi6=52lercgp&I#oNHTdik`bCizE?#xMX0#FVP-c z|EvGEG%|tQuL2p<*$y=+5V=9S)zVv2_TO+*vvwk(F7e%4|n`dq4h3(_l0>qt6uefNBEq}2ne6sODAk7rf{vgq^y24CU|j{%=k&RjOkng zGODk9q>1`0AID#iW(-m4QbuUr;1$IK#g67(7mbd0z%>Slipw$$ z^9uC6gN{WTefjIB#;MbRVe3*Q)qs;!Owl4#a*?K-qWdkcw<}k(RsMGLl`1Dhk>lA# zv&$i;y^gJJ?+|>=8BB}c-Kiw&>18p#UFl_OMphX_xvrJXyW-_%d7E_7Qps0#x+mAcd!orhWQGKk}!ybcQ$VpTBR^oEm@ zx$-)!S)F5wNHMp!sFIZ`$HxAvmCm>42GnAzzQc+xyz`(1N&ZzA&W5miYn^%@-v3ph zq=B=U8^w;#Sh|#QEeyI}@K!KTvN^)A#l`}-DK7Z~u4!*ZM@%P51SRWZ;tLa#6!;Pijh+aJR{4j98w zyaT={()0$?iGCwBJg++^wB@<2X-p%C1%}!OX*aVuoh6?mOhKxf?fz?zIb&vIw;MV2v zcb#^SIhYP6XY#3wvQ<;z9BmJ?+h75L?V4ELrm55<12)?L1H9^LbzF*LeDGjNtDLT2 zRt=P`JEJ=oPLdd27#=3^KYK#YFxRyMs?$$qqi0{g9+fS1^-8hiJp$|X@8DNI%Qx2R z^%3DrNzuUbSU79bQ_=otcv#aXXzt+GJJG6$Cv2kLGd7G$ISgqt^!}#lFm)xa?r`k> z_q~m<0J+A$nS-uD!eSo4TANt$K!f+5@H0iqC=ROnm5HX(JaB6a7RnsI^|1C6{1ULw zsvE6pNf!eRT77E{v~HV*buffer.length) + if (offset + 16 > buffer.length) throw new PartialReadError(); return { - value: UUID.stringify(buffer.slice(offset,16+offset)), + value: UUID.stringify(buffer.slice(offset, 16 + offset)), size: 16 }; } function writeUUID(value, buffer, offset) { - const buf=UUID.parse(value); - buf.copy(buffer,offset); + const buf = UUID.parse(value); + buf.copy(buffer, offset); return offset + 16; } function readNbt(buffer, offset) { - return nbt.protoLE.read(buffer,offset,"nbt"); + return proto.read(buffer, offset, "nbt") } function writeNbt(value, buffer, offset) { - return nbt.protoLE.write(value,buffer,offset,"nbt"); + return proto.write(value, buffer, offset, "nbt") } function sizeOfNbt(value) { - return nbt.protoLE.sizeOf(value,"nbt"); + return proto.sizeOf(value, "nbt") } function readEntityMetadata(buffer, offset, _ref) { @@ -74,7 +77,7 @@ function sizeOfEntityMetadata(value, _ref3) { } function readIpAddress(buffer, offset) { - var address = buffer[offset] + '.' + buffer[offset+1] + '.' + buffer[offset+2] + '.' + buffer[offset+3]; + var address = buffer[offset] + '.' + buffer[offset + 1] + '.' + buffer[offset + 2] + '.' + buffer[offset + 3]; return { size: 4, value: address @@ -84,7 +87,7 @@ function readIpAddress(buffer, offset) { function writeIpAddress(value, buffer, offset) { var address = value.split('.'); - address.forEach(function(b) { + address.forEach(function (b) { buffer[offset] = parseInt(b); offset++; }); @@ -93,10 +96,10 @@ function writeIpAddress(value, buffer, offset) { } function readEndOfArray(buffer, offset, typeArgs) { - var type=typeArgs.type; + var type = typeArgs.type; var cursor = offset; var elements = []; - while(cursor Date: Wed, 3 Feb 2021 13:17:13 -0500 Subject: [PATCH 085/458] move files --- .gitignore | 3 +- src/BatchPacket.js | 7 +-- src/auth/encryption.js | 22 +------- src/auth/{ => tests}/encrypt.js | 0 src/auth/{ => tests}/encryptTest.js | 0 src/auth/{ => tests}/jwtTest.js | 0 src/{serverTest.js => server.js} | 84 +++++++++++++++++++++++++++-- src/transforms/encryption.js | 2 - 8 files changed, 84 insertions(+), 34 deletions(-) rename src/auth/{ => tests}/encrypt.js (100%) rename src/auth/{ => tests}/encryptTest.js (100%) rename src/auth/{ => tests}/jwtTest.js (100%) rename src/{serverTest.js => server.js} (74%) diff --git a/.gitignore b/.gitignore index 9303c34..20c7123 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -npm-debug.log \ No newline at end of file +npm-debug.log +__* \ No newline at end of file diff --git a/src/BatchPacket.js b/src/BatchPacket.js index 98de0c4..cdd9296 100644 --- a/src/BatchPacket.js +++ b/src/BatchPacket.js @@ -3,7 +3,7 @@ const Zlib = require('zlib'); const NETWORK_ID = 0xfe -// This is not a MCPE packet, it's a wrapper that contains compressed batched packets +// This is not a real MCPE packet, it's a wrapper that contains compressed/encrypted batched packets class BatchPacket { constructor(stream) { @@ -13,10 +13,6 @@ class BatchPacket { this.compressionLevel = 7 } - init() { - - } - decode() { // Read header const pid = this.stream.readByte(); @@ -47,7 +43,6 @@ class BatchPacket { addEncodedPacket(packet) { this.stream.writeUnsignedVarInt(packet.byteLength) this.stream.append(packet) - // this.payload = Buffer.concat([this.payload, stream.getBuffer()]); } getPackets() { diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 9529fc0..a487f3e 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -1,10 +1,9 @@ const JWT = require('jsonwebtoken') const crypto = require('crypto') -const constants = require('./constants') const { Ber } = require('asn1') const ec_pem = require('ec-pem') -const SALT = 'ABC' +const SALT = '🧂' function Encrypt(client, options) { function startClientboundEncryption(publicKey) { @@ -48,25 +47,6 @@ function Encrypt(client, options) { client.startEncryption(initial) } - function startClientCiphers() { - - var decipher = crypto.createDecipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0, 16)) - - let customPackets = JSON.parse(JSON.stringify(require("../data/protocol"))) - - customPackets['types']['encapsulated_packet'][1][1]['type'][1]['fields']['mcpe_encrypted'] = 'restBuffer' - customPackets['types']['encapsulated_packet'][1][0]['type'][1]['mappings']['0xfe'] = 'mcpe_encrypted' - client.encapsulatedPacketParser.proto.addTypes(merge(require('raknet').protocol, customPackets).types) - - client.encryptionEnabled = true - - client.on("mcpe_encrypted", packet => { - decipher.write(packet); - }); - - client.cipher = crypto.createCipheriv('aes-256-cfb8', client.secretKeyBytes, client.secretKeyBytes.slice(0, 16)); - } - client.on('server.client_handshake', startClientboundEncryption) } diff --git a/src/auth/encrypt.js b/src/auth/tests/encrypt.js similarity index 100% rename from src/auth/encrypt.js rename to src/auth/tests/encrypt.js diff --git a/src/auth/encryptTest.js b/src/auth/tests/encryptTest.js similarity index 100% rename from src/auth/encryptTest.js rename to src/auth/tests/encryptTest.js diff --git a/src/auth/jwtTest.js b/src/auth/tests/jwtTest.js similarity index 100% rename from src/auth/jwtTest.js rename to src/auth/tests/jwtTest.js diff --git a/src/serverTest.js b/src/server.js similarity index 74% rename from src/serverTest.js rename to src/server.js index 226cd22..c4eaeb7 100644 --- a/src/serverTest.js +++ b/src/server.js @@ -1,4 +1,3 @@ -console.log('IMPORTING') const BinaryStream = require('@jsprismarine/jsbinaryutils').default const Listener = require('@jsprismarine/raknet/listener') const { ProtoDef, Parser, Serializer } = require('protodef') @@ -10,8 +9,7 @@ const { Encrypt } = require('./auth/encryption') const { decodeLoginJWT } = require('./auth/jwt') const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') -console.log('IMPORTED') -// const Zlib = require('zlib'); + var protocol = require('../data/newproto.json').types; @@ -123,6 +121,25 @@ class Player extends EventEmitter { } } + writeRaw(name, buffer) { // skip protodef serializaion + // temporary hard coded stuff + const batch = new BatchPacket() + if (name == 'biome_definition_list') { + // so we can send nbt straight from file without parsing + const stream = new BinaryStream() + stream.writeUnsignedVarInt(0x7a) + stream.append(buffer) + batch.addEncodedPacket(stream.getBuffer()) + // console.log('----- SENDING BIOME DEFINITIONS') + } + + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + sendDecryptedBatch(batch) { const buf = batch.encode() // send to raknet @@ -130,7 +147,7 @@ class Player extends EventEmitter { sendPacket.reliability = 0; sendPacket.buffer = buf - this.connection.addEncapsulatedToQueue(sendPacket, 1) + this.connection.addEncapsulatedToQueue(sendPacket) this.connection.sendQueue() } @@ -268,21 +285,80 @@ class Server extends EventEmitter { } } +let CreativeItems = require('../data/creativeitems.json') +let NBT = require('prismarine-nbt') + let server = new Server({ }) server.create('0.0.0.0', 19130) +let ran = false + server.on('connect', ({ client }) => { /** @type {Player} */ client.on('join', () => { console.log('Client joined', client.getData()) + + // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It + // sends a list of the resource packs it has and basic information on them like the version and description. client.write('resource_packs_info', { 'must_accept': false, 'has_scripts': false, 'behaviour_packs': [], 'texture_packs': [] }) + + client.once('resource_pack_client_response', (packet) => { + // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs + // should be applied (and downloaded) by the client. + client.write('resource_pack_stack', { + 'must_accept': false, + 'behavior_packs': [], + 'resource_packs': [], + 'game_version': '', + 'experiments': [], + 'experiments_previously_toggled': false + }) + + client.once('resource_pack_client_response', async (packet) => { + if (ran === true) throw 'Already sent' + ran = true + let items = [] + let ids = 0 + for (var item of CreativeItems) { + let creativeitem = { runtime_id: items.length } + if (item.id != 0) { + const hasNbt = !!item.nbt_b64 + creativeitem.item = { + network_id: item.id, + auxiliary_value: item.damage || 0, + has_nbt: hasNbt|0, + nbt_version: 1, + blocking_tick: 0, + can_destroy: [], + can_place_on: [] + } + if (hasNbt) { + let nbtBuf = Buffer.from(item.nbt_b64, 'base64') + let { result } = await NBT.parse(nbtBuf, 'little') + creativeitem.item.nbt = result + } + } + items.push(creativeitem) + // console.log(creativeitem) + } + + console.log(items, ids) + + client.write('creative_content', { items }) + + setTimeout(() => { + const biomeDefs = fs.readFileSync('../data/biome_definitions.nbt') + client.writeRaw('biome_definition_list', biomeDefs) + }, 1000) + }) + }) }) }) \ No newline at end of file diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 491fe09..7aaee6b 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -130,14 +130,12 @@ function createDecryptor(client, iv) { } else { throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) } - // console.log('Calling cb') cb() } }) const inflator = new Transform({ transform(chunk, enc, cb) { - // console.log('INFLATING') Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buf) => { if (err) throw err this.push(buf) From 9c171aa0da0e67d5436037d3a1675c18bb9bc213 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 3 Feb 2021 13:26:13 -0500 Subject: [PATCH 086/458] seperate server/serverTest --- data/newproto.json | 751 ++++++++++++++++++++++++++++++--------------- src/server.js | 79 +---- src/serverTest.js | 79 +++++ 3 files changed, 583 insertions(+), 326 deletions(-) create mode 100644 src/serverTest.js diff --git a/data/newproto.json b/data/newproto.json index 2af7f0b..3a166bf 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -20,7 +20,7 @@ ], "varint32": "varint", "varint64": "varint", - "bool": "i8", + "bool": "native", "zigzag32": "native", "zigzag64": "native", "uuid": "native", @@ -110,21 +110,27 @@ } ], "ResourcePackIdVersions": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "name", - "type": "string" - } - ] + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } ], "ResourcePackIds": [ "array", @@ -187,6 +193,32 @@ "type": "GameRule" } ], + "Chunks": [ + "container", + [ + { + "name": "cache_enabled", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "cache_enabled", + "fields": { + "true": "void", + "false": "void" + } + } + ] + }, + { + "name": "data", + "type": "string" + } + ] + ], "BlockPalette": [ "array", { @@ -253,17 +285,88 @@ "type": "zigzag32" }, { - "name": "user_data_marker", - "type": "li16" + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "0", + "0xffff": "1" + } + } + ] }, { - "name": "nbt", - "type": "nbt" + "anon": true, + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "1": [ + "container", + [ + { + "name": "nbt_version", + "type": "u8" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "zigzag32", + "type": "string" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "zigzag32", + "type": "string" + } + ] } ] ] } ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "355": [ + "container", + [ + { + "name": "blocking_tick", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] } ] ], @@ -573,7 +676,7 @@ "type": "zigzag32" }, { - "anon": true, + "name": "legacy_transactions", "type": [ "switch", { @@ -640,125 +743,216 @@ { "name": "inventory_actions", "type": [ - "array", + "switch", { - "countType": "varint", - "type": [ - "container", - [ + "compareTo": "has_network_ids", + "fields": { + "true": [ + "array", { - "name": "source_type", + "countType": "varint", "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "INV_SOURCE_TYPE_CONTAINER", - "1": "INV_SOURCE_TYPE_GLOBAL", - "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", - "3": "INV_SOURCE_TYPE_CREATIVE", - "100": "INV_SOURCE_TYPE_CRAFT_SLOT", - "99999": "INV_SOURCE_TYPE_CRAFT" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "INV_SOURCE_TYPE_CONTAINER": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" + "container", + [ + { + "name": "source_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "INV_SOURCE_TYPE_CONTAINER", + "1": "INV_SOURCE_TYPE_GLOBAL", + "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", + "3": "INV_SOURCE_TYPE_CREATIVE", + "100": "INV_SOURCE_TYPE_CRAFT_SLOT", + "99999": "INV_SOURCE_TYPE_CRAFT" } - ] - ], - "INV_SOURCE_TYPE_WORLD_INTERACTION": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CREATIVE": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CRAFT": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CRAFT_SLOT": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] + } ] - } - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "has_network_ids", - "fields": { - "true": [ - "container", - [ - { - "name": "new_item_stack_id", - "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "INV_SOURCE_TYPE_CONTAINER": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_WORLD_INTERACTION": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CREATIVE": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT_SLOT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] } - ] - ], - "false": "void" + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + }, + { + "name": "new_item_stack_id", + "type": "zigzag32" } - } + ] + ] + } + ], + "false": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "source_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "INV_SOURCE_TYPE_CONTAINER", + "1": "INV_SOURCE_TYPE_GLOBAL", + "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", + "3": "INV_SOURCE_TYPE_CREATIVE", + "100": "INV_SOURCE_TYPE_CRAFT_SLOT", + "99999": "INV_SOURCE_TYPE_CRAFT" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "INV_SOURCE_TYPE_CONTAINER": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_WORLD_INTERACTION": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CREATIVE": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT_SLOT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] + } + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + }, + { + "name": "new_item_stack_id", + "type": "void" + } + ] ] } ] - ] + } } ] }, { - "name": "transactionMap", + "name": "transaction_data", "type": [ "switch", { @@ -766,7 +960,7 @@ "fields": { "TYPE_NORMAL": "void", "TYPE_INVENTORY_MISMATCH": "void", - "TYPE_USE_ITEM": [ + "TYPE_ITEM_USE": [ "container", [ { @@ -863,7 +1057,7 @@ "container", [ { - "name": "network_id", + "name": "runtime_id", "type": "zigzag32" }, { @@ -1431,7 +1625,8 @@ } ] ] - } + }, + "default": "void" } ] }, @@ -1464,97 +1659,139 @@ ] }, { - "name": "entries", + "anon": true, "type": [ - "array", + "switch", { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "li64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "remove": [ + "compareTo": "type", + "fields": { + "remove": [ + "container", + [ + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ "container", [ { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" - } - } - ] + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" }, { "anon": true, "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": [ - "container", - [ - { - "name": "entity_unique_id", - "type": "zigzag64" + "container", + [ + { + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" } - ] - ], - "entity": [ - "container", - [ - { - "name": "entity_unique_id", - "type": "zigzag64" + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": [ + "container", + [ + { + "name": "entity_unique_id", + "type": "zigzag64" + } + ] + ], + "entity": [ + "container", + [ + { + "name": "entity_unique_id", + "type": "zigzag64" + } + ] + ], + "fake_player": [ + "container", + [ + { + "name": "custom_name", + "type": "string" + } + ] + ] } - ] - ], - "fake_player": [ - "container", - [ - { - "name": "custom_name", - "type": "string" - } - ] + } ] } - } + ] ] } ] - ], - "change": "void" + ] } - } - ] - } + ] + } + ] + ], + "change": [ + "container", + [ + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": "void" + } + ] + ] + } + ] + } + ] ] - ] + } } ] } @@ -1577,41 +1814,67 @@ ] }, { - "name": "entries", + "anon": true, "type": [ - "array", + "switch", { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "TYPE_REGISTER_IDENTITY": [ + "compareTo": "type", + "fields": { + "TYPE_REGISTER_IDENTITY": [ + "container", + [ + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ "container", [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, { "name": "entity_unique_id", "type": "zigzag64" } ] ] - }, - "default": "void" - } - ] - } + } + ] + } + ] + ], + "TYPE_CLEAR_IDENTITY": [ + "container", + [ + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "anon": true, + "type": "void" + } + ] + ] + } + ] + } + ] ] - ] + } } ] } @@ -2020,7 +2283,7 @@ "type": [ "mapper", { - "type": "u8", + "type": "varint", "mappings": { "0x01": "login", "0x02": "play_status", @@ -2402,11 +2665,11 @@ "type": "bool" }, { - "name": "behavior_pack_id_versions", + "name": "behavior_packs", "type": "ResourcePackIdVersions" }, { - "name": "resource_pack_id_versions", + "name": "resource_packs", "type": "ResourcePackIdVersions" }, { @@ -2415,7 +2678,7 @@ }, { "name": "experiments", - "type": "li32" + "type": "Experiments" }, { "name": "experiments_previously_toggled", @@ -3644,7 +3907,7 @@ "type": "BlockCoordinates" }, { - "name": "namedtag", + "name": "nbt", "type": "nbt" } ] @@ -3686,8 +3949,8 @@ "type": "varint" }, { - "name": "cache_enabled", - "type": "bool" + "name": "column", + "type": "Chunks" } ] ], @@ -3941,7 +4204,7 @@ "type": "string" }, { - "name": "namedtag", + "name": "nbt", "type": "nbt" } ] @@ -3966,7 +4229,7 @@ "type": "zigzag64" }, { - "name": "namedtag", + "name": "nbt", "type": "nbt" } ] @@ -4324,15 +4587,7 @@ } ] ], - "packet_set_score": [ - "container", - [ - { - "name": "entries", - "type": "ScoreEntries" - } - ] - ], + "packet_set_score": "ScoreEntries", "packet_lab_table": [ "container", [ @@ -4473,7 +4728,7 @@ "container", [ { - "name": "namedtag", + "name": "nbt", "type": "nbt" } ] @@ -4524,7 +4779,7 @@ "container", [ { - "name": "namedtag", + "name": "nbt", "type": "nbt" } ] @@ -4620,7 +4875,7 @@ "container", [ { - "name": "namedtag", + "name": "nbt", "type": "nbt" } ] @@ -4650,7 +4905,7 @@ "container", [ { - "name": "input", + "name": "items", "type": "ItemStacks" } ] diff --git a/src/server.js b/src/server.js index c4eaeb7..636f104 100644 --- a/src/server.js +++ b/src/server.js @@ -3,7 +3,6 @@ const Listener = require('@jsprismarine/raknet/listener') const { ProtoDef, Parser, Serializer } = require('protodef') const BatchPacket = require('./BatchPacket') const { EventEmitter } = require('events') -const fs = require('fs') const cipher = require('./transforms/encryption') const { Encrypt } = require('./auth/encryption') @@ -285,80 +284,4 @@ class Server extends EventEmitter { } } -let CreativeItems = require('../data/creativeitems.json') -let NBT = require('prismarine-nbt') - -let server = new Server({ - -}) -server.create('0.0.0.0', 19130) - -let ran = false - -server.on('connect', ({ client }) => { - /** @type {Player} */ - client.on('join', () => { - console.log('Client joined', client.getData()) - - - // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It - // sends a list of the resource packs it has and basic information on them like the version and description. - client.write('resource_packs_info', { - 'must_accept': false, - 'has_scripts': false, - 'behaviour_packs': [], - 'texture_packs': [] - }) - - client.once('resource_pack_client_response', (packet) => { - // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs - // should be applied (and downloaded) by the client. - client.write('resource_pack_stack', { - 'must_accept': false, - 'behavior_packs': [], - 'resource_packs': [], - 'game_version': '', - 'experiments': [], - 'experiments_previously_toggled': false - }) - - client.once('resource_pack_client_response', async (packet) => { - if (ran === true) throw 'Already sent' - ran = true - let items = [] - let ids = 0 - for (var item of CreativeItems) { - let creativeitem = { runtime_id: items.length } - if (item.id != 0) { - const hasNbt = !!item.nbt_b64 - creativeitem.item = { - network_id: item.id, - auxiliary_value: item.damage || 0, - has_nbt: hasNbt|0, - nbt_version: 1, - blocking_tick: 0, - can_destroy: [], - can_place_on: [] - } - if (hasNbt) { - let nbtBuf = Buffer.from(item.nbt_b64, 'base64') - let { result } = await NBT.parse(nbtBuf, 'little') - creativeitem.item.nbt = result - } - } - items.push(creativeitem) - // console.log(creativeitem) - } - - console.log(items, ids) - - client.write('creative_content', { items }) - - setTimeout(() => { - const biomeDefs = fs.readFileSync('../data/biome_definitions.nbt') - client.writeRaw('biome_definition_list', biomeDefs) - }, 1000) - }) - }) - }) -}) \ No newline at end of file +module.exports = { Server, Player, PLAY_STATUS } \ No newline at end of file diff --git a/src/serverTest.js b/src/serverTest.js new file mode 100644 index 0000000..aa356fc --- /dev/null +++ b/src/serverTest.js @@ -0,0 +1,79 @@ +const { Server } = require('./server') +const CreativeItems = require('../data/creativeitems.json') +const NBT = require('prismarine-nbt') +const fs = require('fs') + +let server = new Server({ + +}) +server.create('0.0.0.0', 19130) + +let ran = false + +server.on('connect', ({ client }) => { + /** @type {Player} */ + client.on('join', () => { + console.log('Client joined', client.getData()) + + // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It + // sends a list of the resource packs it has and basic information on them like the version and description. + client.write('resource_packs_info', { + 'must_accept': false, + 'has_scripts': false, + 'behaviour_packs': [], + 'texture_packs': [] + }) + + client.once('resource_pack_client_response', (packet) => { + // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs + // should be applied (and downloaded) by the client. + client.write('resource_pack_stack', { + 'must_accept': false, + 'behavior_packs': [], + 'resource_packs': [], + 'game_version': '', + 'experiments': [], + 'experiments_previously_toggled': false + }) + + client.once('resource_pack_client_response', async (packet) => { + ran = true + let items = [] + let ids = 0 + for (var item of CreativeItems) { + let creativeitem = { runtime_id: items.length } + if (item.id != 0) { + const hasNbt = !!item.nbt_b64 + creativeitem.item = { + network_id: item.id, + auxiliary_value: item.damage || 0, + has_nbt: hasNbt|0, + nbt_version: 1, + blocking_tick: 0, + can_destroy: [], + can_place_on: [] + } + if (hasNbt) { + let nbtBuf = Buffer.from(item.nbt_b64, 'base64') + let { result } = await NBT.parse(nbtBuf, 'little') + creativeitem.item.nbt = result + } + } + items.push(creativeitem) + // console.log(creativeitem) + } + + console.log(items, ids) + + client.write('creative_content', { items }) + // wait a bit just for easier debugging + setTimeout(() => { + const biomeDefs = fs.readFileSync('../data/biome_definitions.nbt') + client.writeRaw('biome_definition_list', biomeDefs) + + // TODO: send chunks so we can spawn player + }, 1000) + }) + }) + }) +}) \ No newline at end of file From 73d4dd1325efc7d6f51d42dfab494ed74a5e7126 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 7 Feb 2021 05:25:22 -0500 Subject: [PATCH 087/458] protocol def updates --- data/new/compile.js | 15 + data/new/proto.yml | 1426 +++++++++++++++++++++++++++++++++++++++++++ data/new/types.yaml | 457 ++++++++++++++ data/newproto.json | 1067 +++++++++++++------------------- 4 files changed, 2322 insertions(+), 643 deletions(-) create mode 100644 data/new/compile.js create mode 100644 data/new/proto.yml create mode 100644 data/new/types.yaml diff --git a/data/new/compile.js b/data/new/compile.js new file mode 100644 index 0000000..8a3b575 --- /dev/null +++ b/data/new/compile.js @@ -0,0 +1,15 @@ +const fs = require('fs') + +let compile +try { + compile = require('protodef-yaml/compiler') +} catch (e) { + require('child_process').execSync('npx protodef-yaml proto.yml protocol.json') +} + +if (compile) { + compile('./proto.yml', 'protocol.json') +} + +fs.writeFileSync( '../newproto.json', JSON.stringify({ types: require('./protocol.json') }, null, 2) ) +fs.unlinkSync('./protocol.json') //remove temp file \ No newline at end of file diff --git a/data/new/proto.yml b/data/new/proto.yml new file mode 100644 index 0000000..37f7f0a --- /dev/null +++ b/data/new/proto.yml @@ -0,0 +1,1426 @@ +# Created from MiNET docs +string: ["pstring",{"countType":"varint"}] +ByteArray: ["buffer",{"countType":"varint"}] +LittleString: ["pstring",{"countType":"li32"}] +varint32: varint +varint64: varint +bool: native +zigzag32: native +zigzag64: native +uuid: native +byterot: native +MapInfo: native +nbt: native + +!import: types.yaml + +mcpe_packet: + name: varint => + 0x01: login + 0x02: play_status + 0x03: server_to_client_handshake + 0x04: client_to_server_handshake + 0x05: disconnect + 0x06: resource_packs_info + 0x07: resource_pack_stack + 0x08: resource_pack_client_response + 0x09: text + 0x0a: set_time + 0x0b: start_game + 0x0c: add_player + 0x0d: add_entity + 0x0e: remove_entity + 0x0f: add_item_entity + 0x11: take_item_entity + 0x12: move_entity + 0x13: move_player + 0x14: rider_jump + 0x15: update_block + 0x16: add_painting + 0x17: tick_sync + 0x18: level_sound_event_old + 0x19: level_event + 0x1a: block_event + 0x1b: entity_event + 0x1c: mob_effect + 0x1d: update_attributes + 0x1e: inventory_transaction + 0x1f: mob_equipment + 0x20: mob_armor_equipment + 0x21: interact + 0x22: block_pick_request + 0x23: entity_pick_request + 0x24: player_action + 0x26: hurt_armor + 0x27: set_entity_data + 0x28: set_entity_motion + 0x29: set_entity_link + 0x2a: set_health + 0x2b: set_spawn_position + 0x2c: animate + 0x2d: respawn + 0x2e: container_open + 0x2f: container_close + 0x30: player_hotbar + 0x31: inventory_content + 0x32: inventory_slot + 0x33: container_set_data + 0x34: crafting_data + 0x35: crafting_event + 0x36: gui_data_pick_item + 0x37: adventure_settings + 0x38: block_entity_data + 0x39: player_input + 0x3a: level_chunk + 0x3b: set_commands_enabled + 0x3c: set_difficulty + 0x3d: change_dimension + 0x3e: set_player_game_type + 0x3f: player_list + 0x40: simple_event + 0x42: spawn_experience_orb + 0x43: clientbound_map_item_data + 0x44: map_info_request + 0x45: request_chunk_radius + 0x46: chunk_radius_update + 0x47: item_frame_drop_item + 0x48: game_rules_changed + 0x49: camera + 0x4a: boss_event + 0x4b: show_credits + 0x4c: available_commands + 0x4d: command_request + 0x4e: command_block_update + 0x4f: command_output + 0x50: update_trade + 0x51: update_equipment + 0x52: resource_pack_data_info + 0x53: resource_pack_chunk_data + 0x54: resource_pack_chunk_request + 0x55: transfer + 0x56: play_sound + 0x57: stop_sound + 0x58: set_title + 0x59: add_behavior_tree + 0x5a: structure_block_update + 0x5b: show_store_offer + 0x5c: purchase_receipt + 0x5d: player_skin + 0x5e: sub_client_login + 0x5f: initiate_web_socket_connection + 0x60: set_last_hurt_by + 0x61: book_edit + 0x62: npc_request + 0x63: photo_transfer + 0x64: modal_form_request + 0x65: modal_form_response + 0x66: server_settings_request + 0x67: server_settings_response + 0x68: show_profile + 0x69: set_default_game_type + 0x6a: remove_objective + 0x6b: set_display_objective + 0x6c: set_score + 0x6d: lab_table + 0x6e: update_block_synced + 0x6f: move_entity_delta + 0x70: set_scoreboard_identity + 0x71: set_local_player_as_initialized + 0x72: update_soft_enum + 0x73: network_stack_latency + 0x75: script_custom_event + 0x76: spawn_particle_effect + 0x77: available_entity_identifiers + 0x78: level_sound_event_v2 + 0x79: network_chunk_publisher_update + 0x7a: biome_definition_list + 0x7b: level_sound_event + 0x7c: level_event_generic + 0x7d: lectern_update + 0x7e: video_stream_connect + 0x81: client_cache_status + 0x82: on_screen_texture_animation + 0x83: map_create_locked_copy + 0x84: structure_template_data_export_request + 0x85: structure_template_data_export_response + 0x86: update_block_properties + 0x87: client_cache_blob_status + 0x88: client_cache_miss_response + 0x8f: network_settings + 0x91: creative_content + 0x92: player_enchant_options + 0x93: item_stack_request + 0x94: item_stack_response + 0x97: update_player_game_type + 0x9c: packet_violation_warning + 0xa2: item_component + 0xa3: filter_text_packet + params: name ? + if login: packet_login + if play_status: packet_play_status + if server_to_client_handshake: packet_server_to_client_handshake + if client_to_server_handshake: packet_client_to_server_handshake + if disconnect: packet_disconnect + if resource_packs_info: packet_resource_packs_info + if resource_pack_stack: packet_resource_pack_stack + if resource_pack_client_response: packet_resource_pack_client_response + if text: packet_text + if set_time: packet_set_time + if start_game: packet_start_game + if add_player: packet_add_player + if add_entity: packet_add_entity + if remove_entity: packet_remove_entity + if add_item_entity: packet_add_item_entity + if take_item_entity: packet_take_item_entity + if move_entity: packet_move_entity + if move_player: packet_move_player + if rider_jump: packet_rider_jump + if update_block: packet_update_block + if add_painting: packet_add_painting + if tick_sync: packet_tick_sync + if level_sound_event_old: packet_level_sound_event_old + if level_event: packet_level_event + if block_event: packet_block_event + if entity_event: packet_entity_event + if mob_effect: packet_mob_effect + if update_attributes: packet_update_attributes + if inventory_transaction: packet_inventory_transaction + if mob_equipment: packet_mob_equipment + if mob_armor_equipment: packet_mob_armor_equipment + if interact: packet_interact + if block_pick_request: packet_block_pick_request + if entity_pick_request: packet_entity_pick_request + if player_action: packet_player_action + if hurt_armor: packet_hurt_armor + if set_entity_data: packet_set_entity_data + if set_entity_motion: packet_set_entity_motion + if set_entity_link: packet_set_entity_link + if set_health: packet_set_health + if set_spawn_position: packet_set_spawn_position + if animate: packet_animate + if respawn: packet_respawn + if container_open: packet_container_open + if container_close: packet_container_close + if player_hotbar: packet_player_hotbar + if inventory_content: packet_inventory_content + if inventory_slot: packet_inventory_slot + if container_set_data: packet_container_set_data + if crafting_data: packet_crafting_data + if crafting_event: packet_crafting_event + if gui_data_pick_item: packet_gui_data_pick_item + if adventure_settings: packet_adventure_settings + if block_entity_data: packet_block_entity_data + if player_input: packet_player_input + if level_chunk: packet_level_chunk + if set_commands_enabled: packet_set_commands_enabled + if set_difficulty: packet_set_difficulty + if change_dimension: packet_change_dimension + if set_player_game_type: packet_set_player_game_type + if player_list: packet_player_list + if simple_event: packet_simple_event + if spawn_experience_orb: packet_spawn_experience_orb + if clientbound_map_item_data: packet_clientbound_map_item_data + if map_info_request: packet_map_info_request + if request_chunk_radius: packet_request_chunk_radius + if chunk_radius_update: packet_chunk_radius_update + if item_frame_drop_item: packet_item_frame_drop_item + if game_rules_changed: packet_game_rules_changed + if camera: packet_camera + if boss_event: packet_boss_event + if show_credits: packet_show_credits + if available_commands: packet_available_commands + if command_request: packet_command_request + if command_block_update: packet_command_block_update + if command_output: packet_command_output + if update_trade: packet_update_trade + if update_equipment: packet_update_equipment + if resource_pack_data_info: packet_resource_pack_data_info + if resource_pack_chunk_data: packet_resource_pack_chunk_data + if resource_pack_chunk_request: packet_resource_pack_chunk_request + if transfer: packet_transfer + if play_sound: packet_play_sound + if stop_sound: packet_stop_sound + if set_title: packet_set_title + if add_behavior_tree: packet_add_behavior_tree + if structure_block_update: packet_structure_block_update + if show_store_offer: packet_show_store_offer + if purchase_receipt: packet_purchase_receipt + if player_skin: packet_player_skin + if sub_client_login: packet_sub_client_login + if initiate_web_socket_connection: packet_initiate_web_socket_connection + if set_last_hurt_by: packet_set_last_hurt_by + if book_edit: packet_book_edit + if npc_request: packet_npc_request + if photo_transfer: packet_photo_transfer + if modal_form_request: packet_modal_form_request + if modal_form_response: packet_modal_form_response + if server_settings_request: packet_server_settings_request + if server_settings_response: packet_server_settings_response + if show_profile: packet_show_profile + if set_default_game_type: packet_set_default_game_type + if remove_objective: packet_remove_objective + if set_display_objective: packet_set_display_objective + if set_score: packet_set_score + if lab_table: packet_lab_table + if update_block_synced: packet_update_block_synced + if move_entity_delta: packet_move_entity_delta + if set_scoreboard_identity: packet_set_scoreboard_identity + if set_local_player_as_initialized: packet_set_local_player_as_initialized + if update_soft_enum: packet_update_soft_enum + if network_stack_latency: packet_network_stack_latency + if script_custom_event: packet_script_custom_event + if spawn_particle_effect: packet_spawn_particle_effect + if available_entity_identifiers: packet_available_entity_identifiers + if level_sound_event_v2: packet_level_sound_event_v2 + if network_chunk_publisher_update: packet_network_chunk_publisher_update + if biome_definition_list: packet_biome_definition_list + if level_sound_event: packet_level_sound_event + if level_event_generic: packet_level_event_generic + if lectern_update: packet_lectern_update + if video_stream_connect: packet_video_stream_connect + if client_cache_status: packet_client_cache_status + if on_screen_texture_animation: packet_on_screen_texture_animation + if map_create_locked_copy: packet_map_create_locked_copy + if structure_template_data_export_request: packet_structure_template_data_export_request + if structure_template_data_export_response: packet_structure_template_data_export_response + if update_block_properties: packet_update_block_properties + if client_cache_blob_status: packet_client_cache_blob_status + if client_cache_miss_response: packet_client_cache_miss_response + if network_settings: packet_network_settings + if creative_content: packet_creative_content + if player_enchant_options: packet_player_enchant_options + if item_stack_request: packet_item_stack_request + if item_stack_response: packet_item_stack_response + if update_player_game_type: packet_update_player_game_type + if packet_violation_warning: packet_packet_violation_warning + if item_component: packet_item_component + if filter_text_packet: packet_filter_text_packet + +packet_login: + !id: 0x01 + !server: false + !client: true + protocol_version: i32 + payload_size: varint + chain: LittleString + client_data: LittleString + +packet_play_status: + !id: 0x02 + !server: true + !client: false + status: i32 + +packet_server_to_client_handshake: + !id: 0x03 + !server: true + !client: false + token: string + +packet_client_to_server_handshake: + !id: 0x04 + !server: false + !client: true + +packet_disconnect: + !id: 0x05 + !server: true + !client: false + hide_disconnect_reason: bool + message: string + +packet_resource_packs_info: + !id: 0x06 + !server: true + !client: false + must_accept: bool + has_scripts: bool + behaviour_packs: BehaviourPackInfos + texture_packs: TexturePackInfos + +packet_resource_pack_stack: + !id: 0x07 + !server: true + !client: false + must_accept: bool + behavior_packs: ResourcePackIdVersions + resource_packs: ResourcePackIdVersions + game_version: string + experiments: Experiments + experiments_previously_toggled: bool + +packet_resource_pack_client_response: + !id: 0x08 + !server: false + !client: true + response_status: u8 + resourcepackids: ResourcePackIds + +packet_text: + !id: 0x09 + !server: true + !client: true + type: u8 + +packet_set_time: + !id: 0x0a + !server: true + !client: false + time: zigzag32 + +packet_start_game: + !id: 0x0b + !server: true + !client: false + entity_id: zigzag64 + runtime_entity_id: varint + player_gamemode: zigzag32 + spawn: vec3f + rotation: vec3f + seed: zigzag32 + biome_type: li16 + biome_name: string + dimension: zigzag32 + generator: zigzag32 + gamemode: zigzag32 + difficulty: zigzag32 + x: zigzag32 + y: varint + z: zigzag32 + has_achievements_disabled: bool + day_cycle_stop_time: zigzag32 + edu_offer: zigzag32 + has_edu_features_enabled: bool + edu_product_uuid_: string + rain_level: lf32 + lightning_level: lf32 + has_confirmed_platform_locked_content: bool + is_multiplayer: bool + broadcast_to_lan: bool + xbox_live_broadcast_mode: varint + platform_broadcast_mode: varint + enable_commands: bool + is_texturepacks_required: bool + gamerules: GameRules + experiments: Experiments + experiments_previously_toggled: bool + bonus_chest: bool + map_enabled: bool + permission_level: zigzag32 + server_chunk_tick_range: li32 + has_locked_behavior_pack: bool + has_locked_resource_pack: bool + is_from_locked_world_template: bool + msa_gamertags_only: bool + is_from_world_template: bool + is_world_template_option_locked: bool + only_spawn_v1_villagers: bool + game_version: string + limited_world_width_: li32 + limited_world_length_: li32 + is_new_nether_: bool + experimental_gameplay_override: bool + level_id: string + world_name: string + premium_world_template_id: string + is_trial: bool + movement_type: zigzag32 + current_tick: li64 + enchantment_seed: zigzag32 + block_palette: BlockPalette + itemstates: Itemstates + multiplayer_correlation_id: string + server_authoritative_inventory: bool + +packet_add_player: + !id: 0x0c + !server: true + !client: false + uuid: uuid + username: string + entity_id_self: zigzag64 + runtime_entity_id: varint + platform_chat_id: string + x: lf32 + y: lf32 + z: lf32 + speed_x: lf32 + speed_y: lf32 + speed_z: lf32 + pitch: lf32 + yaw: lf32 + head_yaw: lf32 + held_item: Item + metadata: MetadataDictionary + flags: varint + command_permission: varint + action_permissions: varint + permission_level: varint + custom_stored_permissions: varint + user_id: li64 + links: Links + device_id: string + device_os: li32 + +packet_add_entity: + !id: 0x0d + !server: true + !client: false + entity_id_self: zigzag64 + runtime_entity_id: varint + entity_type: string + x: lf32 + y: lf32 + z: lf32 + speed_x: lf32 + speed_y: lf32 + speed_z: lf32 + pitch: lf32 + yaw: lf32 + head_yaw: lf32 + attributes: EntityAttributes + metadata: MetadataDictionary + links: Links + +packet_remove_entity: + !id: 0x0e + !server: true + !client: false + entity_id_self: zigzag64 + +packet_add_item_entity: + !id: 0x0f + !server: true + !client: false + entity_id_self: zigzag64 + runtime_entity_id: varint + item: Item + x: lf32 + y: lf32 + z: lf32 + speed_x: lf32 + speed_y: lf32 + speed_z: lf32 + metadata: MetadataDictionary + is_from_fishing: bool + +packet_take_item_entity: + !id: 0x11 + !server: true + !client: false + runtime_entity_id: varint + target: varint + +packet_move_entity: + !id: 0x12 + !server: true + !client: true + runtime_entity_id: varint + flags: u8 + position: vec3f + rotation: Rotation + +packet_move_player: + !id: 0x13 + !server: true + !client: true + runtime_entity_id: varint + x: lf32 + y: lf32 + z: lf32 + pitch: lf32 + yaw: lf32 + head_yaw: lf32 + mode: u8 + on_ground: bool + other_runtime_entity_id: varint + +packet_rider_jump: + !id: 0x14 + !server: true + !client: true + unknown: zigzag32 + +packet_update_block: + !id: 0x15 + !server: true + !client: false + coordinates: BlockCoordinates + block_runtime_id: varint + block_priority: varint + storage: varint + +packet_add_painting: + !id: 0x16 + !server: true + !client: false + entity_id_self: zigzag64 + runtime_entity_id: varint + coordinates: BlockCoordinates + direction: zigzag32 + title: string + +packet_tick_sync: + !id: 0x17 + !server: true + !client: true + request_time: li64 + response_time: li64 + +packet_level_sound_event_old: + !id: 0x18 + !server: true + !client: true + sound_id: u8 + position: vec3f + block_id: zigzag32 + entity_type: zigzag32 + is_baby_mob: bool + is_global: bool + +packet_level_event: + !id: 0x19 + !server: true + !client: false + event_id: zigzag32 + position: vec3f + data: zigzag32 + +packet_block_event: + !id: 0x1a + !server: true + !client: false + coordinates: BlockCoordinates + case_1: zigzag32 + case_2: zigzag32 + +packet_entity_event: + !id: 0x1b + !server: true + !client: true + runtime_entity_id: varint + event_id: u8 + data: zigzag32 + +packet_mob_effect: + !id: 0x1c + !server: true + !client: false + runtime_entity_id: varint + event_id: u8 + effect_id: zigzag32 + amplifier: zigzag32 + particles: bool + duration: zigzag32 + +packet_update_attributes: + !id: 0x1d + !server: true + !client: false + runtime_entity_id: varint + attributes: PlayerAttributes + tick: varint + +packet_inventory_transaction: + !id: 0x1e + !server: true + !client: true + transaction: Transaction + +packet_mob_equipment: + !id: 0x1f + !server: true + !client: true + runtime_entity_id: varint + item: Item + slot: u8 + selected_slot: u8 + windows_id: u8 + +packet_mob_armor_equipment: + !id: 0x20 + !server: true + !client: true + runtime_entity_id: varint + helmet: Item + chestplate: Item + leggings: Item + boots: Item + +packet_interact: + !id: 0x21 + !server: true + !client: true + action_id: u8 + target_runtime_entity_id: varint + +packet_block_pick_request: + !id: 0x22 + !server: false + !client: true + x: zigzag32 + y: zigzag32 + z: zigzag32 + add_user_data: bool + selected_slot: u8 + +packet_entity_pick_request: + !id: 0x23 + !server: false + !client: true + runtime_entity_id: lu64 + selected_slot: u8 + +packet_player_action: + !id: 0x24 + !server: false + !client: true + runtime_entity_id: varint + action_id: zigzag32 + coordinates: BlockCoordinates + face: zigzag32 + +packet_hurt_armor: + !id: 0x26 + !server: true + !client: false + health: zigzag32 + +packet_set_entity_data: + !id: 0x27 + !server: true + !client: true + runtime_entity_id: varint + metadata: MetadataDictionary + tick: varint + +packet_set_entity_motion: + !id: 0x28 + !server: true + !client: true + runtime_entity_id: varint + velocity: vec3f + +packet_set_entity_link: + !id: 0x29 + !server: true + !client: false + ridden_id: zigzag64 + rider_id: zigzag64 + link_type: u8 + unknown: u8 + +packet_set_health: + !id: 0x2a + !server: true + !client: false + health: zigzag32 + +packet_set_spawn_position: + !id: 0x2b + !server: true + !client: false + spawn_type: zigzag32 + coordinates: BlockCoordinates + dimension: zigzag32 + unknown_coordinates: BlockCoordinates + +packet_animate: + !id: 0x2c + !server: true + !client: true + action_id: zigzag32 + runtime_entity_id: varint + +packet_respawn: + !id: 0x2d + !server: true + !client: true + x: lf32 + y: lf32 + z: lf32 + state: u8 + runtime_entity_id: varint + +packet_container_open: + !id: 0x2e + !server: true + !client: false + window_id: u8 + type: u8 + coordinates: BlockCoordinates + runtime_entity_id: zigzag64 + +packet_container_close: + !id: 0x2f + !server: true + !client: true + window_id: u8 + server: bool + +packet_player_hotbar: + !id: 0x30 + !server: true + !client: true + selected_slot: varint + window_id: u8 + select_slot_: bool + +packet_inventory_content: + !id: 0x31 + !server: true + !client: true + inventory_id: varint + input: ItemStacks + +packet_inventory_slot: + !id: 0x32 + !server: true + !client: true + inventory_id: varint + slot: varint + uniqueid: zigzag32 + item: Item + +packet_container_set_data: + !id: 0x33 + !server: true + !client: false + window_id: u8 + property: zigzag32 + value: zigzag32 + +packet_crafting_data: + !id: 0x34 + !server: true + !client: false + recipes: Recipes + potion_type_recipes: PotionTypeRecipes + potion_container_recipes: PotionContainerChangeRecipes + is_clean: bool + +packet_crafting_event: + !id: 0x35 + !server: true + !client: true + window_id: u8 + recipe_type: zigzag32 + recipe_id: uuid + input: ItemStacks + result: ItemStacks + +packet_gui_data_pick_item: + !id: 0x36 + !server: true + !client: false + +packet_adventure_settings: + !id: 0x37 + !server: true + !client: true + flags: varint + command_permission: varint + action_permissions: varint + permission_level: varint + custom_stored_permissions: varint + user_id: li64 + +packet_block_entity_data: + !id: 0x38 + !server: true + !client: true + coordinates: BlockCoordinates + nbt: nbt + +packet_player_input: + !id: 0x39 + !server: false + !client: true + motion_x: lf32 + motion_z: lf32 + jumping: bool + sneaking: bool + +packet_level_chunk: + !id: 0x3a + !server: true + !client: false + chunk_x: zigzag32 + chunk_z: zigzag32 + sub_chunk_count: varint + column: Chunks + +packet_set_commands_enabled: + !id: 0x3b + !server: true + !client: false + enabled: bool + +packet_set_difficulty: + !id: 0x3c + !server: true + !client: false + difficulty: varint + +packet_change_dimension: + !id: 0x3d + !server: true + !client: false + dimension: zigzag32 + position: vec3f + respawn: bool + +packet_set_player_game_type: + !id: 0x3e + !server: true + !client: true + gamemode: zigzag32 + +packet_player_list: + !id: 0x3f + !server: true + !client: false + records: PlayerRecords + +packet_simple_event: + !id: 0x40 + !server: true + !client: false + event_type: lu16 + +packet_spawn_experience_orb: + !id: 0x42 + !server: true + !client: false + position: vec3f + count: zigzag32 + +packet_clientbound_map_item_data: + !id: 0x43 + !server: true + !client: false + mapinfo: MapInfo + +packet_map_info_request: + !id: 0x44 + !server: true + !client: true + map_id: zigzag64 + +packet_request_chunk_radius: + !id: 0x45 + !server: true + !client: true + chunk_radius: zigzag32 + +packet_chunk_radius_update: + !id: 0x46 + !server: true + !client: false + chunk_radius: zigzag32 + +packet_item_frame_drop_item: + !id: 0x47 + !server: true + !client: true + coordinates: BlockCoordinates + +packet_game_rules_changed: + !id: 0x48 + !server: true + !client: false + rules: GameRules + +packet_camera: + !id: 0x49 + !server: true + !client: false + unknown1: zigzag64 + unknown2: zigzag64 + +packet_boss_event: + !id: 0x4a + !server: true + !client: false + boss_entity_id: zigzag64 + event_type: varint + +packet_show_credits: + !id: 0x4b + !server: true + !client: false + runtime_entity_id: varint + status: zigzag32 + +packet_available_commands: + !id: 0x4c + !server: true + !client: false + +packet_command_request: + !id: 0x4d + !server: false + !client: true + command: string + command_type: varint + unknown_uuid: uuid + request_id: string + unknown: bool + +packet_command_block_update: + !id: 0x4e + !server: false + !client: true + is_block: bool + +packet_command_output: + !id: 0x4f + !server: true + !client: false + +packet_update_trade: + !id: 0x50 + !server: true + !client: false + window_id: u8 + window_type: u8 + unknown0: varint + unknown1: varint + unknown2: varint + is_willing: bool + trader_entity_id: zigzag64 + player_entity_id: zigzag64 + display_name: string + nbt: nbt + +packet_update_equipment: + !id: 0x51 + !server: true + !client: false + window_id: u8 + window_type: u8 + unknown: u8 + entity_id: zigzag64 + nbt: nbt + +packet_resource_pack_data_info: + !id: 0x52 + !server: true + !client: false + package_id: string + max_chunk_size: lu32 + chunk_count: lu32 + compressed_package_size: lu64 + hash: ByteArray + is_premium: bool + pack_type: u8 + +packet_resource_pack_chunk_data: + !id: 0x53 + !server: true + !client: false + package_id: string + chunk_index: lu32 + progress: lu64 + payload: ByteArray + +packet_resource_pack_chunk_request: + !id: 0x54 + !server: false + !client: true + package_id: string + chunk_index: lu32 + +packet_transfer: + !id: 0x55 + !server: true + !client: false + server_address: string + port: lu16 + +packet_play_sound: + !id: 0x56 + !server: true + !client: false + name: string + coordinates: BlockCoordinates + volume: lf32 + pitch: lf32 + +packet_stop_sound: + !id: 0x57 + !server: true + !client: false + name: string + stop_all: bool + +packet_set_title: + !id: 0x58 + !server: true + !client: false + type: zigzag32 + text: string + fade_in_time: zigzag32 + stay_time: zigzag32 + fade_out_time: zigzag32 + +packet_add_behavior_tree: + !id: 0x59 + !server: true + !client: false + behaviortree: string + +packet_structure_block_update: + !id: 0x5a + !server: true + !client: false + +packet_show_store_offer: + !id: 0x5b + !server: true + !client: false + unknown0: string + unknown1: bool + +packet_purchase_receipt: + !id: 0x5c + !server: false + !client: true + +packet_player_skin: + !id: 0x5d + !server: true + !client: true + uuid: uuid + skin: Skin + skin_name: string + old_skin_name: string + is_verified: bool + +packet_sub_client_login: + !id: 0x5e + !server: true + !client: false + +packet_initiate_web_socket_connection: + !id: 0x5f + !server: true + !client: false + server: string + +packet_set_last_hurt_by: + !id: 0x60 + !server: true + !client: false + unknown: varint + +packet_book_edit: + !id: 0x61 + !server: true + !client: false + +packet_npc_request: + !id: 0x62 + !server: true + !client: true + runtime_entity_id: varint + unknown0: u8 + unknown1: string + unknown2: u8 + +packet_photo_transfer: + !id: 0x63 + !server: false + !client: true + file_name: string + image_data: string + unknown2: string + +packet_modal_form_request: + !id: 0x64 + !server: true + !client: false + form_id: varint + data: string + +packet_modal_form_response: + !id: 0x65 + !server: false + !client: true + form_id: varint + data: string + +packet_server_settings_request: + !id: 0x66 + !server: false + !client: true + +packet_server_settings_response: + !id: 0x67 + !server: true + !client: false + form_id: varint + data: string + +packet_show_profile: + !id: 0x68 + !server: true + !client: false + xuid: string + +packet_set_default_game_type: + !id: 0x69 + !server: true + !client: false + gamemode: varint + +packet_remove_objective: + !id: 0x6a + !server: true + !client: false + objective_name: string + +packet_set_display_objective: + !id: 0x6b + !server: true + !client: false + display_slot: string + objective_name: string + display_name: string + criteria_name: string + sort_order: zigzag32 + +packet_set_score: + !id: 0x6c + !server: true + !client: false + entries: ScoreEntries + +packet_lab_table: + !id: 0x6d + !server: true + !client: true + useless_byte: u8 + lab_table_x: varint + lab_table_y: varint + lab_table_z: varint + reaction_type: u8 + +packet_update_block_synced: + !id: 0x6e + !server: true + !client: false + coordinates: BlockCoordinates + block_runtime_id: varint + block_priority: varint + data_layer_id: varint + unknown0: varint + unknown1: varint + +packet_move_entity_delta: + !id: 0x6f + !server: true + !client: false + runtime_entity_id: varint + flags: lu16 + +packet_set_scoreboard_identity: + !id: 0x70 + !server: true + !client: false + entries: ScoreboardIdentityEntries + +packet_set_local_player_as_initialized: + !id: 0x71 + !server: false + !client: true + runtime_entity_id: varint + +packet_update_soft_enum: + !id: 0x72 + !server: true + !client: false + +packet_network_stack_latency: + !id: 0x73 + !server: true + !client: true + timestamp: lu64 + unknown_flag: u8 + +packet_script_custom_event: + !id: 0x75 + !server: true + !client: true + event_name: string + event_data: string + +packet_spawn_particle_effect: + !id: 0x76 + !server: true + !client: false + dimension_id: u8 + entity_id: zigzag64 + position: vec3f + particle_name: string + +packet_available_entity_identifiers: + !id: 0x77 + !server: true + !client: false + nbt: nbt + +packet_level_sound_event_v2: + !id: 0x78 + !server: true + !client: true + sound_id: u8 + position: vec3f + block_id: zigzag32 + entity_type: string + is_baby_mob: bool + is_global: bool + +packet_network_chunk_publisher_update: + !id: 0x79 + !server: true + !client: false + coordinates: BlockCoordinates + radius: varint + +packet_biome_definition_list: + !id: 0x7a + !server: true + !client: false + nbt: nbt + +packet_level_sound_event: + !id: 0x7b + !server: true + !client: true + sound_id: varint + position: vec3f + block_id: zigzag32 + entity_type: string + is_baby_mob: bool + is_global: bool + +packet_level_event_generic: + !id: 0x7c + !server: true + !client: false + +packet_lectern_update: + !id: 0x7d + !server: true + !client: false + +packet_video_stream_connect: + !id: 0x7e + !server: true + !client: false + server_uri: string + frame_send_frequency: lf32 + action: u8 + resolution_x: li32 + resolution_y: li32 + +packet_client_cache_status: + !id: 0x81 + !server: true + !client: true + enabled: bool + +packet_on_screen_texture_animation: + !id: 0x82 + !server: true + !client: false + +packet_map_create_locked_copy: + !id: 0x83 + !server: true + !client: false + +packet_structure_template_data_export_request: + !id: 0x84 + !server: true + !client: false + +packet_structure_template_data_export_response: + !id: 0x85 + !server: true + !client: false + +packet_update_block_properties: + !id: 0x86 + !server: true + !client: false + nbt: nbt + +packet_client_cache_blob_status: + !id: 0x87 + !server: true + !client: false + +packet_client_cache_miss_response: + !id: 0x88 + !server: true + !client: false + +packet_network_settings: + !id: 0x8f + !server: true + !client: true + unknown: u8 + compression_threshold: u8 + +packet_creative_content: + !id: 0x91 + !server: true + !client: false + items: ItemStacks + +packet_player_enchant_options: + !id: 0x92 + !server: true + !client: false + enchant_options: EnchantOptions + +packet_item_stack_request: + !id: 0x93 + !server: false + !client: true + requests: ItemStackRequests + +packet_item_stack_response: + !id: 0x94 + !server: true + !client: false + responses: ItemStackResponses + +packet_update_player_game_type: + !id: 0x97 + !server: false + !client: true + +packet_packet_violation_warning: + !id: 0x9c + !server: false + !client: true + violation_type: zigzag32 + severity: zigzag32 + packet_id: zigzag32 + reason: string + +packet_item_component: + !id: 0xa2 + !server: true + !client: false + entries: ItemComponentList + +packet_filter_text_packet: + !id: 0xa3 + !server: true + !client: false + text: string + from_server: bool diff --git a/data/new/types.yaml b/data/new/types.yaml new file mode 100644 index 0000000..c84339c --- /dev/null +++ b/data/new/types.yaml @@ -0,0 +1,457 @@ +BehaviourPackInfos: []li16 + uuid: string + version: string + size: lu64 + content_key: string + sub_pack_name: string + content_identity: string + has_scripts: bool + +TexturePackInfos: []li16 + uuid: string + version: string + size: lu64 + content_key: string + sub_pack_name: string + content_identity: string + has_scripts: bool + rtx_enabled: bool + +ResourcePackIdVersions: []varint + uuid: string + version: string + name: string + +ResourcePackIds: string[]varint + +Experiment: + name: string + enabled: bool + +Experiments: Experiment[]varint + +GameRule: + name: string + type: varint => + 1: bool + 2: int + 3: float + value: type? + if bool: bool + if int: varint + if float: lf32 + +GameRules: GameRule[]varint + +Chunks: + cache_enabled: bool + _: cache_enabled? + if true: void # TODO + if false: void + + +BlockPalette: []varint + name: string + state: nbt + +Itemstates: []varint + name: string + runtime_id: li16 + component_based: bool + +Item: + network_id: zigzag32 + _: network_id? + if 0: void + default: + auxiliary_value: zigzag32 + has_nbt: lu16 => + 0xffff: '1' + 0x0000: '0' + _: has_nbt? + if 1: + nbt_version: u8 + nbt: nbt + default: void + can_place_on: string[]zigzag32 + can_destroy: string[]zigzag32 + _: network_id? + if 355: + blocking_tick: zigzag64 + +vec3i: + x: zigzag32 + y: zigzag32 + z: zigzag32 + +vec3u: + x: varint + y: varint + z: varint + +vec3f: + x: lf32 + y: lf32 + z: lf32 + +vec2f: + x: lf32 + z: lf32 + +MetadataDictionary: []varint + key: varint + type: varint => + 0: BYTE + 1: SHORT + 2: INT + 3: FLOAT + 4: STRING + 5: COMPOUND_TAG + 6: POS + 7: LONG + 8: VECTOR3F + value: type? + if BYTE: i8 + if SHORT: li16 + if INT: zigzag32 + if FLOAT: lf32 + if STRING: string + if COMPOUND_TAG: nbt + if POS: vec3i + if LONG: zigzag64 + if VECTOR3F: li32 + +Links: []varint + ridden_entity_id: zigzag64 + rider_entity_id: zigzag64 + type: u8 + immediate: bool + rider_initiated: bool + +EntityAttributes: []varint + name: string + min: lf32 + value: lf32 + max: lf32 + +Rotation: + yaw: byterot + pitch: byterot + head_yaw: byterot + +BlockCoordinates: # mojang... + x: zigzag32 + y: varint + z: zigzag32 + +PlayerAttributes: []varint + min: lf32 + max: lf32 + current: lf32 + default: lf32 + name: string + +Transaction: + legacy_request_id: zigzag32 + legacy_transactions: legacy_request_id? + if 0: void + default: []varint + container_id: u8 + changed_slots: []varint + slot_id: u8 + transaction_type: varint => + 0: TYPE_NORMAL + 1: TYPE_INVENTORY_MISMATCH + 2: TYPE_ITEM_USE + 3: TYPE_ITEM_USE_ON_ENTITY + 4: TYPE_ITEM_RELEASE + has_network_ids: bool + inventory_actions: []varint + source_type: varint => + "0": "INV_SOURCE_TYPE_CONTAINER" + "1": "INV_SOURCE_TYPE_GLOBAL" + "2": "INV_SOURCE_TYPE_WORLD_INTERACTION" + "3": "INV_SOURCE_TYPE_CREATIVE" + "100": "INV_SOURCE_TYPE_CRAFT_SLOT" + "99999": "INV_SOURCE_TYPE_CRAFT" + _: source_type? + if INV_SOURCE_TYPE_CONTAINER or INV_SOURCE_TYPE_CREATIVE: + inventory_id: varint + if INV_SOURCE_TYPE_WORLD_INTERACTION: + flags: varint + if INV_SOURCE_TYPE_CRAFT or INV_SOURCE_TYPE_CRAFT_SLOT: + action: varint + default: void + slot: varint + old_item: Item + new_item: Item + new_item_stack_id: has_network_ids? + if true: zigzag32 + default: void + transaction_data: transaction_type? + if TYPE_NORMAL or TYPE_INVENTORY_MISMATCH: void + if TYPE_ITEM_USE: + action_type: varint + face: varint + hotbar_slot: varint + item_in_hand: Item + player_pos: vec3f + click_pos: vec3f + block_runtime_id: varint + if TYPE_ITEM_USE_ON_ENTITY: + entity_runtime_id: varint64 + action_type: varint + hotbar_slot: zigzag32 + item_in_hand: Item + player_pos: vec3f + click_pos: vec3f + if TYPE_ITEM_RELEASE: + action_type: varint + hotbar_slot: zigzag32 + item_in_hand: Item + head_pos: vec3f + +ItemStacks: []varint + runtime_id: zigzag32 + item: Item + +RecipeIngredient: + network_id: zigzag32 + _: network_id? + if 0: void + default: + network_data: zigzag32 + count: zigzag32 + +PotionTypeRecipes: []varint + input_item_id: zigzag32 + input_item_meta: zigzag32 + ingredient_id: zigzag32 + ingredient_meta: zigzag32 + output_item_id: zigzag32 + output_item_meta: zigzag32 + +PotionContainerChangeRecipes: []varint + input_item_id: zigzag32 + ingredient_id: zigzag32 + output_item_id: zigzag32 + +Recipes: []varint + type: varint => + '0': 'shapeless' #'ENTRY_SHAPELESS', + '1': 'shaped' #'ENTRY_SHAPED', + '2': 'furnace' # 'ENTRY_FURNACE', + # `furnace_with_metadata` is a recipe specifically used for furnace-type crafting stations. It is equal to + # `furnace`, except it has an input item with a specific metadata value, instead of any metadata value. + '3': 'furnace_with_metadata' # 'ENTRY_FURNACE_DATA', // has metadata + '4': 'multi' #'ENTRY_MULTI', //TODO + '5': 'shapeless' #'ENTRY_SHULKER_BOX', //TODO + '6': 'shapeless' #'ENTRY_SHAPELESS_CHEMISTRY', //TODO + '7': 'shaped' #'ENTRY_SHAPED_CHEMISTRY', //TODO + recipe: type? + if shapeless: + recipe_id: string + input: RecipeIngredient[]varint + output: Item[]varint + uuid: uuid + block: string + priority: zigzag32 + network_id: zigzag32 + if shaped: + recipe_id: string + width: zigzag32 + height: zigzag32 + # todo: can this become + # RecipeIngredient[$height][$width] or RecipeIngredient[]$height[]$width ? + input: []$width + _: RecipeIngredient[]$height + output: Item[]varint + uuid: uuid + block: string + priority: zigzag32 + network_id: zigzag32 + if furnace: + input_id: zigzag32 + output: Item + block: string + if furnace_with_metadata: + input_id: zigzag32 + input_meta: zigzag32 + output: Item + block: string + if multi: + uuid: uuid + network_id: zigzag32 + +SkinImage: + width: li32 + height: li32 + data: string + +Skin: + skin_id: string + skin_resource_pack: string + skin_data: SkinImage + animations: []li32 + skin_image: SkinImage + animation_type: li32 + animation_frames: lf32 + expression_type: lf32 + cape_data: SkinImage + geometry_data: string + animation_data: string + premium: string + persona: bool + cape_on_classic: bool + cape_id: string + full_skin_id: string + arm_size: string + skin_color: string + personal_pieces: []li32 + piece_id: string + piece_type: string + pack_id: string + is_default_piece: bool + product_id: string + piece_tint_colors: []li32 + piece_type: string + colors: string[]li32 + +PlayerRecords: + type: u8 => + 0: add + 1: remove + records_count: varint + records: []$records_count + _: type? + if add: + uuid: uuid + entity_unique_id: zigzag64 + username: string + xbox_user_id: string + platform_chat_id: string + build_platform: li32 + skin_data: Skin + is_teacher: bool + is_host: bool + if remove: + uuid: uuid + uuid: type? + if add: uuid + default: void + verified: bool[]$records_count + +ScoreEntries: + type: u8 => + 0: change + 1: remove + entries: []varint + scoreboard_id: zigzag64 + objective_name: string + score: li32 + _: type? + if remove: + entry_type: i8 => + 1: player + 2: entity + 3: fake_player + _: entry_type? + if player or entity: + entity_unique_id: zigzag64 + if fake_player: + custom_name: string + +ScoreboardIdentityEntries: + type: i8 => + 0: TYPE_REGISTER_IDENTITY + 1: TYPE_CLEAR_IDENTITY + entries: []varint + scoreboard_id: zigzag64 + entity_unique_id: type ? + if TYPE_REGISTER_IDENTITY: zigzag64 + default: void + +Enchant: + id: u8 + level: u8 + +EnchantOptions: []varint + cost: varint + slot_flags: li32 + equip_enchants: Enchant[]varint + held_enchants: Enchant[]varint + self_enchants: Enchant[]varint + name: string + option_id: zigzag32 + + +StackRequestSlotInfo: + container_id: u8 + slot_id: u8 + stack_id: zigzag32 + +# + +ItemStackRequests: []varint + request_id: zigzag32 + actions: []varint + type_id: u8 => + '0': 'TAKE' + '1': 'PLACE' + '2': 'SWAP' + '3': 'DROP' + '4': 'DESTROY' + '5': 'CRAFTING_CONSUME_INPUT' + '6': 'create' + '7': 'LAB_TABLE_COMBINE' + '8': 'BEACON_PAYMENT' + '9': 'CRAFTING_RECIPE' + '10': 'CRAFTING_RECIPE_AUTO' #recipe book? + '11': 'CREATIVE_CREATE' + '12': 'CRAFTING_NON_IMPLEMENTED_DEPRECATED' #anvils aren't fully implemented yet + '13': 'CRAFTING_RESULTS_DEPRECATED' #no idea what this is for + _: type_id ? + if TAKE or PLACE: + count: u8 + source: StackRequestSlotInfo + destination: StackRequestSlotInfo + if SWAP: + source: StackRequestSlotInfo + destination: StackRequestSlotInfo + if DROP: + count: u8 + source: StackRequestSlotInfo + randomly: bool + if DESTROY or CRAFTING_CONSUME_INPUT: + count: u8 + source: StackRequestSlotInfo + if create: + result_slot_id: u8 + if BEACON_PAYMENT: + primary_effect: varint + secondary_effect: varint + if CRAFTING_RECIPE or CRAFTING_RECIPE_AUTO: + recipe_network_id: varint32 + if CREATIVE_CREATE: + creative_item_network_id: varint32 + if CRAFTING_NON_IMPLEMENTED_DEPRECATED: void + if CRAFTING_RESULTS_DEPRECATED: + result_items: ItemStacks + times_crafted: u8 + + +ItemStackResponses: []varint + result: u8 + request_id: varint32 + containers: []varint + container_id: u8 + slots: []varint + slot: u8 + hotbar_slot: u8 + count: u8 + item_stack_id: varint32 + custom_name: string + +ItemComponentList: []varint + name: string + nbt: nbt \ No newline at end of file diff --git a/data/newproto.json b/data/newproto.json index 3a166bf..13ffeaf 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -1,23 +1,5 @@ { "types": { - "string": [ - "pstring", - { - "countType": "varint" - } - ], - "ByteArray": [ - "buffer", - { - "countType": "varint" - } - ], - "LittleString": [ - "pstring", - { - "countType": "li32" - } - ], "varint32": "varint", "varint64": "varint", "bool": "native", @@ -164,11 +146,21 @@ [ { "name": "name", - "type": "varint" + "type": "string" }, { "name": "type", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "bool", + "2": "int", + "3": "float" + } + } + ] }, { "name": "value", @@ -177,10 +169,11 @@ { "compareTo": "type", "fields": { - "1": "bool", - "2": "varint", - "3": "lf32" - } + "bool": "bool", + "int": "varint", + "float": "lf32" + }, + "default": "void" } ] } @@ -209,13 +202,10 @@ "fields": { "true": "void", "false": "void" - } + }, + "default": "void" } ] - }, - { - "name": "data", - "type": "string" } ] ], @@ -251,7 +241,7 @@ }, { "name": "runtime_id", - "type": "i16" + "type": "li16" }, { "name": "component_based", @@ -292,7 +282,7 @@ "type": "lu16", "mappings": { "0": "0", - "0xffff": "1" + "65535": "1" } } ] @@ -441,103 +431,44 @@ "type": [ "container", [ - { - "name": "key", - "type": "varint" - }, { "name": "type", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "BYTE", + "1": "SHORT", + "2": "INT", + "3": "FLOAT", + "4": "STRING", + "5": "COMPOUND_TAG", + "6": "POS", + "7": "LONG", + "8": "VECTOR3F" + } + } + ] }, { - "anon": true, + "name": "value", "type": [ "switch", { "compareTo": "type", "fields": { - "0": [ - "container", - [ - { - "name": "value", - "type": "i8" - } - ] - ], - "1": [ - "container", - [ - { - "name": "value", - "type": "li16" - } - ] - ], - "2": [ - "container", - [ - { - "name": "value", - "type": "zigzag32" - } - ] - ], - "3": [ - "container", - [ - { - "name": "value", - "type": "lf32" - } - ] - ], - "4": [ - "container", - [ - { - "name": "value", - "type": "string" - } - ] - ], - "5": [ - "container", - [ - { - "name": "value", - "type": "nbt" - } - ] - ], - "6": [ - "container", - [ - { - "name": "value", - "type": "vec3i" - } - ] - ], - "7": [ - "container", - [ - { - "name": "value", - "type": "zigzag64" - } - ] - ], - "8": [ - "container", - [ - { - "name": "value", - "type": "li32" - } - ] - ] - } + "BYTE": "i8", + "SHORT": "li16", + "INT": "zigzag32", + "FLOAT": "lf32", + "STRING": "string", + "COMPOUND_TAG": "nbt", + "POS": "vec3i", + "LONG": "zigzag64", + "VECTOR3F": "li32" + }, + "default": "void" } ] } @@ -743,211 +674,113 @@ { "name": "inventory_actions", "type": [ - "switch", + "array", { - "compareTo": "has_network_ids", - "fields": { - "true": [ - "array", + "countType": "varint", + "type": [ + "container", + [ { - "countType": "varint", + "name": "source_type", "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "INV_SOURCE_TYPE_CONTAINER", - "1": "INV_SOURCE_TYPE_GLOBAL", - "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", - "3": "INV_SOURCE_TYPE_CREATIVE", - "100": "INV_SOURCE_TYPE_CRAFT_SLOT", - "99999": "INV_SOURCE_TYPE_CRAFT" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "INV_SOURCE_TYPE_CONTAINER": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_WORLD_INTERACTION": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CREATIVE": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CRAFT": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CRAFT_SLOT": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - } - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - }, - { - "name": "new_item_stack_id", - "type": "zigzag32" + "mapper", + { + "type": "varint", + "mappings": { + "0": "INV_SOURCE_TYPE_CONTAINER", + "1": "INV_SOURCE_TYPE_GLOBAL", + "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", + "3": "INV_SOURCE_TYPE_CREATIVE", + "100": "INV_SOURCE_TYPE_CRAFT_SLOT", + "99999": "INV_SOURCE_TYPE_CRAFT" } - ] + } ] - } - ], - "false": [ - "array", + }, { - "countType": "varint", + "anon": true, "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "INV_SOURCE_TYPE_CONTAINER", - "1": "INV_SOURCE_TYPE_GLOBAL", - "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", - "3": "INV_SOURCE_TYPE_CREATIVE", - "100": "INV_SOURCE_TYPE_CRAFT_SLOT", - "99999": "INV_SOURCE_TYPE_CRAFT" + "switch", + { + "compareTo": "source_type", + "fields": { + "INV_SOURCE_TYPE_CONTAINER": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" } - } + ] + ], + "INV_SOURCE_TYPE_CREATIVE": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_WORLD_INTERACTION": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "INV_SOURCE_TYPE_CRAFT_SLOT": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] ] }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "INV_SOURCE_TYPE_CONTAINER": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_WORLD_INTERACTION": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CREATIVE": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CRAFT": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "INV_SOURCE_TYPE_CRAFT_SLOT": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - } - } - ] + "default": "void" + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + }, + { + "name": "new_item_stack_id", + "type": [ + "switch", + { + "compareTo": "../has_network_ids", + "fields": { + "true": "zigzag32" }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - }, - { - "name": "new_item_stack_id", - "type": "void" - } - ] + "default": "void" + } ] } ] - } + ] } ] }, @@ -1043,7 +876,8 @@ } ] ] - } + }, + "default": "void" } ] } @@ -1348,7 +1182,8 @@ } ] ] - } + }, + "default": "void" } ] } @@ -1381,7 +1216,7 @@ "type": "string" }, { - "name": "skin_resource_pach", + "name": "skin_resource_pack", "type": "string" }, { @@ -1551,7 +1386,7 @@ "type": [ "switch", { - "compareTo": "type", + "compareTo": "../type", "fields": { "add": [ "container", @@ -1603,28 +1438,21 @@ } ] ] - } + }, + "default": "void" } ] } ] }, { - "anon": true, + "name": "uuid", "type": [ "switch", { "compareTo": "type", "fields": { - "add": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - } - ] - ] + "add": "uuid" }, "default": "void" } @@ -1659,139 +1487,98 @@ ] }, { - "anon": true, + "name": "entries", "type": [ - "switch", + "array", { - "compareTo": "type", - "fields": { - "remove": [ - "container", - [ - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "../type", + "fields": { + "remove": [ "container", [ { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" + } + } + ] }, { "anon": true, "type": [ - "container", - [ - { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": [ + "container", + [ + { + "name": "entity_unique_id", + "type": "zigzag64" } - } + ] + ], + "entity": [ + "container", + [ + { + "name": "entity_unique_id", + "type": "zigzag64" + } + ] + ], + "fake_player": [ + "container", + [ + { + "name": "custom_name", + "type": "string" + } + ] ] }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": [ - "container", - [ - { - "name": "entity_unique_id", - "type": "zigzag64" - } - ] - ], - "entity": [ - "container", - [ - { - "name": "entity_unique_id", - "type": "zigzag64" - } - ] - ], - "fake_player": [ - "container", - [ - { - "name": "custom_name", - "type": "string" - } - ] - ] - } - } - ] - } - ] + "default": "void" + } ] } ] ] - } - ] - } - ] - ], - "change": [ - "container", - [ - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": "void" - } - ] - ] - } - ] - } - ] + }, + "default": "void" + } + ] + } ] - } + ] } ] } @@ -1814,67 +1601,33 @@ ] }, { - "anon": true, + "name": "entries", "type": [ - "switch", + "array", { - "compareTo": "type", - "fields": { - "TYPE_REGISTER_IDENTITY": [ - "container", - [ - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - } - ] - ] - } - ] - } - ] - ], - "TYPE_CLEAR_IDENTITY": [ - "container", - [ - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "anon": true, - "type": "void" - } - ] - ] - } - ] - } - ] + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "../type", + "fields": { + "TYPE_REGISTER_IDENTITY": "zigzag64" + }, + "default": "void" + } + ] + } ] - } + ] } ] } @@ -2172,7 +1925,8 @@ } ] ] - } + }, + "default": "void" } ] } @@ -2285,145 +2039,145 @@ { "type": "varint", "mappings": { - "0x01": "login", - "0x02": "play_status", - "0x03": "server_to_client_handshake", - "0x04": "client_to_server_handshake", - "0x05": "disconnect", - "0x06": "resource_packs_info", - "0x07": "resource_pack_stack", - "0x08": "resource_pack_client_response", - "0x09": "text", - "0x0a": "set_time", - "0x0b": "start_game", - "0x0c": "add_player", - "0x0d": "add_entity", - "0x0e": "remove_entity", - "0x0f": "add_item_entity", - "0x11": "take_item_entity", - "0x12": "move_entity", - "0x13": "move_player", - "0x14": "rider_jump", - "0x15": "update_block", - "0x16": "add_painting", - "0x17": "tick_sync", - "0x18": "level_sound_event_old", - "0x19": "level_event", - "0x1a": "block_event", - "0x1b": "entity_event", - "0x1c": "mob_effect", - "0x1d": "update_attributes", - "0x1e": "inventory_transaction", - "0x1f": "mob_equipment", - "0x20": "mob_armor_equipment", - "0x21": "interact", - "0x22": "block_pick_request", - "0x23": "entity_pick_request", - "0x24": "player_action", - "0x26": "hurt_armor", - "0x27": "set_entity_data", - "0x28": "set_entity_motion", - "0x29": "set_entity_link", - "0x2a": "set_health", - "0x2b": "set_spawn_position", - "0x2c": "animate", - "0x2d": "respawn", - "0x2e": "container_open", - "0x2f": "container_close", - "0x30": "player_hotbar", - "0x31": "inventory_content", - "0x32": "inventory_slot", - "0x33": "container_set_data", - "0x34": "crafting_data", - "0x35": "crafting_event", - "0x36": "gui_data_pick_item", - "0x37": "adventure_settings", - "0x38": "block_entity_data", - "0x39": "player_input", - "0x3a": "level_chunk", - "0x3b": "set_commands_enabled", - "0x3c": "set_difficulty", - "0x3d": "change_dimension", - "0x3e": "set_player_game_type", - "0x3f": "player_list", - "0x40": "simple_event", - "0x42": "spawn_experience_orb", - "0x43": "clientbound_map_item_data_", - "0x44": "map_info_request", - "0x45": "request_chunk_radius", - "0x46": "chunk_radius_update", - "0x47": "item_frame_drop_item", - "0x48": "game_rules_changed", - "0x49": "camera", - "0x4a": "boss_event", - "0x4b": "show_credits", - "0x4c": "available_commands", - "0x4d": "command_request", - "0x4e": "command_block_update", - "0x4f": "command_output", - "0x50": "update_trade", - "0x51": "update_equipment", - "0x52": "resource_pack_data_info", - "0x53": "resource_pack_chunk_data", - "0x54": "resource_pack_chunk_request", - "0x55": "transfer", - "0x56": "play_sound", - "0x57": "stop_sound", - "0x58": "set_title", - "0x59": "add_behavior_tree", - "0x5a": "structure_block_update", - "0x5b": "show_store_offer", - "0x5c": "purchase_receipt", - "0x5d": "player_skin", - "0x5e": "sub_client_login", - "0x5f": "initiate_web_socket_connection", - "0x60": "set_last_hurt_by", - "0x61": "book_edit", - "0x62": "npc_request", - "0x63": "photo_transfer", - "0x64": "modal_form_request", - "0x65": "modal_form_response", - "0x66": "server_settings_request", - "0x67": "server_settings_response", - "0x68": "show_profile", - "0x69": "set_default_game_type", - "0x6a": "remove_objective", - "0x6b": "set_display_objective", - "0x6c": "set_score", - "0x6d": "lab_table", - "0x6e": "update_block_synced", - "0x6f": "move_entity_delta", - "0x70": "set_scoreboard_identity", - "0x71": "set_local_player_as_initialized", - "0x72": "update_soft_enum", - "0x73": "network_stack_latency", - "0x75": "script_custom_event", - "0x76": "spawn_particle_effect", - "0x77": "available_entity_identifiers", - "0x78": "level_sound_event_v2", - "0x79": "network_chunk_publisher_update", - "0x7a": "biome_definition_list", - "0x7b": "level_sound_event", - "0x7c": "level_event_generic", - "0x7d": "lectern_update", - "0x7e": "video_stream_connect", - "0x81": "client_cache_status", - "0x82": "on_screen_texture_animation", - "0x83": "map_create_locked_copy", - "0x84": "structure_template_data_export_request", - "0x85": "structure_template_data_export_response", - "0x86": "update_block_properties", - "0x87": "client_cache_blob_status", - "0x88": "client_cache_miss_response", - "0x8f": "network_settings", - "0x91": "creative_content", - "0x92": "player_enchant_options", - "0x93": "item_stack_request", - "0x94": "item_stack_response", - "0x97": "update_player_game_type", - "0x9c": "packet_violation_warning", - "0xa2": "item_component", - "0xa3": "filter_text_packet" + "1": "login", + "2": "play_status", + "3": "server_to_client_handshake", + "4": "client_to_server_handshake", + "5": "disconnect", + "6": "resource_packs_info", + "7": "resource_pack_stack", + "8": "resource_pack_client_response", + "9": "text", + "10": "set_time", + "11": "start_game", + "12": "add_player", + "13": "add_entity", + "14": "remove_entity", + "15": "add_item_entity", + "17": "take_item_entity", + "18": "move_entity", + "19": "move_player", + "20": "rider_jump", + "21": "update_block", + "22": "add_painting", + "23": "tick_sync", + "24": "level_sound_event_old", + "25": "level_event", + "26": "block_event", + "27": "entity_event", + "28": "mob_effect", + "29": "update_attributes", + "30": "inventory_transaction", + "31": "mob_equipment", + "32": "mob_armor_equipment", + "33": "interact", + "34": "block_pick_request", + "35": "entity_pick_request", + "36": "player_action", + "38": "hurt_armor", + "39": "set_entity_data", + "40": "set_entity_motion", + "41": "set_entity_link", + "42": "set_health", + "43": "set_spawn_position", + "44": "animate", + "45": "respawn", + "46": "container_open", + "47": "container_close", + "48": "player_hotbar", + "49": "inventory_content", + "50": "inventory_slot", + "51": "container_set_data", + "52": "crafting_data", + "53": "crafting_event", + "54": "gui_data_pick_item", + "55": "adventure_settings", + "56": "block_entity_data", + "57": "player_input", + "58": "level_chunk", + "59": "set_commands_enabled", + "60": "set_difficulty", + "61": "change_dimension", + "62": "set_player_game_type", + "63": "player_list", + "64": "simple_event", + "66": "spawn_experience_orb", + "67": "clientbound_map_item_data", + "68": "map_info_request", + "69": "request_chunk_radius", + "70": "chunk_radius_update", + "71": "item_frame_drop_item", + "72": "game_rules_changed", + "73": "camera", + "74": "boss_event", + "75": "show_credits", + "76": "available_commands", + "77": "command_request", + "78": "command_block_update", + "79": "command_output", + "80": "update_trade", + "81": "update_equipment", + "82": "resource_pack_data_info", + "83": "resource_pack_chunk_data", + "84": "resource_pack_chunk_request", + "85": "transfer", + "86": "play_sound", + "87": "stop_sound", + "88": "set_title", + "89": "add_behavior_tree", + "90": "structure_block_update", + "91": "show_store_offer", + "92": "purchase_receipt", + "93": "player_skin", + "94": "sub_client_login", + "95": "initiate_web_socket_connection", + "96": "set_last_hurt_by", + "97": "book_edit", + "98": "npc_request", + "99": "photo_transfer", + "100": "modal_form_request", + "101": "modal_form_response", + "102": "server_settings_request", + "103": "server_settings_response", + "104": "show_profile", + "105": "set_default_game_type", + "106": "remove_objective", + "107": "set_display_objective", + "108": "set_score", + "109": "lab_table", + "110": "update_block_synced", + "111": "move_entity_delta", + "112": "set_scoreboard_identity", + "113": "set_local_player_as_initialized", + "114": "update_soft_enum", + "115": "network_stack_latency", + "117": "script_custom_event", + "118": "spawn_particle_effect", + "119": "available_entity_identifiers", + "120": "level_sound_event_v2", + "121": "network_chunk_publisher_update", + "122": "biome_definition_list", + "123": "level_sound_event", + "124": "level_event_generic", + "125": "lectern_update", + "126": "video_stream_connect", + "129": "client_cache_status", + "130": "on_screen_texture_animation", + "131": "map_create_locked_copy", + "132": "structure_template_data_export_request", + "133": "structure_template_data_export_response", + "134": "update_block_properties", + "135": "client_cache_blob_status", + "136": "client_cache_miss_response", + "143": "network_settings", + "145": "creative_content", + "146": "player_enchant_options", + "147": "item_stack_request", + "148": "item_stack_response", + "151": "update_player_game_type", + "156": "packet_violation_warning", + "162": "item_component", + "163": "filter_text_packet" } } ] @@ -2498,7 +2252,7 @@ "player_list": "packet_player_list", "simple_event": "packet_simple_event", "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data_": "packet_clientbound_map_item_data_", + "clientbound_map_item_data": "packet_clientbound_map_item_data", "map_info_request": "packet_map_info_request", "request_chunk_radius": "packet_request_chunk_radius", "chunk_radius_update": "packet_chunk_radius_update", @@ -2574,7 +2328,8 @@ "packet_violation_warning": "packet_packet_violation_warning", "item_component": "packet_item_component", "filter_text_packet": "packet_filter_text_packet" - } + }, + "default": "void" } ] } @@ -4029,7 +3784,7 @@ } ] ], - "packet_clientbound_map_item_data_": [ + "packet_clientbound_map_item_data": [ "container", [ { @@ -4587,7 +4342,15 @@ } ] ], - "packet_set_score": "ScoreEntries", + "packet_set_score": [ + "container", + [ + { + "name": "entries", + "type": "ScoreEntries" + } + ] + ], "packet_lab_table": [ "container", [ @@ -4983,6 +4746,24 @@ "type": "bool" } ] + ], + "string": [ + "pstring", + { + "countType": "varint" + } + ], + "ByteArray": [ + "buffer", + { + "countType": "varint" + } + ], + "LittleString": [ + "pstring", + { + "countType": "li32" + } ] } } \ No newline at end of file From da85b80c591194cb1aed391473e8d7c28c387236 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 7 Feb 2021 05:28:03 -0500 Subject: [PATCH 088/458] server player extends connection --- src/auth/{jwt.js => chains.js} | 18 ++++-- src/auth/encryption.js | 28 ++++++++- src/connection.js | 107 ++++++++++++++++++++++++++++++++ src/server.js | 109 +-------------------------------- 4 files changed, 148 insertions(+), 114 deletions(-) rename src/auth/{jwt.js => chains.js} (92%) create mode 100644 src/connection.js diff --git a/src/auth/jwt.js b/src/auth/chains.js similarity index 92% rename from src/auth/jwt.js rename to src/auth/chains.js index 155f7fb..5208b9f 100644 --- a/src/auth/jwt.js +++ b/src/auth/chains.js @@ -80,7 +80,18 @@ function decodeLoginJWT(authTokens, skinTokens) { return { key, userData: data, skinData } } -function test() { +function encodeLoginJWT(localChain, mojangChain) { + const chains = [] + chains.push(localChain) + for (const chain of mojangChain) { + chains.push(chain) + } + return chains +} + +module.exports = { encodeLoginJWT, decodeLoginJWT } + +function testServer() { const loginPacket = require('./login.json') // console.log(loginPacket) @@ -95,10 +106,7 @@ function test() { } console.log('Authed') - // console.log(loginPacket) } -module.exports = { decodeLoginJWT } - -// test() \ No newline at end of file +// testServer() \ No newline at end of file diff --git a/src/auth/encryption.js b/src/auth/encryption.js index a487f3e..f32bc69 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -4,15 +4,19 @@ const { Ber } = require('asn1') const ec_pem = require('ec-pem') const SALT = '🧂' +const curve = 'secp384r1' function Encrypt(client, options) { + client.ecdhKeyPair = crypto.createECDH(curve) + client.ecdhKeyPair.generateKeys() + + createClientChain(client) + function startClientboundEncryption(publicKey) { console.warn('[encrypt] Pub key base64: ', publicKey) const pubKeyBuf = readX509PublicKey(publicKey.key) - const curve = 'secp384r1' - const alice = crypto.createECDH(curve) - alice.generateKeys() + const alice = client.ecdhKeyPair const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 const alicePEMPrivate = alicePEM.encodePrivateKey() // Shared secret from bob's public key + our private key @@ -47,9 +51,27 @@ function Encrypt(client, options) { client.startEncryption(initial) } + function startServerboundEncryption() { + + } + client.on('server.client_handshake', startClientboundEncryption) } +function createClientChain(client) { + const alice = client.ecdhKeyPair + const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 + const alicePEMPrivate = alicePEM.encodePrivateKey() + const x509 = writeX509PublicKey(alice.getPublicKey()) + + const token = JWT.sign({ + salt: toBase64(SALT), + signedToken: alice.getPublicKey('base64') + }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } }) + + client.clientChain = token +} + function toBase64(string) { return Buffer.from(string).toString('base64') } diff --git a/src/connection.js b/src/connection.js new file mode 100644 index 0000000..9830b57 --- /dev/null +++ b/src/connection.js @@ -0,0 +1,107 @@ +const BinaryStream = require('@jsprismarine/jsbinaryutils').default +const BatchPacket = require('./BatchPacket') +const cipher = require('./transforms/encryption') +const { EventEmitter } = require('events') +const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') + + +class Connection extends EventEmitter { + startEncryption(iv) { + this.encryptionEnabled = true + + this.decrypt = cipher.createDecryptor(this, iv) + this.encrypt = cipher.createEncryptor(this, iv) + } + + write(name, params) { // TODO: Batch + console.log('Need to encode', name, params) + const batch = new BatchPacket() + const packet = this.server.serializer.createPacketBuffer({ name, params }) + batch.addEncodedPacket(packet) + + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + + writeRaw(name, buffer) { // skip protodef serializaion + // temporary hard coded stuff + const batch = new BatchPacket() + if (name == 'biome_definition_list') { + // so we can send nbt straight from file without parsing + const stream = new BinaryStream() + stream.writeUnsignedVarInt(0x7a) + stream.append(buffer) + batch.addEncodedPacket(stream.getBuffer()) + // console.log('----- SENDING BIOME DEFINITIONS') + } + + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + + sendDecryptedBatch(batch) { + const buf = batch.encode() + // send to raknet + const sendPacket = new EncapsulatedPacket(); + sendPacket.reliability = 0; + sendPacket.buffer = buf + + this.connection.addEncapsulatedToQueue(sendPacket) + this.connection.sendQueue() + } + + sendEncryptedBatch(batch) { + const buf = batch.stream.getBuffer() + console.log('Sending encrypted batch', batch) + this.encrypt(buf) + } + + // These are callbacks called from encryption.js + onEncryptedPacket = (buf) => { + console.log('ENC BUF', buf) + const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header + const sendPacket = new EncapsulatedPacket(); + sendPacket.reliability = 0 + sendPacket.buffer = packet + console.log('Sending wrapped encrypted batch', packet) + this.connection.addEncapsulatedToQueue(sendPacket) + } + + onDecryptedPacket = (buf) => { + console.log('Decrypted', buf) + + const stream = new BinaryStream(buf) + const packets = BatchPacket.getPackets(stream) + + for (const packet of packets) { + this.readPacket(packet) + } + } + + handle(buffer) { // handle encapsulated + if (buffer[0] == 0xfe) { // wrapper + + if (this.encryptionEnabled) { + // console.log('READING ENCRYPTED PACKET', buffer) + this.decrypt(buffer.slice(1)) + } else { + const stream = new BinaryStream(buffer) + const batch = new BatchPacket(stream) + batch.decode() + const packets = batch.getPackets() + console.log('Reading ', packets.length, 'packets') + for (var packet of packets) { + this.readPacket(packet) + } + } + } + } +} + +module.exports = { Connection } \ No newline at end of file diff --git a/src/server.js b/src/server.js index 636f104..af25535 100644 --- a/src/server.js +++ b/src/server.js @@ -1,14 +1,9 @@ -const BinaryStream = require('@jsprismarine/jsbinaryutils').default const Listener = require('@jsprismarine/raknet/listener') const { ProtoDef, Parser, Serializer } = require('protodef') -const BatchPacket = require('./BatchPacket') const { EventEmitter } = require('events') -const cipher = require('./transforms/encryption') const { Encrypt } = require('./auth/encryption') - -const { decodeLoginJWT } = require('./auth/jwt') -const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') - +const { decodeLoginJWT } = require('./auth/chains') +const { Connection } = require('./connection') var protocol = require('../data/newproto.json').types; @@ -41,7 +36,7 @@ const PLAY_STATUS = { 'LoginFailedServerFull': 7 } -class Player extends EventEmitter { +class Player extends Connection { constructor(server, connection, options) { super() this.server = server @@ -100,84 +95,6 @@ class Player extends EventEmitter { this.emit('join') } - startEncryption(iv) { - this.encryptionEnabled = true - - this.decrypt = cipher.createDecryptor(this, iv) - this.encrypt = cipher.createEncryptor(this, iv) - } - - write(name, params) { // TODO: Batch - console.log('Need to encode', name, params) - const batch = new BatchPacket() - const packet = this.server.serializer.createPacketBuffer({ name, params }) - batch.addEncodedPacket(packet) - - if (this.encryptionEnabled) { - this.sendEncryptedBatch(batch) - } else { - this.sendDecryptedBatch(batch) - } - } - - writeRaw(name, buffer) { // skip protodef serializaion - // temporary hard coded stuff - const batch = new BatchPacket() - if (name == 'biome_definition_list') { - // so we can send nbt straight from file without parsing - const stream = new BinaryStream() - stream.writeUnsignedVarInt(0x7a) - stream.append(buffer) - batch.addEncodedPacket(stream.getBuffer()) - // console.log('----- SENDING BIOME DEFINITIONS') - } - - if (this.encryptionEnabled) { - this.sendEncryptedBatch(batch) - } else { - this.sendDecryptedBatch(batch) - } - } - - sendDecryptedBatch(batch) { - const buf = batch.encode() - // send to raknet - const sendPacket = new EncapsulatedPacket(); - sendPacket.reliability = 0; - sendPacket.buffer = buf - - this.connection.addEncapsulatedToQueue(sendPacket) - this.connection.sendQueue() - } - - sendEncryptedBatch(batch) { - const buf = batch.stream.getBuffer() - console.log('Sending encrypted batch', batch) - this.encrypt(buf) - } - - // These are callbacks called from encryption.js - onEncryptedPacket = (buf) => { - console.log('ENC BUF', buf) - const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header - const sendPacket = new EncapsulatedPacket(); - sendPacket.reliability = 0 - sendPacket.buffer = packet - console.log('Sending wrapped encrypted batch', packet) - this.connection.addEncapsulatedToQueue(sendPacket) - } - - onDecryptedPacket = (buf) => { - console.log('Decrypted', buf) - - const stream = new BinaryStream(buf) - const packets = BatchPacket.getPackets(stream) - - for (const packet of packets) { - this.readPacket(packet) - } - } - readPacket(packet) { console.log('packet', packet) const des = this.server.deserializer.parsePacketBuffer(packet) @@ -193,26 +110,6 @@ class Player extends EventEmitter { console.log('ignoring, unhandled') } this.emit(des.data.name, des.data.params) - - } - - handle(buffer) { // handle encapsulated - if (buffer[0] == 0xfe) { // wrapper - - if (this.encryptionEnabled) { - // console.log('READING ENCRYPTED PACKET', buffer) - this.decrypt(buffer.slice(1)) - } else { - const stream = new BinaryStream(buffer) - const batch = new BatchPacket(stream) - batch.decode() - const packets = batch.getPackets() - console.log('Reading ', packets.length, 'packets') - for (var packet of packets) { - this.readPacket(packet) - } - } - } } } From 51214fcf2993c0c70a9e6b9d015f0178015ba261 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 7 Feb 2021 16:47:07 -0500 Subject: [PATCH 089/458] seperate packet map from proto.yml --- data/new/compile.js | 2 +- data/new/packet_map.yml | 283 ++++++++++++++++ data/new/proto.yml | 701 ++++++++-------------------------------- 3 files changed, 424 insertions(+), 562 deletions(-) create mode 100644 data/new/packet_map.yml diff --git a/data/new/compile.js b/data/new/compile.js index 8a3b575..2800ba8 100644 --- a/data/new/compile.js +++ b/data/new/compile.js @@ -2,7 +2,7 @@ const fs = require('fs') let compile try { - compile = require('protodef-yaml/compiler') + compile = require('protodef-yaml/compiler').compile } catch (e) { require('child_process').execSync('npx protodef-yaml proto.yml protocol.json') } diff --git a/data/new/packet_map.yml b/data/new/packet_map.yml new file mode 100644 index 0000000..6f698c9 --- /dev/null +++ b/data/new/packet_map.yml @@ -0,0 +1,283 @@ + +!import: types.yaml +mcpe_packet: + name: varint => + 0x01: login + 0x02: play_status + 0x03: server_to_client_handshake + 0x04: client_to_server_handshake + 0x05: disconnect + 0x06: resource_packs_info + 0x07: resource_pack_stack + 0x08: resource_pack_client_response + 0x09: text + 0x0a: set_time + 0x0b: start_game + 0x0c: add_player + 0x0d: add_entity + 0x0e: remove_entity + 0x0f: add_item_entity + 0x11: take_item_entity + 0x12: move_entity + 0x13: move_player + 0x14: rider_jump + 0x15: update_block + 0x16: add_painting + 0x17: tick_sync + 0x18: level_sound_event_old + 0x19: level_event + 0x1a: block_event + 0x1b: entity_event + 0x1c: mob_effect + 0x1d: update_attributes + 0x1e: inventory_transaction + 0x1f: mob_equipment + 0x20: mob_armor_equipment + 0x21: interact + 0x22: block_pick_request + 0x23: entity_pick_request + 0x24: player_action + 0x26: hurt_armor + 0x27: set_entity_data + 0x28: set_entity_motion + 0x29: set_entity_link + 0x2a: set_health + 0x2b: set_spawn_position + 0x2c: animate + 0x2d: respawn + 0x2e: container_open + 0x2f: container_close + 0x30: player_hotbar + 0x31: inventory_content + 0x32: inventory_slot + 0x33: container_set_data + 0x34: crafting_data + 0x35: crafting_event + 0x36: gui_data_pick_item + 0x37: adventure_settings + 0x38: block_entity_data + 0x39: player_input + 0x3a: level_chunk + 0x3b: set_commands_enabled + 0x3c: set_difficulty + 0x3d: change_dimension + 0x3e: set_player_game_type + 0x3f: player_list + 0x40: simple_event + 0x42: spawn_experience_orb + 0x43: clientbound_map_item_data + 0x44: map_info_request + 0x45: request_chunk_radius + 0x46: chunk_radius_update + 0x47: item_frame_drop_item + 0x48: game_rules_changed + 0x49: camera + 0x4a: boss_event + 0x4b: show_credits + 0x4c: available_commands + 0x4d: command_request + 0x4e: command_block_update + 0x4f: command_output + 0x50: update_trade + 0x51: update_equipment + 0x52: resource_pack_data_info + 0x53: resource_pack_chunk_data + 0x54: resource_pack_chunk_request + 0x55: transfer + 0x56: play_sound + 0x57: stop_sound + 0x58: set_title + 0x59: add_behavior_tree + 0x5a: structure_block_update + 0x5b: show_store_offer + 0x5c: purchase_receipt + 0x5d: player_skin + 0x5e: sub_client_login + 0x5f: initiate_web_socket_connection + 0x60: set_last_hurt_by + 0x61: book_edit + 0x62: npc_request + 0x63: photo_transfer + 0x64: modal_form_request + 0x65: modal_form_response + 0x66: server_settings_request + 0x67: server_settings_response + 0x68: show_profile + 0x69: set_default_game_type + 0x6a: remove_objective + 0x6b: set_display_objective + 0x6c: set_score + 0x6d: lab_table + 0x6e: update_block_synced + 0x6f: move_entity_delta + 0x70: set_scoreboard_identity + 0x71: set_local_player_as_initialized + 0x72: update_soft_enum + 0x73: network_stack_latency + 0x75: script_custom_event + 0x76: spawn_particle_effect + 0x77: available_entity_identifiers + 0x78: level_sound_event_v2 + 0x79: network_chunk_publisher_update + 0x7a: biome_definition_list + 0x7b: level_sound_event + 0x7c: level_event_generic + 0x7d: lectern_update + 0x7e: video_stream_connect + 0x81: client_cache_status + 0x82: on_screen_texture_animation + 0x83: map_create_locked_copy + 0x84: structure_template_data_export_request + 0x85: structure_template_data_export_response + 0x86: update_block_properties + 0x87: client_cache_blob_status + 0x88: client_cache_miss_response + 0x8f: network_settings + 0x91: creative_content + 0x92: player_enchant_options + 0x93: item_stack_request + 0x94: item_stack_response + 0x97: update_player_game_type + 0x9c: packet_violation_warning + 0xa2: item_component + 0xa3: filter_text_packet + params: name ? + if login: packet_login + if play_status: packet_play_status + if server_to_client_handshake: packet_server_to_client_handshake + if client_to_server_handshake: packet_client_to_server_handshake + if disconnect: packet_disconnect + if resource_packs_info: packet_resource_packs_info + if resource_pack_stack: packet_resource_pack_stack + if resource_pack_client_response: packet_resource_pack_client_response + if text: packet_text + if set_time: packet_set_time + if start_game: packet_start_game + if add_player: packet_add_player + if add_entity: packet_add_entity + if remove_entity: packet_remove_entity + if add_item_entity: packet_add_item_entity + if take_item_entity: packet_take_item_entity + if move_entity: packet_move_entity + if move_player: packet_move_player + if rider_jump: packet_rider_jump + if update_block: packet_update_block + if add_painting: packet_add_painting + if tick_sync: packet_tick_sync + if level_sound_event_old: packet_level_sound_event_old + if level_event: packet_level_event + if block_event: packet_block_event + if entity_event: packet_entity_event + if mob_effect: packet_mob_effect + if update_attributes: packet_update_attributes + if inventory_transaction: packet_inventory_transaction + if mob_equipment: packet_mob_equipment + if mob_armor_equipment: packet_mob_armor_equipment + if interact: packet_interact + if block_pick_request: packet_block_pick_request + if entity_pick_request: packet_entity_pick_request + if player_action: packet_player_action + if hurt_armor: packet_hurt_armor + if set_entity_data: packet_set_entity_data + if set_entity_motion: packet_set_entity_motion + if set_entity_link: packet_set_entity_link + if set_health: packet_set_health + if set_spawn_position: packet_set_spawn_position + if animate: packet_animate + if respawn: packet_respawn + if container_open: packet_container_open + if container_close: packet_container_close + if player_hotbar: packet_player_hotbar + if inventory_content: packet_inventory_content + if inventory_slot: packet_inventory_slot + if container_set_data: packet_container_set_data + if crafting_data: packet_crafting_data + if crafting_event: packet_crafting_event + if gui_data_pick_item: packet_gui_data_pick_item + if adventure_settings: packet_adventure_settings + if block_entity_data: packet_block_entity_data + if player_input: packet_player_input + if level_chunk: packet_level_chunk + if set_commands_enabled: packet_set_commands_enabled + if set_difficulty: packet_set_difficulty + if change_dimension: packet_change_dimension + if set_player_game_type: packet_set_player_game_type + if player_list: packet_player_list + if simple_event: packet_simple_event + if spawn_experience_orb: packet_spawn_experience_orb + if clientbound_map_item_data: packet_clientbound_map_item_data + if map_info_request: packet_map_info_request + if request_chunk_radius: packet_request_chunk_radius + if chunk_radius_update: packet_chunk_radius_update + if item_frame_drop_item: packet_item_frame_drop_item + if game_rules_changed: packet_game_rules_changed + if camera: packet_camera + if boss_event: packet_boss_event + if show_credits: packet_show_credits + if available_commands: packet_available_commands + if command_request: packet_command_request + if command_block_update: packet_command_block_update + if command_output: packet_command_output + if update_trade: packet_update_trade + if update_equipment: packet_update_equipment + if resource_pack_data_info: packet_resource_pack_data_info + if resource_pack_chunk_data: packet_resource_pack_chunk_data + if resource_pack_chunk_request: packet_resource_pack_chunk_request + if transfer: packet_transfer + if play_sound: packet_play_sound + if stop_sound: packet_stop_sound + if set_title: packet_set_title + if add_behavior_tree: packet_add_behavior_tree + if structure_block_update: packet_structure_block_update + if show_store_offer: packet_show_store_offer + if purchase_receipt: packet_purchase_receipt + if player_skin: packet_player_skin + if sub_client_login: packet_sub_client_login + if initiate_web_socket_connection: packet_initiate_web_socket_connection + if set_last_hurt_by: packet_set_last_hurt_by + if book_edit: packet_book_edit + if npc_request: packet_npc_request + if photo_transfer: packet_photo_transfer + if modal_form_request: packet_modal_form_request + if modal_form_response: packet_modal_form_response + if server_settings_request: packet_server_settings_request + if server_settings_response: packet_server_settings_response + if show_profile: packet_show_profile + if set_default_game_type: packet_set_default_game_type + if remove_objective: packet_remove_objective + if set_display_objective: packet_set_display_objective + if set_score: packet_set_score + if lab_table: packet_lab_table + if update_block_synced: packet_update_block_synced + if move_entity_delta: packet_move_entity_delta + if set_scoreboard_identity: packet_set_scoreboard_identity + if set_local_player_as_initialized: packet_set_local_player_as_initialized + if update_soft_enum: packet_update_soft_enum + if network_stack_latency: packet_network_stack_latency + if script_custom_event: packet_script_custom_event + if spawn_particle_effect: packet_spawn_particle_effect + if available_entity_identifiers: packet_available_entity_identifiers + if level_sound_event_v2: packet_level_sound_event_v2 + if network_chunk_publisher_update: packet_network_chunk_publisher_update + if biome_definition_list: packet_biome_definition_list + if level_sound_event: packet_level_sound_event + if level_event_generic: packet_level_event_generic + if lectern_update: packet_lectern_update + if video_stream_connect: packet_video_stream_connect + if client_cache_status: packet_client_cache_status + if on_screen_texture_animation: packet_on_screen_texture_animation + if map_create_locked_copy: packet_map_create_locked_copy + if structure_template_data_export_request: packet_structure_template_data_export_request + if structure_template_data_export_response: packet_structure_template_data_export_response + if update_block_properties: packet_update_block_properties + if client_cache_blob_status: packet_client_cache_blob_status + if client_cache_miss_response: packet_client_cache_miss_response + if network_settings: packet_network_settings + if creative_content: packet_creative_content + if player_enchant_options: packet_player_enchant_options + if item_stack_request: packet_item_stack_request + if item_stack_response: packet_item_stack_response + if update_player_game_type: packet_update_player_game_type + if packet_violation_warning: packet_packet_violation_warning + if item_component: packet_item_component + if filter_text_packet: packet_filter_text_packet \ No newline at end of file diff --git a/data/new/proto.yml b/data/new/proto.yml index 37f7f0a..737c70e 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -12,294 +12,11 @@ byterot: native MapInfo: native nbt: native -!import: types.yaml - -mcpe_packet: - name: varint => - 0x01: login - 0x02: play_status - 0x03: server_to_client_handshake - 0x04: client_to_server_handshake - 0x05: disconnect - 0x06: resource_packs_info - 0x07: resource_pack_stack - 0x08: resource_pack_client_response - 0x09: text - 0x0a: set_time - 0x0b: start_game - 0x0c: add_player - 0x0d: add_entity - 0x0e: remove_entity - 0x0f: add_item_entity - 0x11: take_item_entity - 0x12: move_entity - 0x13: move_player - 0x14: rider_jump - 0x15: update_block - 0x16: add_painting - 0x17: tick_sync - 0x18: level_sound_event_old - 0x19: level_event - 0x1a: block_event - 0x1b: entity_event - 0x1c: mob_effect - 0x1d: update_attributes - 0x1e: inventory_transaction - 0x1f: mob_equipment - 0x20: mob_armor_equipment - 0x21: interact - 0x22: block_pick_request - 0x23: entity_pick_request - 0x24: player_action - 0x26: hurt_armor - 0x27: set_entity_data - 0x28: set_entity_motion - 0x29: set_entity_link - 0x2a: set_health - 0x2b: set_spawn_position - 0x2c: animate - 0x2d: respawn - 0x2e: container_open - 0x2f: container_close - 0x30: player_hotbar - 0x31: inventory_content - 0x32: inventory_slot - 0x33: container_set_data - 0x34: crafting_data - 0x35: crafting_event - 0x36: gui_data_pick_item - 0x37: adventure_settings - 0x38: block_entity_data - 0x39: player_input - 0x3a: level_chunk - 0x3b: set_commands_enabled - 0x3c: set_difficulty - 0x3d: change_dimension - 0x3e: set_player_game_type - 0x3f: player_list - 0x40: simple_event - 0x42: spawn_experience_orb - 0x43: clientbound_map_item_data - 0x44: map_info_request - 0x45: request_chunk_radius - 0x46: chunk_radius_update - 0x47: item_frame_drop_item - 0x48: game_rules_changed - 0x49: camera - 0x4a: boss_event - 0x4b: show_credits - 0x4c: available_commands - 0x4d: command_request - 0x4e: command_block_update - 0x4f: command_output - 0x50: update_trade - 0x51: update_equipment - 0x52: resource_pack_data_info - 0x53: resource_pack_chunk_data - 0x54: resource_pack_chunk_request - 0x55: transfer - 0x56: play_sound - 0x57: stop_sound - 0x58: set_title - 0x59: add_behavior_tree - 0x5a: structure_block_update - 0x5b: show_store_offer - 0x5c: purchase_receipt - 0x5d: player_skin - 0x5e: sub_client_login - 0x5f: initiate_web_socket_connection - 0x60: set_last_hurt_by - 0x61: book_edit - 0x62: npc_request - 0x63: photo_transfer - 0x64: modal_form_request - 0x65: modal_form_response - 0x66: server_settings_request - 0x67: server_settings_response - 0x68: show_profile - 0x69: set_default_game_type - 0x6a: remove_objective - 0x6b: set_display_objective - 0x6c: set_score - 0x6d: lab_table - 0x6e: update_block_synced - 0x6f: move_entity_delta - 0x70: set_scoreboard_identity - 0x71: set_local_player_as_initialized - 0x72: update_soft_enum - 0x73: network_stack_latency - 0x75: script_custom_event - 0x76: spawn_particle_effect - 0x77: available_entity_identifiers - 0x78: level_sound_event_v2 - 0x79: network_chunk_publisher_update - 0x7a: biome_definition_list - 0x7b: level_sound_event - 0x7c: level_event_generic - 0x7d: lectern_update - 0x7e: video_stream_connect - 0x81: client_cache_status - 0x82: on_screen_texture_animation - 0x83: map_create_locked_copy - 0x84: structure_template_data_export_request - 0x85: structure_template_data_export_response - 0x86: update_block_properties - 0x87: client_cache_blob_status - 0x88: client_cache_miss_response - 0x8f: network_settings - 0x91: creative_content - 0x92: player_enchant_options - 0x93: item_stack_request - 0x94: item_stack_response - 0x97: update_player_game_type - 0x9c: packet_violation_warning - 0xa2: item_component - 0xa3: filter_text_packet - params: name ? - if login: packet_login - if play_status: packet_play_status - if server_to_client_handshake: packet_server_to_client_handshake - if client_to_server_handshake: packet_client_to_server_handshake - if disconnect: packet_disconnect - if resource_packs_info: packet_resource_packs_info - if resource_pack_stack: packet_resource_pack_stack - if resource_pack_client_response: packet_resource_pack_client_response - if text: packet_text - if set_time: packet_set_time - if start_game: packet_start_game - if add_player: packet_add_player - if add_entity: packet_add_entity - if remove_entity: packet_remove_entity - if add_item_entity: packet_add_item_entity - if take_item_entity: packet_take_item_entity - if move_entity: packet_move_entity - if move_player: packet_move_player - if rider_jump: packet_rider_jump - if update_block: packet_update_block - if add_painting: packet_add_painting - if tick_sync: packet_tick_sync - if level_sound_event_old: packet_level_sound_event_old - if level_event: packet_level_event - if block_event: packet_block_event - if entity_event: packet_entity_event - if mob_effect: packet_mob_effect - if update_attributes: packet_update_attributes - if inventory_transaction: packet_inventory_transaction - if mob_equipment: packet_mob_equipment - if mob_armor_equipment: packet_mob_armor_equipment - if interact: packet_interact - if block_pick_request: packet_block_pick_request - if entity_pick_request: packet_entity_pick_request - if player_action: packet_player_action - if hurt_armor: packet_hurt_armor - if set_entity_data: packet_set_entity_data - if set_entity_motion: packet_set_entity_motion - if set_entity_link: packet_set_entity_link - if set_health: packet_set_health - if set_spawn_position: packet_set_spawn_position - if animate: packet_animate - if respawn: packet_respawn - if container_open: packet_container_open - if container_close: packet_container_close - if player_hotbar: packet_player_hotbar - if inventory_content: packet_inventory_content - if inventory_slot: packet_inventory_slot - if container_set_data: packet_container_set_data - if crafting_data: packet_crafting_data - if crafting_event: packet_crafting_event - if gui_data_pick_item: packet_gui_data_pick_item - if adventure_settings: packet_adventure_settings - if block_entity_data: packet_block_entity_data - if player_input: packet_player_input - if level_chunk: packet_level_chunk - if set_commands_enabled: packet_set_commands_enabled - if set_difficulty: packet_set_difficulty - if change_dimension: packet_change_dimension - if set_player_game_type: packet_set_player_game_type - if player_list: packet_player_list - if simple_event: packet_simple_event - if spawn_experience_orb: packet_spawn_experience_orb - if clientbound_map_item_data: packet_clientbound_map_item_data - if map_info_request: packet_map_info_request - if request_chunk_radius: packet_request_chunk_radius - if chunk_radius_update: packet_chunk_radius_update - if item_frame_drop_item: packet_item_frame_drop_item - if game_rules_changed: packet_game_rules_changed - if camera: packet_camera - if boss_event: packet_boss_event - if show_credits: packet_show_credits - if available_commands: packet_available_commands - if command_request: packet_command_request - if command_block_update: packet_command_block_update - if command_output: packet_command_output - if update_trade: packet_update_trade - if update_equipment: packet_update_equipment - if resource_pack_data_info: packet_resource_pack_data_info - if resource_pack_chunk_data: packet_resource_pack_chunk_data - if resource_pack_chunk_request: packet_resource_pack_chunk_request - if transfer: packet_transfer - if play_sound: packet_play_sound - if stop_sound: packet_stop_sound - if set_title: packet_set_title - if add_behavior_tree: packet_add_behavior_tree - if structure_block_update: packet_structure_block_update - if show_store_offer: packet_show_store_offer - if purchase_receipt: packet_purchase_receipt - if player_skin: packet_player_skin - if sub_client_login: packet_sub_client_login - if initiate_web_socket_connection: packet_initiate_web_socket_connection - if set_last_hurt_by: packet_set_last_hurt_by - if book_edit: packet_book_edit - if npc_request: packet_npc_request - if photo_transfer: packet_photo_transfer - if modal_form_request: packet_modal_form_request - if modal_form_response: packet_modal_form_response - if server_settings_request: packet_server_settings_request - if server_settings_response: packet_server_settings_response - if show_profile: packet_show_profile - if set_default_game_type: packet_set_default_game_type - if remove_objective: packet_remove_objective - if set_display_objective: packet_set_display_objective - if set_score: packet_set_score - if lab_table: packet_lab_table - if update_block_synced: packet_update_block_synced - if move_entity_delta: packet_move_entity_delta - if set_scoreboard_identity: packet_set_scoreboard_identity - if set_local_player_as_initialized: packet_set_local_player_as_initialized - if update_soft_enum: packet_update_soft_enum - if network_stack_latency: packet_network_stack_latency - if script_custom_event: packet_script_custom_event - if spawn_particle_effect: packet_spawn_particle_effect - if available_entity_identifiers: packet_available_entity_identifiers - if level_sound_event_v2: packet_level_sound_event_v2 - if network_chunk_publisher_update: packet_network_chunk_publisher_update - if biome_definition_list: packet_biome_definition_list - if level_sound_event: packet_level_sound_event - if level_event_generic: packet_level_event_generic - if lectern_update: packet_lectern_update - if video_stream_connect: packet_video_stream_connect - if client_cache_status: packet_client_cache_status - if on_screen_texture_animation: packet_on_screen_texture_animation - if map_create_locked_copy: packet_map_create_locked_copy - if structure_template_data_export_request: packet_structure_template_data_export_request - if structure_template_data_export_response: packet_structure_template_data_export_response - if update_block_properties: packet_update_block_properties - if client_cache_blob_status: packet_client_cache_blob_status - if client_cache_miss_response: packet_client_cache_miss_response - if network_settings: packet_network_settings - if creative_content: packet_creative_content - if player_enchant_options: packet_player_enchant_options - if item_stack_request: packet_item_stack_request - if item_stack_response: packet_item_stack_response - if update_player_game_type: packet_update_player_game_type - if packet_violation_warning: packet_packet_violation_warning - if item_component: packet_item_component - if filter_text_packet: packet_filter_text_packet +!import: packet_map.yml packet_login: !id: 0x01 - !server: false - !client: true + !bound: client protocol_version: i32 payload_size: varint chain: LittleString @@ -307,32 +24,27 @@ packet_login: packet_play_status: !id: 0x02 - !server: true - !client: false + !bound: server status: i32 packet_server_to_client_handshake: !id: 0x03 - !server: true - !client: false + !bound: server token: string packet_client_to_server_handshake: !id: 0x04 - !server: false - !client: true + !bound: client packet_disconnect: !id: 0x05 - !server: true - !client: false + !bound: server hide_disconnect_reason: bool message: string packet_resource_packs_info: !id: 0x06 - !server: true - !client: false + !bound: server must_accept: bool has_scripts: bool behaviour_packs: BehaviourPackInfos @@ -340,8 +52,7 @@ packet_resource_packs_info: packet_resource_pack_stack: !id: 0x07 - !server: true - !client: false + !bound: server must_accept: bool behavior_packs: ResourcePackIdVersions resource_packs: ResourcePackIdVersions @@ -351,27 +62,23 @@ packet_resource_pack_stack: packet_resource_pack_client_response: !id: 0x08 - !server: false - !client: true + !bound: client response_status: u8 resourcepackids: ResourcePackIds packet_text: !id: 0x09 - !server: true - !client: true + !bound: both type: u8 packet_set_time: !id: 0x0a - !server: true - !client: false + !bound: server time: zigzag32 packet_start_game: !id: 0x0b - !server: true - !client: false + !bound: server entity_id: zigzag64 runtime_entity_id: varint player_gamemode: zigzag32 @@ -434,8 +141,7 @@ packet_start_game: packet_add_player: !id: 0x0c - !server: true - !client: false + !bound: server uuid: uuid username: string entity_id_self: zigzag64 @@ -464,8 +170,7 @@ packet_add_player: packet_add_entity: !id: 0x0d - !server: true - !client: false + !bound: server entity_id_self: zigzag64 runtime_entity_id: varint entity_type: string @@ -484,14 +189,12 @@ packet_add_entity: packet_remove_entity: !id: 0x0e - !server: true - !client: false + !bound: server entity_id_self: zigzag64 packet_add_item_entity: !id: 0x0f - !server: true - !client: false + !bound: server entity_id_self: zigzag64 runtime_entity_id: varint item: Item @@ -506,15 +209,13 @@ packet_add_item_entity: packet_take_item_entity: !id: 0x11 - !server: true - !client: false + !bound: server runtime_entity_id: varint target: varint packet_move_entity: !id: 0x12 - !server: true - !client: true + !bound: both runtime_entity_id: varint flags: u8 position: vec3f @@ -522,8 +223,7 @@ packet_move_entity: packet_move_player: !id: 0x13 - !server: true - !client: true + !bound: both runtime_entity_id: varint x: lf32 y: lf32 @@ -537,14 +237,12 @@ packet_move_player: packet_rider_jump: !id: 0x14 - !server: true - !client: true + !bound: both unknown: zigzag32 packet_update_block: !id: 0x15 - !server: true - !client: false + !bound: server coordinates: BlockCoordinates block_runtime_id: varint block_priority: varint @@ -552,8 +250,7 @@ packet_update_block: packet_add_painting: !id: 0x16 - !server: true - !client: false + !bound: server entity_id_self: zigzag64 runtime_entity_id: varint coordinates: BlockCoordinates @@ -562,15 +259,13 @@ packet_add_painting: packet_tick_sync: !id: 0x17 - !server: true - !client: true + !bound: both request_time: li64 response_time: li64 packet_level_sound_event_old: !id: 0x18 - !server: true - !client: true + !bound: both sound_id: u8 position: vec3f block_id: zigzag32 @@ -580,32 +275,28 @@ packet_level_sound_event_old: packet_level_event: !id: 0x19 - !server: true - !client: false + !bound: server event_id: zigzag32 position: vec3f data: zigzag32 packet_block_event: !id: 0x1a - !server: true - !client: false + !bound: server coordinates: BlockCoordinates case_1: zigzag32 case_2: zigzag32 packet_entity_event: !id: 0x1b - !server: true - !client: true + !bound: both runtime_entity_id: varint event_id: u8 data: zigzag32 packet_mob_effect: !id: 0x1c - !server: true - !client: false + !bound: server runtime_entity_id: varint event_id: u8 effect_id: zigzag32 @@ -615,22 +306,19 @@ packet_mob_effect: packet_update_attributes: !id: 0x1d - !server: true - !client: false + !bound: server runtime_entity_id: varint attributes: PlayerAttributes tick: varint packet_inventory_transaction: !id: 0x1e - !server: true - !client: true + !bound: both transaction: Transaction packet_mob_equipment: !id: 0x1f - !server: true - !client: true + !bound: both runtime_entity_id: varint item: Item slot: u8 @@ -639,8 +327,7 @@ packet_mob_equipment: packet_mob_armor_equipment: !id: 0x20 - !server: true - !client: true + !bound: both runtime_entity_id: varint helmet: Item chestplate: Item @@ -649,15 +336,13 @@ packet_mob_armor_equipment: packet_interact: !id: 0x21 - !server: true - !client: true + !bound: both action_id: u8 target_runtime_entity_id: varint packet_block_pick_request: !id: 0x22 - !server: false - !client: true + !bound: client x: zigzag32 y: zigzag32 z: zigzag32 @@ -666,15 +351,13 @@ packet_block_pick_request: packet_entity_pick_request: !id: 0x23 - !server: false - !client: true + !bound: client runtime_entity_id: lu64 selected_slot: u8 packet_player_action: !id: 0x24 - !server: false - !client: true + !bound: client runtime_entity_id: varint action_id: zigzag32 coordinates: BlockCoordinates @@ -682,29 +365,25 @@ packet_player_action: packet_hurt_armor: !id: 0x26 - !server: true - !client: false + !bound: server health: zigzag32 packet_set_entity_data: !id: 0x27 - !server: true - !client: true + !bound: both runtime_entity_id: varint metadata: MetadataDictionary tick: varint packet_set_entity_motion: !id: 0x28 - !server: true - !client: true + !bound: both runtime_entity_id: varint velocity: vec3f packet_set_entity_link: !id: 0x29 - !server: true - !client: false + !bound: server ridden_id: zigzag64 rider_id: zigzag64 link_type: u8 @@ -712,14 +391,12 @@ packet_set_entity_link: packet_set_health: !id: 0x2a - !server: true - !client: false + !bound: server health: zigzag32 packet_set_spawn_position: !id: 0x2b - !server: true - !client: false + !bound: server spawn_type: zigzag32 coordinates: BlockCoordinates dimension: zigzag32 @@ -727,15 +404,13 @@ packet_set_spawn_position: packet_animate: !id: 0x2c - !server: true - !client: true + !bound: both action_id: zigzag32 runtime_entity_id: varint packet_respawn: !id: 0x2d - !server: true - !client: true + !bound: both x: lf32 y: lf32 z: lf32 @@ -744,8 +419,7 @@ packet_respawn: packet_container_open: !id: 0x2e - !server: true - !client: false + !bound: server window_id: u8 type: u8 coordinates: BlockCoordinates @@ -753,30 +427,26 @@ packet_container_open: packet_container_close: !id: 0x2f - !server: true - !client: true + !bound: both window_id: u8 server: bool packet_player_hotbar: !id: 0x30 - !server: true - !client: true + !bound: both selected_slot: varint window_id: u8 select_slot_: bool packet_inventory_content: !id: 0x31 - !server: true - !client: true + !bound: both inventory_id: varint input: ItemStacks packet_inventory_slot: !id: 0x32 - !server: true - !client: true + !bound: both inventory_id: varint slot: varint uniqueid: zigzag32 @@ -784,16 +454,14 @@ packet_inventory_slot: packet_container_set_data: !id: 0x33 - !server: true - !client: false + !bound: server window_id: u8 property: zigzag32 value: zigzag32 packet_crafting_data: !id: 0x34 - !server: true - !client: false + !bound: server recipes: Recipes potion_type_recipes: PotionTypeRecipes potion_container_recipes: PotionContainerChangeRecipes @@ -801,8 +469,7 @@ packet_crafting_data: packet_crafting_event: !id: 0x35 - !server: true - !client: true + !bound: both window_id: u8 recipe_type: zigzag32 recipe_id: uuid @@ -811,13 +478,11 @@ packet_crafting_event: packet_gui_data_pick_item: !id: 0x36 - !server: true - !client: false + !bound: server packet_adventure_settings: !id: 0x37 - !server: true - !client: true + !bound: both flags: varint command_permission: varint action_permissions: varint @@ -827,15 +492,13 @@ packet_adventure_settings: packet_block_entity_data: !id: 0x38 - !server: true - !client: true + !bound: both coordinates: BlockCoordinates nbt: nbt packet_player_input: !id: 0x39 - !server: false - !client: true + !bound: client motion_x: lf32 motion_z: lf32 jumping: bool @@ -843,8 +506,7 @@ packet_player_input: packet_level_chunk: !id: 0x3a - !server: true - !client: false + !bound: server chunk_x: zigzag32 chunk_z: zigzag32 sub_chunk_count: varint @@ -852,115 +514,97 @@ packet_level_chunk: packet_set_commands_enabled: !id: 0x3b - !server: true - !client: false + !bound: server enabled: bool packet_set_difficulty: !id: 0x3c - !server: true - !client: false + !bound: server difficulty: varint packet_change_dimension: !id: 0x3d - !server: true - !client: false + !bound: server dimension: zigzag32 position: vec3f respawn: bool packet_set_player_game_type: !id: 0x3e - !server: true - !client: true + !bound: both gamemode: zigzag32 packet_player_list: !id: 0x3f - !server: true - !client: false + !bound: server records: PlayerRecords packet_simple_event: !id: 0x40 - !server: true - !client: false + !bound: server event_type: lu16 packet_spawn_experience_orb: !id: 0x42 - !server: true - !client: false + !bound: server position: vec3f count: zigzag32 packet_clientbound_map_item_data: !id: 0x43 - !server: true - !client: false + !bound: server mapinfo: MapInfo packet_map_info_request: !id: 0x44 - !server: true - !client: true + !bound: both map_id: zigzag64 packet_request_chunk_radius: !id: 0x45 - !server: true - !client: true + !bound: both chunk_radius: zigzag32 packet_chunk_radius_update: !id: 0x46 - !server: true - !client: false + !bound: server chunk_radius: zigzag32 packet_item_frame_drop_item: !id: 0x47 - !server: true - !client: true + !bound: both coordinates: BlockCoordinates packet_game_rules_changed: !id: 0x48 - !server: true - !client: false + !bound: server rules: GameRules packet_camera: !id: 0x49 - !server: true - !client: false + !bound: server unknown1: zigzag64 unknown2: zigzag64 packet_boss_event: !id: 0x4a - !server: true - !client: false + !bound: server boss_entity_id: zigzag64 event_type: varint packet_show_credits: !id: 0x4b - !server: true - !client: false + !bound: server runtime_entity_id: varint status: zigzag32 packet_available_commands: !id: 0x4c - !server: true - !client: false + !bound: server packet_command_request: !id: 0x4d - !server: false - !client: true + !bound: client command: string command_type: varint unknown_uuid: uuid @@ -969,19 +613,16 @@ packet_command_request: packet_command_block_update: !id: 0x4e - !server: false - !client: true + !bound: client is_block: bool packet_command_output: !id: 0x4f - !server: true - !client: false + !bound: server packet_update_trade: !id: 0x50 - !server: true - !client: false + !bound: server window_id: u8 window_type: u8 unknown0: varint @@ -995,8 +636,7 @@ packet_update_trade: packet_update_equipment: !id: 0x51 - !server: true - !client: false + !bound: server window_id: u8 window_type: u8 unknown: u8 @@ -1005,8 +645,7 @@ packet_update_equipment: packet_resource_pack_data_info: !id: 0x52 - !server: true - !client: false + !bound: server package_id: string max_chunk_size: lu32 chunk_count: lu32 @@ -1017,8 +656,7 @@ packet_resource_pack_data_info: packet_resource_pack_chunk_data: !id: 0x53 - !server: true - !client: false + !bound: server package_id: string chunk_index: lu32 progress: lu64 @@ -1026,22 +664,19 @@ packet_resource_pack_chunk_data: packet_resource_pack_chunk_request: !id: 0x54 - !server: false - !client: true + !bound: client package_id: string chunk_index: lu32 packet_transfer: !id: 0x55 - !server: true - !client: false + !bound: server server_address: string port: lu16 packet_play_sound: !id: 0x56 - !server: true - !client: false + !bound: server name: string coordinates: BlockCoordinates volume: lf32 @@ -1049,15 +684,13 @@ packet_play_sound: packet_stop_sound: !id: 0x57 - !server: true - !client: false + !bound: server name: string stop_all: bool packet_set_title: !id: 0x58 - !server: true - !client: false + !bound: server type: zigzag32 text: string fade_in_time: zigzag32 @@ -1066,31 +699,26 @@ packet_set_title: packet_add_behavior_tree: !id: 0x59 - !server: true - !client: false + !bound: server behaviortree: string packet_structure_block_update: !id: 0x5a - !server: true - !client: false + !bound: server packet_show_store_offer: !id: 0x5b - !server: true - !client: false + !bound: server unknown0: string unknown1: bool packet_purchase_receipt: !id: 0x5c - !server: false - !client: true + !bound: client packet_player_skin: !id: 0x5d - !server: true - !client: true + !bound: both uuid: uuid skin: Skin skin_name: string @@ -1099,30 +727,25 @@ packet_player_skin: packet_sub_client_login: !id: 0x5e - !server: true - !client: false + !bound: server packet_initiate_web_socket_connection: !id: 0x5f - !server: true - !client: false + !bound: server server: string packet_set_last_hurt_by: !id: 0x60 - !server: true - !client: false + !bound: server unknown: varint packet_book_edit: !id: 0x61 - !server: true - !client: false + !bound: server packet_npc_request: !id: 0x62 - !server: true - !client: true + !bound: both runtime_entity_id: varint unknown0: u8 unknown1: string @@ -1130,60 +753,51 @@ packet_npc_request: packet_photo_transfer: !id: 0x63 - !server: false - !client: true + !bound: client file_name: string image_data: string unknown2: string packet_modal_form_request: !id: 0x64 - !server: true - !client: false + !bound: server form_id: varint data: string packet_modal_form_response: !id: 0x65 - !server: false - !client: true + !bound: client form_id: varint data: string packet_server_settings_request: !id: 0x66 - !server: false - !client: true + !bound: client packet_server_settings_response: !id: 0x67 - !server: true - !client: false + !bound: server form_id: varint data: string packet_show_profile: !id: 0x68 - !server: true - !client: false + !bound: server xuid: string packet_set_default_game_type: !id: 0x69 - !server: true - !client: false + !bound: server gamemode: varint packet_remove_objective: !id: 0x6a - !server: true - !client: false + !bound: server objective_name: string packet_set_display_objective: !id: 0x6b - !server: true - !client: false + !bound: server display_slot: string objective_name: string display_name: string @@ -1192,14 +806,12 @@ packet_set_display_objective: packet_set_score: !id: 0x6c - !server: true - !client: false + !bound: server entries: ScoreEntries packet_lab_table: !id: 0x6d - !server: true - !client: true + !bound: both useless_byte: u8 lab_table_x: varint lab_table_y: varint @@ -1208,8 +820,7 @@ packet_lab_table: packet_update_block_synced: !id: 0x6e - !server: true - !client: false + !bound: server coordinates: BlockCoordinates block_runtime_id: varint block_priority: varint @@ -1219,46 +830,39 @@ packet_update_block_synced: packet_move_entity_delta: !id: 0x6f - !server: true - !client: false + !bound: server runtime_entity_id: varint flags: lu16 packet_set_scoreboard_identity: !id: 0x70 - !server: true - !client: false + !bound: server entries: ScoreboardIdentityEntries packet_set_local_player_as_initialized: !id: 0x71 - !server: false - !client: true + !bound: client runtime_entity_id: varint packet_update_soft_enum: !id: 0x72 - !server: true - !client: false + !bound: server packet_network_stack_latency: !id: 0x73 - !server: true - !client: true + !bound: both timestamp: lu64 unknown_flag: u8 packet_script_custom_event: !id: 0x75 - !server: true - !client: true + !bound: both event_name: string event_data: string packet_spawn_particle_effect: !id: 0x76 - !server: true - !client: false + !bound: server dimension_id: u8 entity_id: zigzag64 position: vec3f @@ -1266,14 +870,12 @@ packet_spawn_particle_effect: packet_available_entity_identifiers: !id: 0x77 - !server: true - !client: false + !bound: server nbt: nbt packet_level_sound_event_v2: !id: 0x78 - !server: true - !client: true + !bound: both sound_id: u8 position: vec3f block_id: zigzag32 @@ -1283,21 +885,18 @@ packet_level_sound_event_v2: packet_network_chunk_publisher_update: !id: 0x79 - !server: true - !client: false + !bound: server coordinates: BlockCoordinates radius: varint packet_biome_definition_list: !id: 0x7a - !server: true - !client: false + !bound: server nbt: nbt packet_level_sound_event: !id: 0x7b - !server: true - !client: true + !bound: both sound_id: varint position: vec3f block_id: zigzag32 @@ -1307,18 +906,15 @@ packet_level_sound_event: packet_level_event_generic: !id: 0x7c - !server: true - !client: false + !bound: server packet_lectern_update: !id: 0x7d - !server: true - !client: false + !bound: server packet_video_stream_connect: !id: 0x7e - !server: true - !client: false + !bound: server server_uri: string frame_send_frequency: lf32 action: u8 @@ -1327,86 +923,71 @@ packet_video_stream_connect: packet_client_cache_status: !id: 0x81 - !server: true - !client: true + !bound: both enabled: bool packet_on_screen_texture_animation: !id: 0x82 - !server: true - !client: false + !bound: server packet_map_create_locked_copy: !id: 0x83 - !server: true - !client: false + !bound: server packet_structure_template_data_export_request: !id: 0x84 - !server: true - !client: false + !bound: server packet_structure_template_data_export_response: !id: 0x85 - !server: true - !client: false + !bound: server packet_update_block_properties: !id: 0x86 - !server: true - !client: false + !bound: server nbt: nbt packet_client_cache_blob_status: !id: 0x87 - !server: true - !client: false + !bound: server packet_client_cache_miss_response: !id: 0x88 - !server: true - !client: false + !bound: server packet_network_settings: !id: 0x8f - !server: true - !client: true + !bound: both unknown: u8 compression_threshold: u8 packet_creative_content: !id: 0x91 - !server: true - !client: false + !bound: server items: ItemStacks packet_player_enchant_options: !id: 0x92 - !server: true - !client: false + !bound: server enchant_options: EnchantOptions packet_item_stack_request: !id: 0x93 - !server: false - !client: true + !bound: client requests: ItemStackRequests packet_item_stack_response: !id: 0x94 - !server: true - !client: false + !bound: server responses: ItemStackResponses packet_update_player_game_type: !id: 0x97 - !server: false - !client: true + !bound: client packet_packet_violation_warning: !id: 0x9c - !server: false - !client: true + !bound: client violation_type: zigzag32 severity: zigzag32 packet_id: zigzag32 @@ -1414,13 +995,11 @@ packet_packet_violation_warning: packet_item_component: !id: 0xa2 - !server: true - !client: false + !bound: server entries: ItemComponentList packet_filter_text_packet: !id: 0xa3 - !server: true - !client: false + !bound: server text: string from_server: bool From 1a7205b3d18fc8d6f7b1611d0942a63ff4622eb9 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 7 Feb 2021 19:45:46 -0500 Subject: [PATCH 090/458] update protocol, add some doc --- data/new/proto.yml | 240 ++++++++++++++++++++++++++++++++++++++++++-- data/new/types.yaml | 5 + data/newproto.json | 238 +++++++++++++++++++++++++++++++++++++++---- src/server.js | 19 +--- src/serverTest.js | 2 +- 5 files changed, 456 insertions(+), 48 deletions(-) diff --git a/data/new/proto.yml b/data/new/proto.yml index 737c70e..5bf4498 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -14,138 +14,356 @@ nbt: native !import: packet_map.yml +!StartDocs: Packets + +# # Login Sequence +# The login process is as follows: +# +# C→S: [Login](#packet_login) +# S→C: [Server To Client Handshake](#packet_server_to_client_handshake) +# C→S: [Client To Server Handshake](#packet_client_to_server_handshake) +# S→C: [Play Status (Login success)](#packet_play_status) +# To spawn, the following packets should be sent, in order, after the ones above: +# +# S→C: [Resource Packs Info](#packet_resource_packs_info) +# C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) +# S→C: [Resource Pack Stack](#packet_resource_pack_stack) +# C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) +# S→C: [Start Game](#packet_start_game) +# S→C: [Creative Content](#packet_creative_content) +# S→C: [Biome Definition List](#packet_biome_definition_list) +# S→C: [Chunks](#packet_level_chunk) +# S→C: [Play Status (Player spawn)](#packet_play_status) +# If there are no resource packs being sent, a Resource Pack Stack can be sent directly +# after Resource Packs Info to avoid the client responses. + + packet_login: !id: 0x01 !bound: client protocol_version: i32 + # The combined size of the `chain` and `client_data` payload_size: varint + # JSON array of JWT data: contains the display name, UUID and XUID + # It should be signed by the Mojang public key chain: LittleString + # Skin related data client_data: LittleString packet_play_status: !id: 0x02 !bound: server - status: i32 + status: i32 => + # Sent after Login has been successfully decoded and the player has logged in + 0: login_success + # Displays "Could not connect: Outdated client!" + 1: failed_client + # Displays "Could not connect: Outdated server!" + 2: failed_spawn + # Sent after world data to spawn the player + 3: player_spawn + # Displays "Unable to connect to world. Your school does not have access to this server." + 4: failed_invalid_tenant + # Displays "The server is not running Minecraft: Education Edition. Failed to connect." + 5: failed_vanilla_edu + # Displays "The server is running an incompatible edition of Minecraft. Failed to connect." + 6: failed_edu_vanilla + # Displays "Wow this server is popular! Check back later to see if space opens up. Server Full" + 7: failed_server_full + packet_server_to_client_handshake: !id: 0x03 !bound: server + # Contains the salt to complete the Diffie-Hellman key exchange token: string + +# Sent by the client in response to a Server To Client Handshake packet +# sent by the server. It is the first encrypted packet in the login handshake +# and serves as a confirmation that encryption is correctly initialized client side. +# It has no fields. packet_client_to_server_handshake: !id: 0x04 !bound: client +# Sent by the server to disconnect a client. packet_disconnect: !id: 0x05 !bound: server + # Specifies if the disconnection screen should be hidden when the client is disconnected, + # meaning it will be sent directly to the main menu. hide_disconnect_reason: bool + # An optional message to show when disconnected. message: string + packet_resource_packs_info: !id: 0x06 !bound: server + # If the resource pack requires the client accept it. must_accept: bool + # If scripting is enabled. has_scripts: bool + # A list of behaviour packs that the client needs to download before joining the server. + # All of these behaviour packs will be applied together. behaviour_packs: BehaviourPackInfos + # A list of resource packs that the client needs to download before joining the server. + # The order of these resource packs is not relevant in this packet. It is however important in the Resource Pack Stack packet. texture_packs: TexturePackInfos packet_resource_pack_stack: !id: 0x07 !bound: server + # If the resource pack must be accepted for the player to join the server. must_accept: bool + # [inline] behavior_packs: ResourcePackIdVersions + # [inline] resource_packs: ResourcePackIdVersions game_version: string - experiments: Experiments - experiments_previously_toggled: bool + experiments: Experiments # ??? such random fields + experiments_previously_used: bool packet_resource_pack_client_response: !id: 0x08 !bound: client - response_status: u8 + response_status: u8 => + 0: none + 1: refused + 2: send_packs + 3: have_all_packs + 4: completed + # All of the pack IDs. resourcepackids: ResourcePackIds +# Sent by the client to the server to send chat messages, and by the server to the client +# to forward or send messages, which may be chat, popups, tips etc. +## https://github.com/pmmp/PocketMine-MP/blob/a43b46a93cb127f037c879b5d8c29cda251dd60c/src/pocketmine/network/mcpe/protocol/TextPacket.php +## https://github.com/Sandertv/gophertunnel/blob/05ac3f843dd60d48b9ca0ab275cda8d9e85d8c43/minecraft/protocol/packet/text.go packet_text: !id: 0x09 !bound: both - type: u8 + type: u8 => + 0: raw + 1: chat + 2: translation + 3: popup + 4: jukebox_popup + 5: tip + 6: system + 7: whisper + 8: announcement + 9: json_whisper + 10: json + # NeedsTranslation specifies if any of the messages need to be translated. It seems that where % is found + # in translatable text types, these are translated regardless of this bool. Translatable text types + # include TextTypeTip, TextTypePopup and TextTypeJukeboxPopup. + needs_translation: bool + _: type? + if chat or whisper or announcement: + sourceName: string + if raw or tip or system or json_whisper or json: + message: string + if translation or popup or jukebox_popup: + message: string + paramaters: string[]varint + # The XUID of the player who sent this message. + xuid: string + # PlatformChatID is an identifier only set for particular platforms when chatting (presumably only for + # Nintendo Switch). It is otherwise an empty string, and is used to decide which players are able to + # chat with each other. + platform_chat_id: string +# For additional information and examples of all the chat types above, see here: https://imgur.com/a/KhcFscg + +# Sent by the server to update the current time client-side. The client actually advances time +# client-side by itself, so this packet does not need to be sent each tick. It is merely a means +# of synchronizing time between server and client. packet_set_time: !id: 0x0a !bound: server + # Time is the current time. The time is not limited to 24000 (time of day), but continues + # progressing after that. time: zigzag32 +# Sent by the server to send information about the world the player will be spawned in. packet_start_game: !id: 0x0b !bound: server + # The unique ID of the player. The unique ID is a value that remains consistent across + # different sessions of the same world, but most unofficial servers simply fill the + # runtime ID of the entity out for this field. entity_id: zigzag64 + # The runtime ID of the player. The runtime ID is unique for each world session, + # and entities are generally identified in packets using this runtime ID. runtime_entity_id: varint player_gamemode: zigzag32 + # The spawn position of the player in the world. In servers this is often the same as the + # world's spawn position found below. spawn: vec3f + # The pitch and yaw of the player rotation: vec3f + # The seed used to generate the world. Unlike in Java edition, the seed is a 32bit Integer here. seed: zigzag32 biome_type: li16 biome_name: string + # Dimension is the ID of the dimension that the player spawns in. It is a value from 0-2, + # with 0 being the overworld, 1 being the nether and 2 being the end. dimension: zigzag32 + # Generator is the generator used for the world. It is a value from 0-4, with 0 being old + # limited worlds, 1 being infinite worlds, 2 being flat worlds, 3 being nether worlds and + # 4 being end worlds. A value of 0 will actually make the client stop rendering chunks you + # send beyond the world limit. generator: zigzag32 + # The game mode that a player gets when it first spawns in the world. It is shown in the + # settings and is used if the Player Gamemode is set to 5. gamemode: zigzag32 + # Difficulty is the difficulty of the world. It is a value from 0-3, with 0 being peaceful, + # 1 being easy, 2 being normal and 3 being hard. difficulty: zigzag32 - x: zigzag32 - y: varint - z: zigzag32 + # The block on which the world spawn of the world. This coordinate has no effect on the place + # that the client spawns, but it does have an effect on the direction that a compass poInts. + spawn_position: BlockCoordinates + # Defines if achievements are disabled in the world. The client crashes if this value is set + # to true while the player's or the world's game mode is creative, and it's recommended to simply + # always set this to false as a server. has_achievements_disabled: bool + # The time at which the day cycle was locked if the day cycle is disabled using the respective + # game rule. The client will maIntain this time as Boolean as the day cycle is disabled. day_cycle_stop_time: zigzag32 + # Some Minecraft: Education Edition field that specifies what 'region' the world was from, + # with 0 being None, 1 being RestOfWorld, and 2 being China. The actual use of this field is unknown. edu_offer: zigzag32 + # Specifies if the world has education edition features enabled, such as the blocks or entities + # specific to education edition. has_edu_features_enabled: bool edu_product_uuid_: string + # The level specifying the Intensity of the rain falling. When set to 0, no rain falls at all. rain_level: lf32 lightning_level: lf32 + # The level specifying the Intensity of the thunder. This may actually be set independently + # from the rain level, meaning dark clouds can be produced without rain. has_confirmed_platform_locked_content: bool + # Specifies if the world is a multi-player game. This should always be set to true for servers. is_multiplayer: bool + # Specifies if LAN broadcast was Intended to be enabled for the world. broadcast_to_lan: bool + # The mode used to broadcast the joined game across XBOX Live. xbox_live_broadcast_mode: varint + # The mode used to broadcast the joined game across the platform. platform_broadcast_mode: varint + # If commands are enabled for the player. It is recommended to always set this to true on the + # server, as setting it to false means the player cannot, under any circumstance, use a command. enable_commands: bool + # Specifies if the texture pack the world might hold is required, meaning the client was + # forced to download it before joining. is_texturepacks_required: bool + # Defines game rules currently active with their respective values. The value of these game + # rules may be either 'bool', 'Int32' or 'Float32'. Some game rules are server side only, + # and don't necessarily need to be sent to the client. gamerules: GameRules experiments: Experiments - experiments_previously_toggled: bool + experiments_previously_used: bool + # Specifies if the world had the bonus map setting enabled when generating it. + # It does not have any effect client-side. bonus_chest: bool + # Specifies if the world has the start with map setting enabled, meaning each + # joining player obtains a map. This should always be set to false, because the + # client obtains a map all on its own accord if this is set to true. map_enabled: bool + # The permission level of the player. It is a value from 0-3, with 0 being visitor, + # 1 being member, 2 being operator and 3 being custom. permission_level: zigzag32 + # The radius around the player in which chunks are ticked. Most servers set this value + # to a fixed number, as it does not necessarily affect anything client-side. server_chunk_tick_range: li32 + # Specifies if the texture pack of the world is locked, meaning it cannot be disabled + # from the world. This is typically set for worlds on the marketplace that have a dedicated + # texture pack. has_locked_behavior_pack: bool + # Specifies if the texture pack of the world is locked, meaning it cannot be disabled from the + # world. This is typically set for worlds on the marketplace that have a dedicated texture pack. has_locked_resource_pack: bool + # Specifies if the world from the server was from a locked world template. + # For servers this should always be set to false. is_from_locked_world_template: bool msa_gamertags_only: bool + # Specifies if the world from the server was from a locked world template. + # For servers this should always be set to false. is_from_world_template: bool + # Specifies if the world was a template that locks all settings that change properties + # above in the settings GUI. It is recommended to set this to true for servers that + # do not allow things such as setting game rules through the GUI. is_world_template_option_locked: bool + # A hack that Mojang put in place to preserve backwards compatibility with old villagers. + # The his never actually read though, so it has no functionality. only_spawn_v1_villagers: bool + # The version of the game from which Vanilla features will be used. + # The exact function of this field isn't clear. game_version: string limited_world_width_: li32 limited_world_length_: li32 is_new_nether_: bool experimental_gameplay_override: bool + # A base64 encoded world ID that is used to identify the world. level_id: string + # The name of the world that the player is joining. Note that this field shows up + # above the player list for the rest of the game session, and cannot be changed. + # Setting the server name to this field is recommended. world_name: string + # A UUID specific to the premium world template that might have been used to + # generate the world. Servers should always fill out an empty String for this. premium_world_template_id: string + # Specifies if the world was a trial world, meaning features are limited and there + # is a time limit on the world. is_trial: bool - movement_type: zigzag32 + # Specifies if the client or server is authoritative over the movement of the player, + # meaning it controls the movement of it. + ## https://github.com/pmmp/PocketMine-MP/blob/a43b46a93cb127f037c879b5d8c29cda251dd60c/src/pocketmine/network/mcpe/protocol/types/PlayerMovementType.php#L26 + movement_authority: zigzag32 => + 0: client + 1: server + # PlayerAuthInputPacket + a bunch of junk that solves a nonexisting problem + 2: server_v2_rewind + # The total time in ticks that has elapsed since the start of the world. current_tick: li64 + # The seed used to seed the random used to produce enchantments in the enchantment table. + # Note that the exact correct random implementation must be used to produce the correct + # results both client- and server-side. enchantment_seed: zigzag32 - block_palette: BlockPalette + + ## This is not sent anymore in protocol versions > 419 (Bedrock Edition v1.16.100) + ## A list of all blocks registered on the server. + ## block_palette: BlockPalette + # A list of all items with their legacy IDs which are available in the game. + # Failing to send any of the items that are in the game will crash mobile clients. itemstates: Itemstates + # A unique ID specifying the multi-player session of the player. + # A random UUID should be filled out for this field. multiplayer_correlation_id: string server_authoritative_inventory: bool packet_add_player: !id: 0x0c !bound: server + # UUID is the UUID of the player. It is the same UUID that the client sent in the + # Login packet at the start of the session. A player with this UUID must exist + # in the player list (built up using the Player List packet) for it to show up in-game. uuid: uuid + # Username is the name of the player. This username is the username that will be + # set as the initial name tag of the player. username: string + # The unique ID of the player. The unique ID is a value that remains consistent + # across different sessions of the same world, but most unoffical servers simply + # fill the runtime ID of the player out for this field. entity_id_self: zigzag64 + # The runtime ID of the player. The runtime ID is unique for each world session, + # and entities are generally identified in packets using this runtime ID. runtime_entity_id: varint + # An identifier only set for particular platforms when chatting (presumably only for + # Nintendo Switch). It is otherwise an empty string, and is used to decide which players + # are able to chat with each other. platform_chat_id: string x: lf32 y: lf32 diff --git a/data/new/types.yaml b/data/new/types.yaml index c84339c..6e32afe 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -1,3 +1,5 @@ +!StartDocs: Types + BehaviourPackInfos: []li16 uuid: string version: string @@ -18,8 +20,11 @@ TexturePackInfos: []li16 rtx_enabled: bool ResourcePackIdVersions: []varint + # The ID of the resource pack. uuid: string + # The version of the resource pack. version: string + # The subpack name of the resource pack. name: string ResourcePackIds: string[]varint diff --git a/data/newproto.json b/data/newproto.json index 13ffeaf..5424284 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -2361,7 +2361,22 @@ [ { "name": "status", - "type": "i32" + "type": [ + "mapper", + { + "type": "i32", + "mappings": { + "0": "login_success", + "1": "failed_client", + "2": "failed_spawn", + "3": "player_spawn", + "4": "failed_invalid_tenant", + "5": "failed_vanilla_edu", + "6": "failed_edu_vanilla", + "7": "failed_server_full" + } + } + ] } ] ], @@ -2436,7 +2451,7 @@ "type": "Experiments" }, { - "name": "experiments_previously_toggled", + "name": "experiments_previously_used", "type": "bool" } ] @@ -2446,7 +2461,19 @@ [ { "name": "response_status", - "type": "u8" + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "refused", + "2": "send_packs", + "3": "have_all_packs", + "4": "completed" + } + } + ] }, { "name": "resourcepackids", @@ -2459,7 +2486,178 @@ [ { "name": "type", - "type": "u8" + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "raw", + "1": "chat", + "2": "translation", + "3": "popup", + "4": "jukebox_popup", + "5": "tip", + "6": "system", + "7": "whisper", + "8": "announcement", + "9": "json_whisper", + "10": "json" + } + } + ] + }, + { + "name": "needs_translation", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "chat": [ + "container", + [ + { + "name": "sourceName", + "type": "string" + } + ] + ], + "whisper": [ + "container", + [ + { + "name": "sourceName", + "type": "string" + } + ] + ], + "announcement": [ + "container", + [ + { + "name": "sourceName", + "type": "string" + } + ] + ], + "raw": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "tip": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "system": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json_whisper": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "translation": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "jukebox_popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "xuid", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" } ] ], @@ -2524,16 +2722,8 @@ "type": "zigzag32" }, { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "zigzag32" + "name": "spawn_position", + "type": "BlockCoordinates" }, { "name": "has_achievements_disabled", @@ -2600,7 +2790,7 @@ "type": "Experiments" }, { - "name": "experiments_previously_toggled", + "name": "experiments_previously_used", "type": "bool" }, { @@ -2684,8 +2874,18 @@ "type": "bool" }, { - "name": "movement_type", - "type": "zigzag32" + "name": "movement_authority", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "client", + "1": "server", + "2": "server_v2_rewind" + } + } + ] }, { "name": "current_tick", @@ -2695,10 +2895,6 @@ "name": "enchantment_seed", "type": "zigzag32" }, - { - "name": "block_palette", - "type": "BlockPalette" - }, { "name": "itemstates", "type": "Itemstates" diff --git a/src/server.js b/src/server.js index af25535..13fa23b 100644 --- a/src/server.js +++ b/src/server.js @@ -25,17 +25,6 @@ function createDeserializer() { return new Parser(proto, 'mcpe_packet'); } -const PLAY_STATUS = { - 'LoginSuccess': 0, - 'LoginFailedClient': 1, - 'LoginFailedServer': 2, - 'PlayerSpawn': 3, - 'LoginFailedInvalidTenant': 4, - 'LoginFailedVanillaEdu': 5, - 'LoginFailedEduVanilla': 6, - 'LoginFailedServerFull': 7 -} - class Player extends Connection { constructor(server, connection, options) { super() @@ -55,11 +44,11 @@ class Player extends Connection { const clientVer = body.protocol_version if (this.server.options.version) { if (this.server.options.version < clientVer) { - this.sendDisconnectStatus(PLAY_STATUS.LoginFailedClient) + this.sendDisconnectStatus(failed_client) return } } else if (clientVer < MIN_VERSION) { - this.sendDisconnectStatus(PLAY_STATUS.LoginFailedClient) + this.sendDisconnectStatus(failed_client) return } @@ -91,7 +80,7 @@ class Player extends Connection { // Client to Server handshake response. This indicates successful encryption onHandshake() { // https://wiki.vg/Bedrock_Protocol#Play_Status - this.write('play_status', { status: PLAY_STATUS.LoginSuccess }) + this.write('play_status', { status: 'login_success' }) this.emit('join') } @@ -181,4 +170,4 @@ class Server extends EventEmitter { } } -module.exports = { Server, Player, PLAY_STATUS } \ No newline at end of file +module.exports = { Server, Player } \ No newline at end of file diff --git a/src/serverTest.js b/src/serverTest.js index aa356fc..7dccb65 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -33,7 +33,7 @@ server.on('connect', ({ client }) => { 'resource_packs': [], 'game_version': '', 'experiments': [], - 'experiments_previously_toggled': false + 'experiments_previously_used': false }) client.once('resource_pack_client_response', async (packet) => { From 60e57fad44f199720e1b8e154cc674963c6c76d6 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 10 Feb 2021 01:32:54 -0500 Subject: [PATCH 091/458] protocol updates, use ProtoDef compiler --- data/new/compile.js | 23 +++++- data/new/types.yaml | 33 ++++---- data/newproto.json | 78 ++++++++---------- package.json | 2 +- src/datatypes/compiler-minecraft.js | 39 +++++++++ src/options.js | 12 +++ src/server.js | 47 +++-------- src/serverTest.js | 14 ++-- src/transforms/serializer.js | 52 ++++++++---- test/serialization.js | 119 ++++++++++++++++++++++++++++ 10 files changed, 298 insertions(+), 121 deletions(-) create mode 100644 src/datatypes/compiler-minecraft.js create mode 100644 src/options.js create mode 100644 test/serialization.js diff --git a/data/new/compile.js b/data/new/compile.js index 2800ba8..6df30d9 100644 --- a/data/new/compile.js +++ b/data/new/compile.js @@ -1,4 +1,5 @@ const fs = require('fs') +const { ProtoDefCompiler } = require('protodef').Compiler let compile try { @@ -11,5 +12,23 @@ if (compile) { compile('./proto.yml', 'protocol.json') } -fs.writeFileSync( '../newproto.json', JSON.stringify({ types: require('./protocol.json') }, null, 2) ) -fs.unlinkSync('./protocol.json') //remove temp file \ No newline at end of file +fs.writeFileSync('../newproto.json', JSON.stringify({ types: require('./protocol.json') }, null, 2)) +fs.unlinkSync('./protocol.json') //remove temp file + +function createProtocol() { + const compiler = new ProtoDefCompiler() + const protocol = require('../newproto.json').types + compiler.addTypesToCompile(protocol) + compiler.addTypes(require('../../src/datatypes/compiler-minecraft')) + compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) + + fs.writeFileSync('../read.js', 'module.exports = ' + compiler.readCompiler.generate()) + fs.writeFileSync('../write.js', 'module.exports = ' + compiler.writeCompiler.generate()) + fs.writeFileSync('../size.js', 'module.exports = ' + compiler.sizeOfCompiler.generate()) + + const compiledProto = compiler.compileProtoDefSync() + return compiledProto +} + +console.log('Generating JS...') +createProtocol() \ No newline at end of file diff --git a/data/new/types.yaml b/data/new/types.yaml index 6e32afe..2168098 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -1,9 +1,9 @@ -!StartDocs: Types +# !StartDocs: Types BehaviourPackInfos: []li16 uuid: string version: string - size: lu64 + length: lu64 content_key: string sub_pack_name: string content_identity: string @@ -12,7 +12,7 @@ BehaviourPackInfos: []li16 TexturePackInfos: []li16 uuid: string version: string - size: lu64 + length: lu64 content_key: string sub_pack_name: string content_identity: string @@ -71,11 +71,11 @@ Item: default: auxiliary_value: zigzag32 has_nbt: lu16 => - 0xffff: '1' - 0x0000: '0' - _: has_nbt? - if 1: - nbt_version: u8 + 0xffff: 'true' + 0x0000: 'false' + nbt: has_nbt? + if true: + version: u8 nbt: nbt default: void can_place_on: string[]zigzag32 @@ -150,10 +150,10 @@ BlockCoordinates: # mojang... z: zigzag32 PlayerAttributes: []varint - min: lf32 - max: lf32 - current: lf32 - default: lf32 + min_value: lf32 + max_value: lf32 + current_value: lf32 + default_value: lf32 name: string Transaction: @@ -360,11 +360,10 @@ ScoreEntries: 1: player 2: entity 3: fake_player - _: entry_type? - if player or entity: - entity_unique_id: zigzag64 - if fake_player: - custom_name: string + entity_unique_id: entry_type? + if player or entity: zigzag64 + custom_name: entry_type? + if fake_player: string ScoreboardIdentityEntries: type: i8 => diff --git a/data/newproto.json b/data/newproto.json index 5424284..e520a62 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -25,7 +25,7 @@ "type": "string" }, { - "name": "size", + "name": "length", "type": "lu64" }, { @@ -64,7 +64,7 @@ "type": "string" }, { - "name": "size", + "name": "length", "type": "lu64" }, { @@ -281,24 +281,24 @@ { "type": "lu16", "mappings": { - "0": "0", - "65535": "1" + "0": "false", + "65535": "true" } } ] }, { - "anon": true, + "name": "nbt", "type": [ "switch", { "compareTo": "has_nbt", "fields": { - "1": [ + "true": [ "container", [ { - "name": "nbt_version", + "name": "version", "type": "u8" }, { @@ -431,6 +431,10 @@ "type": [ "container", [ + { + "name": "key", + "type": "varint" + }, { "name": "type", "type": [ @@ -576,19 +580,19 @@ "container", [ { - "name": "min", + "name": "min_value", "type": "lf32" }, { - "name": "max", + "name": "max_value", "type": "lf32" }, { - "name": "current", + "name": "current_value", "type": "lf32" }, { - "name": "default", + "name": "default_value", "type": "lf32" }, { @@ -771,7 +775,7 @@ "type": [ "switch", { - "compareTo": "../has_network_ids", + "compareTo": "has_network_ids", "fields": { "true": "zigzag32" }, @@ -1386,7 +1390,7 @@ "type": [ "switch", { - "compareTo": "../type", + "compareTo": "type", "fields": { "add": [ "container", @@ -1512,7 +1516,7 @@ "type": [ "switch", { - "compareTo": "../type", + "compareTo": "type", "fields": { "remove": [ "container", @@ -1532,39 +1536,27 @@ ] }, { - "anon": true, + "name": "entity_unique_id", "type": [ "switch", { "compareTo": "entry_type", "fields": { - "player": [ - "container", - [ - { - "name": "entity_unique_id", - "type": "zigzag64" - } - ] - ], - "entity": [ - "container", - [ - { - "name": "entity_unique_id", - "type": "zigzag64" - } - ] - ], - "fake_player": [ - "container", - [ - { - "name": "custom_name", - "type": "string" - } - ] - ] + "player": "zigzag64", + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "custom_name", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "fake_player": "string" }, "default": "void" } @@ -1618,7 +1610,7 @@ "type": [ "switch", { - "compareTo": "../type", + "compareTo": "type", "fields": { "TYPE_REGISTER_IDENTITY": "zigzag64" }, diff --git a/package.json b/package.json index 6c7aa73..30346b0 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "jwt-simple": "^0.5.6", "lodash.merge": "^4.4.0", "prismarine-nbt": "github:extremeheat/prismarine-nbt#le", - "protodef": "github:extremeheat/node-protodef#big", + "protodef": "github:extremeheat/node-protodef#compiler", "raknet": "git+https://github.com/mhsjlw/node-raknet.git#master", "uuid-1345": "^0.99.7" }, diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js new file mode 100644 index 0000000..f8fa767 --- /dev/null +++ b/src/datatypes/compiler-minecraft.js @@ -0,0 +1,39 @@ +const UUID = require('uuid-1345') +const minecraft = require('./minecraft') + +module.exports = { + Read: { + UUID: ['native', (buffer, offset) => { + return { + value: UUID.stringify(buffer.slice(offset, 16 + offset)), + size: 16 + } + }], + restBuffer: ['native', (buffer, offset) => { + return { + value: buffer.slice(offset), + size: buffer.length - offset + } + }], + nbt: ['native', minecraft.nbt[0]] + }, + Write: { + UUID: ['native', (value, buffer, offset) => { + const buf = UUID.parse(value) + buf.copy(buffer, offset) + return offset + 16 + }], + restBuffer: ['native', (value, buffer, offset) => { + value.copy(buffer, offset) + return offset + value.length + }], + nbt: ['native', minecraft.nbt[1]] + }, + SizeOf: { + UUID: ['native', 16], + restBuffer: ['native', (value) => { + return value.length + }], + nbt: ['native', minecraft.nbt[2]] + } +} diff --git a/src/options.js b/src/options.js new file mode 100644 index 0000000..dc329ea --- /dev/null +++ b/src/options.js @@ -0,0 +1,12 @@ +// Minimum supported version (< will be kicked) +const MIN_VERSION = 422 +// Currently supported verson +const CURRENT_VERSION = 422 + + +const defaultOptions = { + // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 + version: CURRENT_VERSION +} + +module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION } \ No newline at end of file diff --git a/src/server.js b/src/server.js index 13fa23b..8223f4f 100644 --- a/src/server.js +++ b/src/server.js @@ -1,29 +1,12 @@ const Listener = require('@jsprismarine/raknet/listener') -const { ProtoDef, Parser, Serializer } = require('protodef') const { EventEmitter } = require('events') +const { createDeserializer, createSerializer } = require('./transforms/serializer') const { Encrypt } = require('./auth/encryption') const { decodeLoginJWT } = require('./auth/chains') const { Connection } = require('./connection') +const Options = require('./options') -var protocol = require('../data/newproto.json').types; - -function createProtocol() { - var proto = new ProtoDef(); - proto.addTypes(require('./datatypes/minecraft')); - proto.addTypes(protocol); - - return proto; -} - -function createSerializer() { - var proto = createProtocol() - return new Serializer(proto, 'mcpe_packet'); -} - -function createDeserializer() { - var proto = createProtocol() - return new Parser(proto, 'mcpe_packet'); -} +const log = (...args) => console.log(...args) class Player extends Connection { constructor(server, connection, options) { @@ -102,20 +85,10 @@ class Player extends Connection { } } -// Minimum supported version (< will be kicked) -const MIN_VERSION = 422 -// Currently supported verson -const CURRENT_VERSION = 422 - -const defaultServerOptions = { - // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 - version: CURRENT_VERSION, -} - class Server extends EventEmitter { constructor(options) { super() - this.options = { ...defaultServerOptions, options } + this.options = { ...Options.defaultOptions, options } this.serializer = createSerializer() this.deserializer = createDeserializer() this.clients = {} @@ -123,8 +96,8 @@ class Server extends EventEmitter { } validateOptions() { - if (this.options.version < defaultServerOptions.version) { - throw new Error(`Unsupported protocol version < ${defaultServerOptions.version}: ${this.options.version}`) + if (this.options.version < Options.MIN_VERSION) { + throw new Error(`Unsupported protocol version < ${Options.MIN_VERSION} : ${this.options.version}`) } } @@ -133,7 +106,7 @@ class Server extends EventEmitter { } onOpenConnection = (conn) => { - console.log('Got connection', conn) + log('new connection', conn) const player = new Player(this, conn) this.clients[this.getAddrHash(conn.address)] = player @@ -141,12 +114,12 @@ class Server extends EventEmitter { } onCloseConnection = (inetAddr, reason) => { - console.log('Close connection', inetAddr, reason) + log('close connection', inetAddr, reason) delete this.clients[this.getAddrHash(inetAddr)] } onEncapsulated = (encapsulated, inetAddr) => { - console.log('Encapsulated', encapsulated, inetAddr) + log(inetAddr.address, ': Encapsulated', encapsulated) const buffer = encapsulated.buffer const client = this.clients[this.getAddrHash(inetAddr)] if (!client) { @@ -158,7 +131,7 @@ class Server extends EventEmitter { async create(serverIp, port) { this.listener = new Listener(this) this.raknet = await this.listener.listen(serverIp, port) - console.log('Listening on', serverIp, port) + log('Listening on', serverIp, port) this.raknet.on('openConnection', this.onOpenConnection) this.raknet.on('closeConnection', this.onCloseConnection) diff --git a/src/serverTest.js b/src/serverTest.js index 7dccb65..a02ac35 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -42,21 +42,23 @@ server.on('connect', ({ client }) => { let ids = 0 for (var item of CreativeItems) { let creativeitem = { runtime_id: items.length } + const has_nbt = !!item.nbt_b64 if (item.id != 0) { - const hasNbt = !!item.nbt_b64 creativeitem.item = { network_id: item.id, auxiliary_value: item.damage || 0, - has_nbt: hasNbt|0, - nbt_version: 1, + has_nbt, + nbt: { + version: 1, + }, blocking_tick: 0, can_destroy: [], can_place_on: [] } - if (hasNbt) { + if (has_nbt) { let nbtBuf = Buffer.from(item.nbt_b64, 'base64') - let { result } = await NBT.parse(nbtBuf, 'little') - creativeitem.item.nbt = result + let { parsed } = await NBT.parse(nbtBuf, 'little') + creativeitem.item.nbt.nbt = parsed } } items.push(creativeitem) diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 010e850..e07b63c 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,30 +1,52 @@ -'use strict'; -var ProtoDef = require('protodef').ProtoDef; -var Serializer = require('protodef').Serializer; -var Parser = require('protodef').Parser; - -var protocol = require('../../data/protocol.json').types; +const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler +const { FullPacketParser, Serializer } = require('protodef') function createProtocol() { - var proto = new ProtoDef(); - proto.addTypes(require('../datatypes/minecraft')); - proto.addTypes(protocol); + const protocol = require('../../data/newproto.json').types + console.log('Proto', protocol) + var compiler = new ProtoDefCompiler() + compiler.addTypesToCompile(protocol) + compiler.addTypes(require('../datatypes/compiler-minecraft')) + compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) - return proto; + const compiledProto = compiler.compileProtoDefSync() + return compiledProto +} + + +function getProtocol() { + const compiler = new ProtoDefCompiler() + compiler.addTypes(require('../datatypes/compiler-minecraft')) + compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) + + const compile = (compiler, file) => { + global.native = compiler.native // eslint-disable-line + const { PartialReadError } = require('protodef/src/utils') // eslint-disable-line + return require(file)() // eslint-disable-line + } + + return new CompiledProtodef( + compile(compiler.sizeOfCompiler, '../../data/size.js'), + compile(compiler.writeCompiler, '../../data/write.js'), + compile(compiler.readCompiler, '../../data/read.js') + // compiler.sizeOfCompiler.compile(fs.readFileSync(__dirname + '/../../data/size.js', 'utf-8')), + // compiler.writeCompiler.compile(fs.readFileSync(__dirname + '/../../data/write.js', 'utf-8')), + // compiler.readCompiler.compile(fs.readFileSync(__dirname + '/../../data/read.js', 'utf-8')) + ) } function createSerializer() { - var proto = createProtocol(); - return new Serializer(proto, 'packet'); + var proto = getProtocol() + return new Serializer(proto, 'mcpe_packet'); } function createDeserializer() { - var proto = createProtocol(); - return new Parser(proto, 'packet'); + var proto = getProtocol() + return new FullPacketParser(proto, 'mcpe_packet'); } module.exports = { createDeserializer: createDeserializer, createSerializer: createSerializer, createProtocol: createProtocol -}; +} \ No newline at end of file diff --git a/test/serialization.js b/test/serialization.js new file mode 100644 index 0000000..c7588ca --- /dev/null +++ b/test/serialization.js @@ -0,0 +1,119 @@ +const { createDeserializer, createSerializer } = require('../src/transforms/serializer') + +function test() { + const serializer = createSerializer() + const deserializer = createDeserializer() + + function write(name, params) { + const packet = serializer.createPacketBuffer({ name, params }) + console.log('Encoded', packet) + return packet + } + + function read(packet) { + const des = deserializer.parsePacketBuffer(packet) + return des + } + + async function creativeTest() { + let CreativeItems = require('../../data/creativeitems.json') + + let items = [] + let ids = 0 + for (var item of CreativeItems) { + let creativeitem = { runtime_id: items.length } + if (item.id != 0) { + const hasNbt = !!item.nbt_b64 + creativeitem.item = { + network_id: item.id, + auxiliary_value: item.damage || 0, + has_nbt: hasNbt, + nbt: { version: 1 }, + blocking_tick: 0, + can_destroy: [], + can_place_on: [] + } + if (hasNbt) { + let nbtBuf = Buffer.from(item.nbt_b64, 'base64') + let { result } = await NBT.parse(nbtBuf, 'little') + + const buf = NBT.writeUncompressed(result, 'littleVarint') + + console.log(nbtBuf, buf, JSON.stringify(result)) + + console.log('\n') + + let res2 = await NBT.parse(buf, 'littleVarint') + console.log(JSON.stringify(result), JSON.stringify(res2.result)) + console.assert(JSON.stringify(result) == JSON.stringify(res2.result), JSON.stringify(result), JSON.stringify(res2.result)) + + console.log('\n') + + creativeitem.item.nbt.nbt = result + } + } + + items.push(creativeitem) + console.log(JSON.stringify(creativeitem)) + // console.log(JSON.stringify(creativeitem)) + + var s = write('creative_content', { items: [creativeitem] }) + var d = read(s).data.params + + // console.log(JSON.stringify(d), JSON.stringify(s)) + // if (JSON.stringify(d) != JSON.stringify(creative_content)) throw 'mismatch' + } + } + + async function creativeTst() { + var creativeitem = { + "runtime_id": 1166, + "item": { + "network_id": 403, + "auxiliary_value": 0, + "has_nbt": true, + "nbt": { + "version": 1, + "nbt": { + "type": "compound", + "name": "", + "value": { + "ench": { + "type": "list", + "value": { + "type": "compound", + "value": [ + { + "id": { + "type": "short", + "value": 0 + }, + "lvl": { + "type": "short", + "value": 1 + } + } + ] + } + } + } + } + }, + "blocking_tick": 0, + "can_destroy": [], + "can_place_on": [] + } + } + + var s = write('creative_content', { items: [creativeitem] }) + var d = read(s).data.params + console.log(JSON.stringify(d)) + } + + + creativeTst() +} + +if (!module.parent) { + test() +} \ No newline at end of file From 49cff40097c8cccdac46570c0088a7ec626b827b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 10 Feb 2021 05:04:10 -0500 Subject: [PATCH 092/458] cliet auth --- .gitignore | 3 +- package.json | 6 +- src/client.js | 112 ++++++++++++++ src/client/auth.js | 104 +++++++++++++ src/client/authConstants.js | 4 + src/client/authFlow.js | 131 ++++++++++++++++ src/client/tokens.js | 299 ++++++++++++++++++++++++++++++++++++ src/clientTest.js | 11 ++ src/connection.js | 3 +- src/server.js | 1 + 10 files changed, 670 insertions(+), 4 deletions(-) create mode 100644 src/client.js create mode 100644 src/client/auth.js create mode 100644 src/client/authConstants.js create mode 100644 src/client/authFlow.js create mode 100644 src/client/tokens.js create mode 100644 src/clientTest.js diff --git a/.gitignore b/.gitignore index 20c7123..570a59b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ npm-debug.log -__* \ No newline at end of file +__* +data/*.js \ No newline at end of file diff --git a/package.json b/package.json index 30346b0..f0cd2f0 100644 --- a/package.json +++ b/package.json @@ -14,19 +14,23 @@ ], "license": "MIT", "dependencies": { + "@azure/msal-node": "^1.0.0-beta.6", "@babel/core": "^7.5.4", "@babel/preset-env": "^7.5.4", "@babel/preset-typescript": "^7.3.3", "@babel/register": "^7.4.4", "@jsprismarine/jsbinaryutils": "^2.1.8", - "@jsprismarine/raknet": "github:extremeheat/raknet", + "@jsprismarine/raknet": "github:extremeheat/raknet#client", + "@xboxreplay/xboxlive-auth": "^3.3.3", "aes-js": "^3.1.2", "asn1": "^0.2.4", "bn.js": "^4.11.4", + "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", "jwt-simple": "^0.5.6", "lodash.merge": "^4.4.0", + "minecraft-folder-path": "^1.1.0", "prismarine-nbt": "github:extremeheat/prismarine-nbt#le", "protodef": "github:extremeheat/node-protodef#compiler", "raknet": "git+https://github.com/mhsjlw/node-raknet.git#master", diff --git a/src/client.js b/src/client.js new file mode 100644 index 0000000..8e20275 --- /dev/null +++ b/src/client.js @@ -0,0 +1,112 @@ +const RakClient = require('@jsprismarine/raknet/client') +const { Connection } = require('./connection') +const { createDeserializer, createSerializer } = require('./transforms/serializer') +const { Encrypt } = require('./auth/encryption') +const auth = require('./client/auth') +const Options = require('./options') + +class Client extends Connection { + constructor(options) { + super() + this.options = { ...Options.defaultOptions, options } + this.serializer = createSerializer() + this.deserializer = createDeserializer() + this.validateOptions() + + Encrypt(this, null, options) + + if (options.password) { + auth.authenticatePassword(this, options) + } else { + auth.authenticateDeviceCode(this, options) + } + + this.on('session', this.connect) + } + + validateOptions() { + if (this.options.version < Options.MIN_VERSION) { + throw new Error(`Unsupported protocol version < ${Options.MIN_VERSION} : ${this.options.version}`) + } + } + + onEncapsulated = (encapsulated, inetAddr) => { + log(inetAddr.address, ': Encapsulated', encapsulated) + const buffer = encapsulated.buffer + this.handle(buffer) + } + + connect = async (sessionData) => { + console.log('Got session data', sessionData) + + if (this.raknet) return + + this.raknet = new RakClient('localhost', 19132) + await this.raknet.connect() + + this.raknet.on('connecting', () => { + // console.log(`[client] connecting to ${hostname}/${port}`) + }) + this.raknet.on('connected', (connection) => { + console.log(`[client] connected!`) + this.connection = connection + this.sendLogin() + }) + + this.raknet.on('encapsulated', this.onEncapsulated) + + this.raknet.on('raw', (buffer, inetAddr) => { + console.log('Raw packet', buffer, inetAddr) + }) + } + + sendLogin() { + + const chain = [ + this.clientChain, // JWT we generated for auth + ...this.accessToken // Mojang + Xbox JWT from auth + ] + + const encodedChain = JSON.stringify({ chain }) + const skinChain = JSON.stringify({}) + + const bodyLength = skinChain.length + encodedChain.length + 8 + + console.log('Auth chain', chain) + + this.write('login', { + protocol_version: this.options.version, + payload_size: bodyLength, + chain: encodedChain, + client_data: skinChain + }) + } + + // After sending Server to Client Handshake, this handles the client's + // Client to Server handshake response. This indicates successful encryption + onHandshake() { + // https://wiki.vg/Bedrock_Protocol#Play_Status + this.write('play_status', { status: PLAY_STATUS.LoginSuccess }) + this.emit('join') + } + + readPacket(packet) { + console.log('packet', packet) + const des = this.server.deserializer.parsePacketBuffer(packet) + console.log('->', des) + switch (des.data.name) { + case 'login': + console.log(des) + this.onLogin(des) + return + case 'client_to_server_handshake': + this.onHandshake() + default: + console.log('ignoring, unhandled') + } + this.emit(des.data.name, des.data.params) + + } +} + +module.exports = { Client } \ No newline at end of file diff --git a/src/client/auth.js b/src/client/auth.js new file mode 100644 index 0000000..696cf30 --- /dev/null +++ b/src/client/auth.js @@ -0,0 +1,104 @@ +const XboxLiveAuth = require('@xboxreplay/xboxlive-auth') +const debug = require('debug')('minecraft-protocol') +const fetch = require('node-fetch') +const authConstants = require('./authConstants') +const { MsAuthFlow } = require('./authFlow.js') + +const getFetchOptions = { + headers: { + 'Content-Type': 'application/json', + 'User-Agent': 'node-minecraft-protocol' + } +} + +/** + * Obtains Minecaft profile data using a Minecraft access token and starts the join sequence + * @param {object} client - The client passed to protocol + * @param {object} options - Client Options + * @param {string} chains - Minecraft JWTs to send to server + */ +async function postAuthenticate (client, options, chains) { + // First chain is Mojang stuff, second is Xbox profile data used by mc + const jwt = chains[1] + const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) + const xboxProfile = JSON.parse(String(payload)) + + // This profile / session here could be simplified down to where it just passes the uuid of the player to encrypt.js + // That way you could remove some lines of code. It accesses client.session.selectedProfile.id so /shrug. + // - Kashalls + const profile = { + name: xboxProfile?.extraData?.displayName || 'Player', + uuid: xboxProfile?.extraData?.identity || 'adfcf5ca-206c-404a-aec4-f59fff264c9b', //random + xuid: xboxProfile?.extraData?.XUID || 0 + } + + client.profile = profile + client.username = profile.name + client.accessToken = chains + client.emit('session', profile) + client.connect() +} + +/** + * Authenticates with Mincrosoft through user credentials, then + * with Xbox Live, Minecraft, checks entitlements and returns profile + * + * @function + * @param {object} client - The client passed to protocol + * @param {object} options - Client Options + */ +async function authenticatePassword (client, options) { + throw Error('Not implemented') +} + +/** + * Authenticates to Minecraft via device code based Microsoft auth, + * then connects to the specified server in Client Options + * + * @function + * @param {object} client - The client passed to protocol + * @param {object} options - Client Options + */ +async function authenticateDeviceCode (client, options) { + try { + const flow = new MsAuthFlow(options.username, options.profilesFolder, options.onMsaCode) + + const chain = await flow.getMinecraftToken(client.clientChain) + + await postAuthenticate(client, options, chain) + } catch (err) { + console.error(err) + client.emit('error', err) + } +} + +function checkStatus (res) { + if (res.ok) { // res.status >= 200 && res.status < 300 + return res.json() + } else { + throw Error(res.statusText) + } +} + +module.exports = { + authenticatePassword, + authenticateDeviceCode +} + +async function msaTest () { + // MsAuthFlow.resetTokenCaches() + + await authenticateDeviceCode({ + connect(...args) { + console.log('Connecting', args) + }, + emit(...e) { + console.log('Event', e) + } + }, {}) +} + +// debug with node microsoftAuth.js +if (!module.parent) { + msaTest() +} diff --git a/src/client/authConstants.js b/src/client/authConstants.js new file mode 100644 index 0000000..26e052d --- /dev/null +++ b/src/client/authConstants.js @@ -0,0 +1,4 @@ +module.exports = { + XSTSRelyingParty: 'https://multiplayer.minecraft.net/', + MinecraftAuth: 'https://multiplayer.minecraft.net/authentication' +} diff --git a/src/client/authFlow.js b/src/client/authFlow.js new file mode 100644 index 0000000..8caab8d --- /dev/null +++ b/src/client/authFlow.js @@ -0,0 +1,131 @@ +const crypto = require('crypto') +const path = require('path') +const fs = require('fs') +const debug = require('debug')('minecraft-protocol') +const mcDefaultFolderPath = require('minecraft-folder-path') +const authConstants = require('./authConstants') +const { MsaTokenManager, XboxTokenManager, MinecraftTokenManager } = require('./tokens') + +// Initialize msal +// Docs: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/request.md#public-apis-1 +const msalConfig = { + auth: { + // the minecraft client: + // clientId: "000000004C12AE6F", + clientId: '389b1b32-b5d5-43b2-bddc-84ce938d6737', // token from https://github.com/microsoft/Office365APIEditor + authority: 'https://login.microsoftonline.com/consumers', + } +} + +async function retry (methodFn, beforeRety, times) { + while (times--) { + if (times !== 0) { + try { return await methodFn() } catch (e) { debug(e) } + await beforeRety() + } else { + return await methodFn() + } + } +} + +class MsAuthFlow { + constructor (username, cacheDir, codeCallback) { + this.initTokenCaches(username, cacheDir) + this.codeCallback = codeCallback + } + + initTokenCaches (username, cacheDir) { + const hash = sha1(username).substr(0, 6) + + let cachePath = cacheDir || mcDefaultFolderPath + try { + if (!fs.existsSync(cachePath + '/nmp-cache')) { + fs.mkdirSync(cachePath + '/nmp-cache') + } + cachePath += '/nmp-cache' + } catch (e) { + console.log('Failed to open cache dir', e) + cachePath = __dirname + } + + const cachePaths = { + msa: path.join(cachePath, `./${hash}_msa-cache.json`), + xbl: path.join(cachePath, `./${hash}_xbl-cache.json`), + bed: path.join(cachePath, `./${hash}_bed-cache.json`) + } + + const scopes = ['XboxLive.signin', 'offline_access'] + this.msa = new MsaTokenManager(msalConfig, scopes, cachePaths.msa) + this.xbl = new XboxTokenManager(authConstants.XSTSRelyingParty, cachePaths.xbl) + this.mca = new MinecraftTokenManager(cachePaths.bed) + } + + static resetTokenCaches (cacheDir) { + let cachePath = cacheDir || mcDefaultFolderPath + try { + if (fs.existsSync(cachePath + '/nmp-cache')) { + cachePath += '/nmp-cache' + fs.rmdirSync(cachePath, { recursive: true }) + return true + } + } catch (e) { + console.log('Failed to clear cache dir', e) + return false + } + } + + async getMsaToken () { + if (await this.msa.verifyTokens()) { + debug('[msa] Using existing tokens') + return this.msa.getAccessToken().token + } else { + debug('[msa] No valid cached tokens, need to sign in') + const ret = await this.msa.authDeviceCode((response) => { + console.info('[msa] First time signing in. Please authenticate now:') + console.info(response.message) + if (this.codeCallback) this.codeCallback(response) + }) + + console.info(`[msa] Signed in as ${ret.account.username}`) + + debug('[msa] got auth result', ret) + return ret.accessToken + } + } + + async getXboxToken () { + if (await this.xbl.verifyTokens()) { + debug('[xbl] Using existing tokens') + return this.xbl.getCachedXstsToken().data + } else { + debug('[xbl] Need to obtain tokens') + return await retry(async () => { + const msaToken = await this.getMsaToken() + const ut = await this.xbl.getUserToken(msaToken) + const xsts = await this.xbl.getXSTSToken(ut) + return xsts + }, () => { this.msa.forceRefresh = true }, 2) + } + } + + async getMinecraftToken (publicKey) { + if (await this.mca.verifyTokens()) { + debug('[mc] Using existing tokens') + return this.mca.getCachedAccessToken().chain + } else { + if (!publicKey) throw new Error('Need to specifiy a ECDH x509 URL encoded public key') + debug('[mc] Need to obtain tokens') + return await retry(async () => { + const xsts = await this.getXboxToken() + debug('[xbl] xsts data', xsts) + return this.mca.getAccessToken(publicKey, xsts).chain + }, () => { this.xbl.forceRefresh = true }, 2) + } + } +} + +function sha1 (data) { + return crypto.createHash('sha1').update(data || '', 'binary').digest('hex') +} + +module.exports = { MsAuthFlow } diff --git a/src/client/tokens.js b/src/client/tokens.js new file mode 100644 index 0000000..aeae166 --- /dev/null +++ b/src/client/tokens.js @@ -0,0 +1,299 @@ +const msal = require('@azure/msal-node') +const XboxLiveAuth = require('@xboxreplay/xboxlive-auth') +const debug = require('debug')('minecraft-protocol') +const fs = require('fs') +const path = require('path') +const fetch = require('node-fetch') +const authConstants = require('./authConstants') + +// Manages Microsoft account tokens +class MsaTokenManager { + constructor(msalConfig, scopes, cacheLocation) { + this.msaClientId = msalConfig.auth.clientId + this.scopes = scopes + this.cacheLocation = cacheLocation || path.join(__dirname, './msa-cache.json') + + try { + this.msaCache = require(this.cacheLocation) + } catch (e) { + this.msaCache = {} + fs.writeFileSync(this.cacheLocation, JSON.stringify(this.msaCache)) + } + + const beforeCacheAccess = async (cacheContext) => { + cacheContext.tokenCache.deserialize(await fs.promises.readFile(this.cacheLocation, 'utf-8')) + } + + const afterCacheAccess = async (cacheContext) => { + if (cacheContext.cacheHasChanged) { + await fs.promises.writeFile(this.cacheLocation, cacheContext.tokenCache.serialize()) + } + } + + const cachePlugin = { + beforeCacheAccess, + afterCacheAccess + } + + msalConfig.cache = { + cachePlugin + } + this.msalApp = new msal.PublicClientApplication(msalConfig) + this.msalConfig = msalConfig + } + + getUsers() { + const accounts = this.msaCache.Account + const users = [] + if (!accounts) return users + for (const account of Object.values(accounts)) { + users.push(account) + } + return users + } + + getAccessToken() { + const tokens = this.msaCache.AccessToken + if (!tokens) return + const account = Object.values(tokens).filter(t => t.client_id === this.msaClientId)[0] + if (!account) { + debug('[msa] No valid access token found', tokens) + return + } + const until = new Date(account.expires_on * 1000) - Date.now() + const valid = until > 1000 + return { valid, until: until, token: account.secret } + } + + getRefreshToken() { + const tokens = this.msaCache.RefreshToken + if (!tokens) return + const account = Object.values(tokens).filter(t => t.client_id === this.msaClientId)[0] + if (!account) { + debug('[msa] No valid refresh token found', tokens) + return + } + return { token: account.secret } + } + + async refreshTokens() { + const rtoken = this.getRefreshToken() + if (!rtoken) { + throw new Error('Cannot refresh without refresh token') + } + const refreshTokenRequest = { + refreshToken: rtoken.token, + scopes: this.scopes + } + + return new Promise((resolve, reject) => { + this.msalApp.acquireTokenByRefreshToken(refreshTokenRequest).then((response) => { + debug('[msa] refreshed token', JSON.stringify(response)) + resolve(response) + }).catch((error) => { + debug('[msa] failed to refresh', JSON.stringify(error)) + reject(error) + }) + }) + } + + async verifyTokens() { + const at = this.getAccessToken() + const rt = this.getRefreshToken() + if (!at || !rt || this.forceRefresh) { + return false + } + debug('[msa] have at, rt', at, rt) + if (at.valid && rt) { + return true + } else { + try { + await this.refreshTokens() + return true + } catch (e) { + return false + } + } + } + + // Authenticate with device_code flow + async authDeviceCode(dataCallback) { + const deviceCodeRequest = { + deviceCodeCallback: (resp) => { + debug('[msa] device_code response: ', resp) + dataCallback(resp) + }, + scopes: this.scopes + } + + return new Promise((resolve, reject) => { + this.msalApp.acquireTokenByDeviceCode(deviceCodeRequest).then((response) => { + debug('[msa] device_code resp', JSON.stringify(response)) + if (!this.msaCache.Account) this.msaCache.Account = { '': response.account } + resolve(response) + }).catch((error) => { + console.warn('[msa] Error getting device code') + console.debug(JSON.stringify(error)) + reject(error) + }) + }) + } +} + +// Manages Xbox Live tokens for xboxlive.com +class XboxTokenManager { + constructor(relyingParty, cacheLocation) { + this.relyingParty = relyingParty + this.cacheLocation = cacheLocation || path.join(__dirname, './xbl-cache.json') + try { + this.cache = require(this.cacheLocation) + } catch (e) { + this.cache = {} + } + } + + getCachedUserToken() { + const token = this.cache.userToken + if (!token) return + const until = new Date(token.NotAfter) + const dn = Date.now() + const remainingMs = until - dn + const valid = remainingMs > 1000 + return { valid, token: token.Token, data: token } + } + + getCachedXstsToken() { + const token = this.cache.xstsToken + if (!token) return + const until = new Date(token.expiresOn) + const dn = Date.now() + const remainingMs = until - dn + const valid = remainingMs > 1000 + return { valid, token: token.XSTSToken, data: token } + } + + setCachedUserToken(data) { + this.cache.userToken = data + fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) + } + + setCachedXstsToken(data) { + this.cache.xstsToken = data + fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) + } + + async verifyTokens() { + const ut = this.getCachedUserToken() + const xt = this.getCachedXstsToken() + if (!ut || !xt || this.forceRefresh) { + return false + } + debug('[xbl] have user, xsts', ut, xt) + if (ut.valid && xt.valid) { + return true + } else if (ut.valid && !xt.valid) { + try { + await this.getXSTSToken(ut.data) + return true + } catch (e) { + return false + } + } + return false + } + + async getUserToken(msaAccessToken) { + debug('[xbl] obtaining xbox token with ms token', msaAccessToken) + if (!msaAccessToken.startsWith('d=')) { msaAccessToken = 'd=' + msaAccessToken } + const xblUserToken = await XboxLiveAuth.exchangeRpsTicketForUserToken(msaAccessToken) + this.setCachedUserToken(xblUserToken) + debug('[xbl] user token:', xblUserToken) + return xblUserToken + } + + async getXSTSToken(xblUserToken) { + debug('[xbl] obtaining xsts token with xbox user token', xblUserToken.Token) + const xsts = await XboxLiveAuth.exchangeUserTokenForXSTSIdentity( + xblUserToken.Token, { XSTSRelyingParty: this.relyingParty, raw: false } + ) + this.setCachedXstsToken(xsts) + debug('[xbl] xsts', xsts) + return xsts + } +} + +// Manages Minecraft tokens for sessionserver.mojang.com +class MinecraftTokenManager { + constructor(clientPublicKey, cacheLocation) { + this.clientPublicKey = clientPublicKey + this.cacheLocation = cacheLocation || path.join(__dirname, './bed-cache.json') + try { + this.cache = require(this.cacheLocation) + } catch (e) { + this.cache = {} + } + } + + getCachedAccessToken() { + const token = this.cache.mca + debug('[mc] token cache', this.cache) + if (!token) return + console.log('TOKEN', token) + const jwt = token.chain[0] + const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) + + const body = JSON.parse(String(payload)) + const expires = new Date(body.exp * 1000) + const remainingMs = expires - Date.now() + const valid = remainingMs > 1000 + return { valid, until: expires, chain: token.chain } + } + + setCachedAccessToken(data) { + data.obtainedOn = Date.now() + this.cache.mca = data + fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) + } + + async verifyTokens() { + const at = this.getCachedAccessToken() + if (!at || this.forceRefresh) { + return false + } + debug('[mc] have user access token', at) + if (at.valid) { + return true + } + return false + } + + async getAccessToken(clientPublicKey, xsts) { + debug('[mc] authing to minecraft', xsts) + const getFetchOptions = { + headers: { + 'Content-Type': 'application/json', + 'User-Agent': 'node-minecraft-protocol', + 'Authorization': `XBL3.0 x=${xsts.userHash};${xsts.XSTSToken}` + } + } + const MineServicesResponse = await fetch(authConstants.MinecraftAuth, { + method: 'post', + ...getFetchOptions, + body: JSON.stringify({ identityPublicKey: clientPublicKey }) + }).then(checkStatus) + + debug('[mc] mc auth response', MineServicesResponse) + this.setCachedAccessToken(MineServicesResponse) + return MineServicesResponse + } +} + +function checkStatus(res) { + if (res.ok) { // res.status >= 200 && res.status < 300 + return res.json() + } else { + throw Error(res.statusText) + } +} + +module.exports = { MsaTokenManager, XboxTokenManager, MinecraftTokenManager } diff --git a/src/clientTest.js b/src/clientTest.js new file mode 100644 index 0000000..4c4eb43 --- /dev/null +++ b/src/clientTest.js @@ -0,0 +1,11 @@ +process.env.DEBUG = 'minecraft-protocol raknet' +const { Client } = require('./client') + + +async function test() { + const client = new Client({ + + }) +} + +test() \ No newline at end of file diff --git a/src/connection.js b/src/connection.js index 9830b57..3712a0f 100644 --- a/src/connection.js +++ b/src/connection.js @@ -16,7 +16,7 @@ class Connection extends EventEmitter { write(name, params) { // TODO: Batch console.log('Need to encode', name, params) const batch = new BatchPacket() - const packet = this.server.serializer.createPacketBuffer({ name, params }) + const packet = this.serializer.createPacketBuffer({ name, params }) batch.addEncodedPacket(packet) if (this.encryptionEnabled) { @@ -86,7 +86,6 @@ class Connection extends EventEmitter { handle(buffer) { // handle encapsulated if (buffer[0] == 0xfe) { // wrapper - if (this.encryptionEnabled) { // console.log('READING ENCRYPTED PACKET', buffer) this.decrypt(buffer.slice(1)) diff --git a/src/server.js b/src/server.js index 8223f4f..7db207d 100644 --- a/src/server.js +++ b/src/server.js @@ -12,6 +12,7 @@ class Player extends Connection { constructor(server, connection, options) { super() this.server = server + this.serializer = server.serializer this.connection = connection Encrypt(this, server, options) } From 233f0d33a660153f3005e6b2b1a7bb061f60ce37 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 13 Feb 2021 18:42:43 -0500 Subject: [PATCH 093/458] workingish client connection to server Joining a vanilla server is still broken (related to encryption), but minet connects --- data/new/proto.yml | 14 ++-- data/new/types.yaml | 25 +++--- data/newproto.json | 51 ++++++------- src/auth/encryption.js | 113 ++++++++++++++++++++++++---- src/client.js | 42 +++++++---- src/client/auth.js | 4 +- src/client/authFlow.js | 7 +- src/client/tokens.js | 2 +- src/clientTest.js | 11 ++- src/connection.js | 4 +- src/datatypes/compiler-minecraft.js | 6 +- src/serverTest.js | 2 +- src/transforms/encryption.js | 53 ++++++++++--- 13 files changed, 231 insertions(+), 103 deletions(-) diff --git a/data/new/proto.yml b/data/new/proto.yml index 5bf4498..a3fe763 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -197,13 +197,13 @@ packet_start_game: entity_id: zigzag64 # The runtime ID of the player. The runtime ID is unique for each world session, # and entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint + runtime_entity_id: varint64 player_gamemode: zigzag32 # The spawn position of the player in the world. In servers this is often the same as the # world's spawn position found below. spawn: vec3f # The pitch and yaw of the player - rotation: vec3f + rotation: vec2f # The seed used to generate the world. Unlike in Java edition, the seed is a 32bit Integer here. seed: zigzag32 biome_type: li16 @@ -302,8 +302,8 @@ packet_start_game: # The version of the game from which Vanilla features will be used. # The exact function of this field isn't clear. game_version: string - limited_world_width_: li32 - limited_world_length_: li32 + limited_world_width: li32 + limited_world_length: li32 is_new_nether_: bool experimental_gameplay_override: bool # A base64 encoded world ID that is used to identify the world. @@ -335,7 +335,7 @@ packet_start_game: ## This is not sent anymore in protocol versions > 419 (Bedrock Edition v1.16.100) ## A list of all blocks registered on the server. - ## block_palette: BlockPalette + block_palette: BlockPalette # A list of all items with their legacy IDs which are available in the game. # Failing to send any of the items that are in the game will crash mobile clients. itemstates: Itemstates @@ -525,9 +525,9 @@ packet_mob_effect: packet_update_attributes: !id: 0x1d !bound: server - runtime_entity_id: varint + runtime_entity_id: varint64 attributes: PlayerAttributes - tick: varint + tick: varint64 packet_inventory_transaction: !id: 0x1e diff --git a/data/new/types.yaml b/data/new/types.yaml index 2168098..f53f36d 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -3,7 +3,7 @@ BehaviourPackInfos: []li16 uuid: string version: string - length: lu64 + size: lu64 content_key: string sub_pack_name: string content_identity: string @@ -12,7 +12,7 @@ BehaviourPackInfos: []li16 TexturePackInfos: []li16 uuid: string version: string - length: lu64 + size: lu64 content_key: string sub_pack_name: string content_identity: string @@ -27,13 +27,13 @@ ResourcePackIdVersions: []varint # The subpack name of the resource pack. name: string -ResourcePackIds: string[]varint +ResourcePackIds: string[]li16 Experiment: name: string enabled: bool -Experiments: Experiment[]varint +Experiments: Experiment[]li32 GameRule: name: string @@ -43,7 +43,7 @@ GameRule: 3: float value: type? if bool: bool - if int: varint + if int: zigzag32 if float: lf32 GameRules: GameRule[]varint @@ -150,10 +150,10 @@ BlockCoordinates: # mojang... z: zigzag32 PlayerAttributes: []varint - min_value: lf32 - max_value: lf32 - current_value: lf32 - default_value: lf32 + min: lf32 + max: lf32 + current: lf32 + default: lf32 name: string Transaction: @@ -190,7 +190,7 @@ Transaction: slot: varint old_item: Item new_item: Item - new_item_stack_id: has_network_ids? + new_item_stack_id: ../has_network_ids? if true: zigzag32 default: void transaction_data: transaction_type? @@ -242,7 +242,7 @@ PotionContainerChangeRecipes: []varint output_item_id: zigzag32 Recipes: []varint - type: varint => + type: zigzag32 => '0': 'shapeless' #'ENTRY_SHAPELESS', '1': 'shaped' #'ENTRY_SHAPED', '2': 'furnace' # 'ENTRY_FURNACE', @@ -341,9 +341,6 @@ PlayerRecords: is_host: bool if remove: uuid: uuid - uuid: type? - if add: uuid - default: void verified: bool[]$records_count ScoreEntries: diff --git a/data/newproto.json b/data/newproto.json index e520a62..f2a320f 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -25,7 +25,7 @@ "type": "string" }, { - "name": "length", + "name": "size", "type": "lu64" }, { @@ -64,7 +64,7 @@ "type": "string" }, { - "name": "length", + "name": "size", "type": "lu64" }, { @@ -117,7 +117,7 @@ "ResourcePackIds": [ "array", { - "countType": "varint", + "countType": "li16", "type": "string" } ], @@ -137,7 +137,7 @@ "Experiments": [ "array", { - "countType": "varint", + "countType": "li32", "type": "Experiment" } ], @@ -170,7 +170,7 @@ "compareTo": "type", "fields": { "bool": "bool", - "int": "varint", + "int": "zigzag32", "float": "lf32" }, "default": "void" @@ -580,19 +580,19 @@ "container", [ { - "name": "min_value", + "name": "min", "type": "lf32" }, { - "name": "max_value", + "name": "max", "type": "lf32" }, { - "name": "current_value", + "name": "current", "type": "lf32" }, { - "name": "default_value", + "name": "default", "type": "lf32" }, { @@ -775,7 +775,7 @@ "type": [ "switch", { - "compareTo": "has_network_ids", + "compareTo": "../has_network_ids", "fields": { "true": "zigzag32" }, @@ -1010,7 +1010,7 @@ "type": [ "mapper", { - "type": "varint", + "type": "zigzag32", "mappings": { "0": "shapeless", "1": "shaped", @@ -1449,19 +1449,6 @@ } ] }, - { - "name": "uuid", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": "uuid" - }, - "default": "void" - } - ] - }, { "name": "verified", "type": [ @@ -2671,7 +2658,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "player_gamemode", @@ -2683,7 +2670,7 @@ }, { "name": "rotation", - "type": "vec3f" + "type": "vec2f" }, { "name": "seed", @@ -2834,11 +2821,11 @@ "type": "string" }, { - "name": "limited_world_width_", + "name": "limited_world_width", "type": "li32" }, { - "name": "limited_world_length_", + "name": "limited_world_length", "type": "li32" }, { @@ -2887,6 +2874,10 @@ "name": "enchantment_seed", "type": "zigzag32" }, + { + "name": "block_palette", + "type": "BlockPalette" + }, { "name": "itemstates", "type": "Itemstates" @@ -3390,7 +3381,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "attributes", @@ -3398,7 +3389,7 @@ }, { "name": "tick", - "type": "varint" + "type": "varint64" } ] ], diff --git a/src/auth/encryption.js b/src/auth/encryption.js index f32bc69..956eede 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -6,11 +6,11 @@ const ec_pem = require('ec-pem') const SALT = '🧂' const curve = 'secp384r1' -function Encrypt(client, options) { +function Encrypt(client, server, options) { client.ecdhKeyPair = crypto.createECDH(curve) client.ecdhKeyPair.generateKeys() + client.clientX509 = writeX509PublicKey(client.ecdhKeyPair.getPublicKey()) - createClientChain(client) function startClientboundEncryption(publicKey) { console.warn('[encrypt] Pub key base64: ', publicKey) @@ -31,9 +31,11 @@ function Encrypt(client, options) { const secretHash = crypto.createHash('sha256') secretHash.update(SALT) secretHash.update(client.sharedSecret) + console.log('---- SHARED SECRET', client.sharedSecret) + client.secretKeyBytes = secretHash.digest() - + console.log('Hash', client.secretKeyBytes) const x509 = writeX509PublicKey(alice.getPublicKey()) const token = JWT.sign({ salt: toBase64(SALT), @@ -51,30 +53,109 @@ function Encrypt(client, options) { client.startEncryption(initial) } - function startServerboundEncryption() { + function startServerboundEncryption(token) { + console.warn('Starting serverbound encryption', token) + const jwt = token?.token + if (!jwt) { + // TODO: allow connecting to servers without encryption + throw Error('Server did not return a valid JWT, cannot start encryption!') + } + // TODO: Should we do some JWT signature validation here? Seems pointless + const alice = client.ecdhKeyPair + const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) + const head = JSON.parse(String(header)) + const body = JSON.parse(String(payload)) + const serverPublicKey = readX509PublicKey(head.x5u) + client.sharedSecret = alice.computeSecret(serverPublicKey) + console.log('------ SHARED SECRET', client.sharedSecret) + const salt = Buffer.from(body.salt, 'base64') + + const secretHash = crypto.createHash('sha256') + secretHash.update(salt) + secretHash.update(client.sharedSecret) + + client.secretKeyBytes = secretHash.digest() + console.log('Hash', client.secretKeyBytes) + const initial = client.secretKeyBytes.slice(0, 16) + client.startEncryption(initial) + + // It works! First encrypted packet :) + client.write('client_to_server_handshake', {}) } client.on('server.client_handshake', startClientboundEncryption) -} -function createClientChain(client) { - const alice = client.ecdhKeyPair - const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 - const alicePEMPrivate = alicePEM.encodePrivateKey() - const x509 = writeX509PublicKey(alice.getPublicKey()) + client.on('client.server_handshake', startServerboundEncryption) - const token = JWT.sign({ - salt: toBase64(SALT), - signedToken: alice.getPublicKey('base64') - }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } }) + client.createClientChain = (mojangKey) => { + mojangKey = mojangKey || require('./constants').PUBLIC_KEY + const alice = client.ecdhKeyPair + const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 + const alicePEMPrivate = alicePEM.encodePrivateKey() - client.clientChain = token + const token = JWT.sign({ + identityPublicKey: mojangKey, + certificateAuthority: true + }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + + client.clientIdentityChain = token + client.createClientUserChain(alicePEMPrivate) + } + + client.createClientUserChain = (privateKey) => { + let payload = { + ServerAddress: options.hostname, + ThirdPartyName: client.profile.name, + DeviceOS: client.session?.deviceOS || 1, + GameVersion: options.version || '1.16.201', + ClientRandomId: Date.now(), // TODO make biggeer + DeviceId: '2099de18-429a-465a-a49b-fc4710a17bb3', // TODO random + LanguageCode: 'en_GB', // TODO locale + AnimatedImageData: [], + PersonaPieces: [], + PieceTintColours: [], + SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343701', + SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', + SkinData: 'AAAAAA==', + SkinResourcePatch: 'ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfMTI4eDEyOCIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfMTI4eDEyOF9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICJhbmltYXRlZF9mYWNlIiA6ICJnZW9tZXRyeS5hbmltYXRlZF9mYWNlX3BlcnNvbmEtZTE5OTY3MmE4YzFhODdlMC0wIiwKICAgICAgImRlZmF1bHQiIDogImdlb21ldHJ5LnBlcnNvbmFfZTE5OTY3MmE4YzFhODdlMC0wIgogICB9Cn0K', + SkinGeometryData: require('./geom'), + "SkinImageHeight": 1, + "SkinImageWidth": 1, + "ArmSize": "wide", + "CapeData": "", + "CapeId": "", + "CapeImageHeight": 0, + "CapeImageWidth": 0, + "CapeOnClassicSkin": false, + PlatformOfflineId: '', + PlatformOnlineId: '', //chat + // a bunch of meaningless junk + CurrentInputMode: 1, + DefaultInputMode: 1, + DeviceModel: '', + GuiScale: -1, + UIProfile: 0, + TenantId: '', + PremiumSkin: false, + PersonaSkin: false, + PieceTintColors: [], + SkinAnimationData: '', + ThirdPartyNameOnly: false, + "SkinColor": "#ffffcd96", + } + payload = require('./logPack.json') + const customPayload = options.userData || {} + payload = { ...payload, ...customPayload } + + client.clientUserChain = JWT.sign(payload, privateKey, + { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + } } function toBase64(string) { return Buffer.from(string).toString('base64') -} +} function readX509PublicKey(key) { var reader = new Ber.Reader(Buffer.from(key, "base64")); diff --git a/src/client.js b/src/client.js index 8e20275..acba7a6 100644 --- a/src/client.js +++ b/src/client.js @@ -4,6 +4,9 @@ const { createDeserializer, createSerializer } = require('./transforms/serialize const { Encrypt } = require('./auth/encryption') const auth = require('./client/auth') const Options = require('./options') +const fs = require('fs') + +const log = console.log class Client extends Connection { constructor(options) { @@ -41,7 +44,7 @@ class Client extends Connection { if (this.raknet) return - this.raknet = new RakClient('localhost', 19132) + this.raknet = new RakClient('127.0.0.1', 19132) await this.raknet.connect() this.raknet.on('connecting', () => { @@ -61,16 +64,17 @@ class Client extends Connection { } sendLogin() { + this.createClientChain() const chain = [ - this.clientChain, // JWT we generated for auth + this.clientIdentityChain, // JWT we generated for auth ...this.accessToken // Mojang + Xbox JWT from auth ] const encodedChain = JSON.stringify({ chain }) const skinChain = JSON.stringify({}) - const bodyLength = skinChain.length + encodedChain.length + 8 + const bodyLength = this.clientUserChain.length + encodedChain.length + 8 console.log('Auth chain', chain) @@ -78,7 +82,7 @@ class Client extends Connection { protocol_version: this.options.version, payload_size: bodyLength, chain: encodedChain, - client_data: skinChain + client_data: this.clientUserChain }) } @@ -90,19 +94,31 @@ class Client extends Connection { this.emit('join') } + onDisconnectRequest(packet) { + // We're talking over UDP, so there is no connection to close, instead + // we stop communicating with the server + console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) + process.exit(1) + } + readPacket(packet) { console.log('packet', packet) - const des = this.server.deserializer.parsePacketBuffer(packet) - console.log('->', des) + const des = this.deserializer.parsePacketBuffer(packet) + console.info('->', des) switch (des.data.name) { - case 'login': - console.log(des) - this.onLogin(des) - return - case 'client_to_server_handshake': - this.onHandshake() + case 'server_to_client_handshake': + this.emit('client.server_handshake', des.data.params) + break + case 'disconnect': // Client kicked + this.onDisconnectRequest(des.data.params) + break + case 'crafting_data': + fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k,v) => typeof v == 'bigint' ? v.toString() : v)) + break + case 'start_game': + fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k,v) => typeof v == 'bigint' ? v.toString() : v)) default: - console.log('ignoring, unhandled') + console.log('Sending to listeners') } this.emit(des.data.name, des.data.params) diff --git a/src/client/auth.js b/src/client/auth.js index 696cf30..bb83897 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -63,8 +63,8 @@ async function authenticateDeviceCode (client, options) { try { const flow = new MsAuthFlow(options.username, options.profilesFolder, options.onMsaCode) - const chain = await flow.getMinecraftToken(client.clientChain) - + const chain = await flow.getMinecraftToken(client.clientX509) + // console.log('Chain', chain) await postAuthenticate(client, options, chain) } catch (err) { console.error(err) diff --git a/src/client/authFlow.js b/src/client/authFlow.js index 8caab8d..1c0325f 100644 --- a/src/client/authFlow.js +++ b/src/client/authFlow.js @@ -109,7 +109,9 @@ class MsAuthFlow { } async getMinecraftToken (publicKey) { - if (await this.mca.verifyTokens()) { + // TODO: Fix cache, in order to do cache we also need to cache the ECDH keys so disable it + // is this even a good idea to cache? + if (await this.mca.verifyTokens() && false) { debug('[mc] Using existing tokens') return this.mca.getCachedAccessToken().chain } else { @@ -118,7 +120,8 @@ class MsAuthFlow { return await retry(async () => { const xsts = await this.getXboxToken() debug('[xbl] xsts data', xsts) - return this.mca.getAccessToken(publicKey, xsts).chain + const token = await this.mca.getAccessToken(publicKey, xsts) + return token.chain }, () => { this.xbl.forceRefresh = true }, 2) } } diff --git a/src/client/tokens.js b/src/client/tokens.js index aeae166..1959211 100644 --- a/src/client/tokens.js +++ b/src/client/tokens.js @@ -268,7 +268,7 @@ class MinecraftTokenManager { } async getAccessToken(clientPublicKey, xsts) { - debug('[mc] authing to minecraft', xsts) + debug('[mc] authing to minecraft', clientPublicKey, xsts) const getFetchOptions = { headers: { 'Content-Type': 'application/json', diff --git a/src/clientTest.js b/src/clientTest.js index 4c4eb43..d0ba45f 100644 --- a/src/clientTest.js +++ b/src/clientTest.js @@ -1,10 +1,19 @@ process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('./client') +// console.log = () => async function test() { const client = new Client({ - + hostname: '127.0.0.1', + port: 19132 + }) + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) }) } diff --git a/src/connection.js b/src/connection.js index 3712a0f..e6eef5a 100644 --- a/src/connection.js +++ b/src/connection.js @@ -8,7 +8,7 @@ const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_p class Connection extends EventEmitter { startEncryption(iv) { this.encryptionEnabled = true - + console.log('Started encryption', this.sharedSecret, iv) this.decrypt = cipher.createDecryptor(this, iv) this.encrypt = cipher.createEncryptor(this, iv) } @@ -74,7 +74,7 @@ class Connection extends EventEmitter { } onDecryptedPacket = (buf) => { - console.log('Decrypted', buf) + console.log('🟢 Decrypted', buf) const stream = new BinaryStream(buf) const packets = BatchPacket.getPackets(stream) diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index f8fa767..7dc6ea4 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -3,7 +3,7 @@ const minecraft = require('./minecraft') module.exports = { Read: { - UUID: ['native', (buffer, offset) => { + uuid: ['native', (buffer, offset) => { return { value: UUID.stringify(buffer.slice(offset, 16 + offset)), size: 16 @@ -18,7 +18,7 @@ module.exports = { nbt: ['native', minecraft.nbt[0]] }, Write: { - UUID: ['native', (value, buffer, offset) => { + uuid: ['native', (value, buffer, offset) => { const buf = UUID.parse(value) buf.copy(buffer, offset) return offset + 16 @@ -30,7 +30,7 @@ module.exports = { nbt: ['native', minecraft.nbt[1]] }, SizeOf: { - UUID: ['native', 16], + uuid: ['native', 16], restBuffer: ['native', (value) => { return value.length }], diff --git a/src/serverTest.js b/src/serverTest.js index a02ac35..0d733f6 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -6,7 +6,7 @@ const fs = require('fs') let server = new Server({ }) -server.create('0.0.0.0', 19130) +server.create('0.0.0.0', 19132) let ran = false diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 7aaee6b..f9cf293 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -119,28 +119,46 @@ function createDecryptor(client, iv) { const verifyChecksum = new Transform({ // verify checksum transform(chunk, encoding, cb) { - console.log('Decryptor: checking checksum', chunk) + console.log('Decryptor: checking checksum', client.receiveCounter, chunk) const packet = chunk.slice(0, chunk.length - 8); const checksum = chunk.slice(chunk.length - 8); const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) + // console.log(computedCheckSum2, computedCheckSum3) console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') client.receiveCounter++ - if (checksum.toString("hex") == computedCheckSum.toString("hex")) { + // if (checksum.toString("hex") == computedCheckSum.toString("hex")) { this.push(packet) - } else { - throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) - } + // console.log('🔵 Decriphered', checksum) + + // const inflated = Zlib.inflateRawSync(chunk, { + // chunkSize: 1024 * 1024 * 2 + // }) + // console.log('🔵 Inflated') + // client.onDecryptedPacket(inflated) + // } else { + // // console.log('🔴 Not OK') + // throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) + // } cb() } }) const inflator = new Transform({ transform(chunk, enc, cb) { - Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buf) => { - if (err) throw err - this.push(buf) - cb() + console.log('🔵 Inflating') + const inflated = Zlib.inflateRawSync(chunk, { + chunkSize: 1024 * 1024 * 2 }) + console.log('🔵 Inflated') + this.push(inflated) + cb() + + // Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buf) => { + // console.log('🔵 INF') + // if (err) throw err + // this.push(buf) + // cb() + // }) } }) @@ -148,11 +166,24 @@ function createDecryptor(client, iv) { .pipe(inflator) // .pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 })) .on('data', (...args) => client.onDecryptedPacket(...args)) - .on('end', () => console.log('Decryptor: finish pipeline')) + // .on('end', () => console.log('Decryptor: finish pipeline')) + // Not sure why, but sending two packets to the decryption pipe before + // the other is completed breaks the checksum check. + // TODO: Refactor the logic here to be async so we can await a promise + // queue + let decQ = [] + setInterval(() => { + if (decQ.length) { + let pak = decQ.shift() + console.log('🟡 DECRYPTING', pak) + client.decipher.write(pak) + } + }, 500) return (blob) => { - client.decipher.write(blob) + decQ.push(blob) + // client.decipher.write(blob) } } From b2a8d6fa2d33f1bbe44491800297527181f681a8 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 13 Feb 2021 21:04:22 -0500 Subject: [PATCH 094/458] rebasing --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a3edda2..037985b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ -pocket-minecraft-protocol +pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/PrismarineJS/pocket-minecraft-protocol](https://badges.gitter.im/PrismarineJS/pocket-minecraft-protocol.svg)](https://gitter.im/PrismarineJS/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ========================= -[![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) -[![Join the chat at https://gitter.im/mhsjlw/pocket-minecraft-protocol](https://badges.gitter.im/mhsjlw/pocket-minecraft-protocol.svg)](https://gitter.im/mhsjlw/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +> Note: **THIS IS NOT USABLE SOFTWARE!** If you're looking for experimental encryption or current support, please see the [1.1](https://github.com/PrismarineJS/pocket-minecraft-protocol/tree/1.1)+ branch -Parse and serialize Minecraft PE packets (use [this](https://github.com/filfat/MiNET-protocol-converter) to generate the protocol data). +Parse and serialize Minecraft: Pocket Edition packets ## Features @@ -16,7 +15,7 @@ Parse and serialize Minecraft PE packets (use [this](https://github.com/filfat/M ## Installation Simply run - npm install pocket-minecraft-protcol + npm install pocket-minecraft-protocol Then view our `examples` for inspiration! From 7b00432c7bcf2535f7700feb760d7877ad5d47bc Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 16 Feb 2021 03:24:25 -0500 Subject: [PATCH 095/458] protocol updates --- data/new/proto.yml | 513 ++++++++++++++++++++++++-------- data/new/types.yaml | 192 ++++++++++-- data/newproto.json | 703 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 1218 insertions(+), 190 deletions(-) diff --git a/data/new/proto.yml b/data/new/proto.yml index a3fe763..9727a76 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -40,7 +40,7 @@ nbt: native packet_login: !id: 0x01 - !bound: client + !bound: server protocol_version: i32 # The combined size of the `chain` and `client_data` payload_size: varint @@ -52,7 +52,7 @@ packet_login: packet_play_status: !id: 0x02 - !bound: server + !bound: client status: i32 => # Sent after Login has been successfully decoded and the player has logged in 0: login_success @@ -74,7 +74,7 @@ packet_play_status: packet_server_to_client_handshake: !id: 0x03 - !bound: server + !bound: client # Contains the salt to complete the Diffie-Hellman key exchange token: string @@ -85,12 +85,12 @@ packet_server_to_client_handshake: # It has no fields. packet_client_to_server_handshake: !id: 0x04 - !bound: client + !bound: server # Sent by the server to disconnect a client. packet_disconnect: !id: 0x05 - !bound: server + !bound: client # Specifies if the disconnection screen should be hidden when the client is disconnected, # meaning it will be sent directly to the main menu. hide_disconnect_reason: bool @@ -100,7 +100,7 @@ packet_disconnect: packet_resource_packs_info: !id: 0x06 - !bound: server + !bound: client # If the resource pack requires the client accept it. must_accept: bool # If scripting is enabled. @@ -114,7 +114,7 @@ packet_resource_packs_info: packet_resource_pack_stack: !id: 0x07 - !bound: server + !bound: client # If the resource pack must be accepted for the player to join the server. must_accept: bool # [inline] @@ -127,7 +127,7 @@ packet_resource_pack_stack: packet_resource_pack_client_response: !id: 0x08 - !bound: client + !bound: server response_status: u8 => 0: none 1: refused @@ -144,6 +144,8 @@ packet_resource_pack_client_response: packet_text: !id: 0x09 !bound: both + # TextType is the type of the text sent. When a client sends this to the server, it should always be + # TextTypeChat. If the server sends it, it may be one of the other text types above. type: u8 => 0: raw 1: chat @@ -162,7 +164,7 @@ packet_text: needs_translation: bool _: type? if chat or whisper or announcement: - sourceName: string + source_name: string if raw or tip or system or json_whisper or json: message: string if translation or popup or jukebox_popup: @@ -182,7 +184,7 @@ packet_text: # of synchronizing time between server and client. packet_set_time: !id: 0x0a - !bound: server + !bound: client # Time is the current time. The time is not limited to 24000 (time of day), but continues # progressing after that. time: zigzag32 @@ -190,7 +192,7 @@ packet_set_time: # Sent by the server to send information about the world the player will be spawned in. packet_start_game: !id: 0x0b - !bound: server + !bound: client # The unique ID of the player. The unique ID is a value that remains consistent across # different sessions of the same world, but most unofficial servers simply fill the # runtime ID of the entity out for this field. @@ -344,9 +346,10 @@ packet_start_game: multiplayer_correlation_id: string server_authoritative_inventory: bool + packet_add_player: !id: 0x0c - !bound: server + !bound: client # UUID is the UUID of the player. It is the same UUID that the client sent in the # Login packet at the start of the session. A player with this UUID must exist # in the player list (built up using the Player List packet) for it to show up in-game. @@ -388,7 +391,7 @@ packet_add_player: packet_add_entity: !id: 0x0d - !bound: server + !bound: client entity_id_self: zigzag64 runtime_entity_id: varint entity_type: string @@ -407,12 +410,12 @@ packet_add_entity: packet_remove_entity: !id: 0x0e - !bound: server + !bound: client entity_id_self: zigzag64 packet_add_item_entity: !id: 0x0f - !bound: server + !bound: client entity_id_self: zigzag64 runtime_entity_id: varint item: Item @@ -427,7 +430,7 @@ packet_add_item_entity: packet_take_item_entity: !id: 0x11 - !bound: server + !bound: client runtime_entity_id: varint target: varint @@ -460,7 +463,7 @@ packet_rider_jump: packet_update_block: !id: 0x15 - !bound: server + !bound: client coordinates: BlockCoordinates block_runtime_id: varint block_priority: varint @@ -468,7 +471,7 @@ packet_update_block: packet_add_painting: !id: 0x16 - !bound: server + !bound: client entity_id_self: zigzag64 runtime_entity_id: varint coordinates: BlockCoordinates @@ -493,28 +496,153 @@ packet_level_sound_event_old: packet_level_event: !id: 0x19 - !bound: server - event_id: zigzag32 + !bound: client + event: zigzag32 => + 1000: sound_click + 1001: sound_click_fail + 1002: sound_shoot + 1003: sound_door + 1004: sound_fizz + 1005: sound_ignite + 1007: sound_ghast + 1008: sound_ghast_shoot + 1009: sound_blaze_shoot + 1010: sound_door_bump + 1012: sound_door_crash + 1018: sound_enderman_teleport + 1020: sound_anvil_break + 1021: sound_anvil_use + 1022: sound_anvil_fall + 1030: sound_pop + 1032: sound_portal + 1040: sound_itemframe_add_item + 1041: sound_itemframe_remove + 1042: sound_itemframe_place + 1043: sound_itemframe_remove_item + 1044: sound_itemframe_rotate_item + 1050: sound_camera + 1051: sound_orb + 1052: sound_totem + 1060: sound_armor_stand_break + 1061: sound_armor_stand_hit + 1062: sound_armor_stand_fall + 1063: sound_armor_stand_place + 2000: particle_shoot #TODO: check 2000-2017 + 2001: particle_destroy + 2002: particle_splash + 2003: particle_eye_despawn + 2004: particle_spawn + 2006: guardian_curse + 2008: particle_block_force_field + 2009: particle_projectile_hit + 2013: particle_enderman_teleport + 2014: particle_punch_block + 3001: start_rain + 3002: start_thunder + 3003: stop_rain + 3004: stop_thunder + 3005: pause_game #data: 1 to pause, 0 to resume + 3006: pause_game_no_screen #data: 1 to pause, 0 to resume - same effect as normal pause but without screen + 3007: set_game_speed #x coordinate of pos = scale factor (default 1.0) + 3500: redstone_trigger + 3501: cauldron_explode + 3502: cauldron_dye_armor + 3503: cauldron_clean_armor + 3504: cauldron_fill_potion + 3505: cauldron_take_potion + 3506: cauldron_fill_water + 3507: cauldron_take_water + 3508: cauldron_add_dye + 3509: cauldron_clean_banner + 3600: block_start_break + 3601: block_stop_break + 4000: set_data + 9800: players_sleeping + 0x4000: add_particle_mask position: vec3f data: zigzag32 packet_block_event: !id: 0x1a - !bound: server - coordinates: BlockCoordinates - case_1: zigzag32 - case_2: zigzag32 + !bound: client + # Position is the position of the block that an event occurred at. + position: BlockCoordinates + # EventType is the type of the block event. + # The event type decides the way the event data that follows is used + type: zigzag32 => + 0: sound + 1: change_state + # EventData holds event type specific data. For chests for example, + # opening the chest means the data must be 1 + data: zigzag32 packet_entity_event: !id: 0x1b !bound: both runtime_entity_id: varint - event_id: u8 + event_id: u8 => + 1: jump + 2: hurt_animation + 3: death_animation + 4: arm_swing + 5: stop_attack + 6: tame_fail + 7: tame_success + 8: shake_wet + 9: use_item + 10: eat_grass_animation + 11: fish_hook_bubble + 12: fish_hook_position + 13: fish_hook_hook + 14: fish_hook_tease + 15: squid_ink_cloud + 16: zombie_villager_cure + 18: respawn + 19: iron_golem_offer_flower + 20: iron_golem_withdraw_flower + 21: love_particles #breeding + 22: villager_angry + 23: villager_happy + 24: witch_spell_particles + 25: firework_particles + 26: in_love_particles + 27: silverfish_spawn_animation + 28: guardian_attack + 29: witch_drink_potion + 30: witch_throw_potion + 31: minecart_tnt_prime_fuse + 32: creeper_prime_fuse + 33: air_supply_expired + 34: player_add_xp_levels + 35: elder_guardian_curse + 36: agent_arm_swing + 37: ender_dragon_death + 38: dust_particles #not sure what this is + 39: arrow_shake + + 57: eating_item + + 60: baby_animal_feed #green particles, like bonemeal on crops + 61: death_smoke_cloud + 62: complete_trade + 63: remove_leash #data 1 = cut leash + + 65: consume_totem + 66: player_check_treasure_hunter_achievement #mojang... + 67: entity_spawn #used for MinecraftEventing stuff, not needed + 68: dragon_puke #they call this puke particles + 69: item_entity_merge + 70: start_swim + 71: balloon_pop + 72: treasure_hunt + 73: agent_summon + 74: charged_crossbow + 75: fall data: zigzag32 packet_mob_effect: !id: 0x1c - !bound: server + !bound: client runtime_entity_id: varint event_id: u8 effect_id: zigzag32 @@ -524,7 +652,7 @@ packet_mob_effect: packet_update_attributes: !id: 0x1d - !bound: server + !bound: client runtime_entity_id: varint64 attributes: PlayerAttributes tick: varint64 @@ -560,7 +688,7 @@ packet_interact: packet_block_pick_request: !id: 0x22 - !bound: client + !bound: server x: zigzag32 y: zigzag32 z: zigzag32 @@ -569,21 +697,59 @@ packet_block_pick_request: packet_entity_pick_request: !id: 0x23 - !bound: client + !bound: server runtime_entity_id: lu64 selected_slot: u8 +# PlayerAction is sent by the client when it executes any action, for example starting to sprint, swim, +# starting the breaking of a block, dropping an item, etc. packet_player_action: !id: 0x24 - !bound: client + !bound: server + # EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and + # entities are generally identified in packets using this runtime ID. runtime_entity_id: varint - action_id: zigzag32 - coordinates: BlockCoordinates + # ActionType is the ID of the action that was executed by the player. It is one of the constants that may + # be found above. + action: zigzag32 => + 0: start_break + 1: abort_break + 2: stop_break + 3: get_updated_block + 4: drop_item + 5: start_sleeping + 6: stop_sleeping + 7: respawn + 8: jump + 9: start_sprint + 10: stop_sprint + 11: start_sneak + 12: stop_sneak + 13: creative_player_destroy_block + # sent when spawning in a different dimension to tell the server we spawned + 14: dimension_change_ack + 15: start_glide + 16: stop_glide + 17: build_denied + 18: continue_break + 19: change_skin + # no longer used + 20: set_enchatnment_seed + 21: swimming + 22: stop_swimming + 23: start_spin_attack + 24: stop_spin_attack + 25: ineract_block + # BlockPosition is the position of the target block, if the action with the ActionType set concerned a + # block. If that is not the case, the block position will be zero. + position: BlockCoordinates + # BlockFace is the face of the target block that was touched. If the action with the ActionType set + # concerned a block. If not, the face is always 0. face: zigzag32 packet_hurt_armor: !id: 0x26 - !bound: server + !bound: client health: zigzag32 packet_set_entity_data: @@ -601,7 +767,7 @@ packet_set_entity_motion: packet_set_entity_link: !id: 0x29 - !bound: server + !bound: client ridden_id: zigzag64 rider_id: zigzag64 link_type: u8 @@ -609,12 +775,12 @@ packet_set_entity_link: packet_set_health: !id: 0x2a - !bound: server + !bound: client health: zigzag32 packet_set_spawn_position: !id: 0x2b - !bound: server + !bound: client spawn_type: zigzag32 coordinates: BlockCoordinates dimension: zigzag32 @@ -637,7 +803,7 @@ packet_respawn: packet_container_open: !id: 0x2e - !bound: server + !bound: client window_id: u8 type: u8 coordinates: BlockCoordinates @@ -672,14 +838,14 @@ packet_inventory_slot: packet_container_set_data: !id: 0x33 - !bound: server + !bound: client window_id: u8 property: zigzag32 value: zigzag32 packet_crafting_data: !id: 0x34 - !bound: server + !bound: client recipes: Recipes potion_type_recipes: PotionTypeRecipes potion_container_recipes: PotionContainerChangeRecipes @@ -696,7 +862,7 @@ packet_crafting_event: packet_gui_data_pick_item: !id: 0x36 - !bound: server + !bound: client packet_adventure_settings: !id: 0x37 @@ -711,12 +877,12 @@ packet_adventure_settings: packet_block_entity_data: !id: 0x38 !bound: both - coordinates: BlockCoordinates + position: BlockCoordinates nbt: nbt packet_player_input: !id: 0x39 - !bound: client + !bound: server motion_x: lf32 motion_z: lf32 jumping: bool @@ -724,25 +890,25 @@ packet_player_input: packet_level_chunk: !id: 0x3a - !bound: server - chunk_x: zigzag32 - chunk_z: zigzag32 + !bound: client + x: zigzag32 + z: zigzag32 sub_chunk_count: varint column: Chunks packet_set_commands_enabled: !id: 0x3b - !bound: server + !bound: client enabled: bool packet_set_difficulty: !id: 0x3c - !bound: server + !bound: client difficulty: varint packet_change_dimension: !id: 0x3d - !bound: server + !bound: client dimension: zigzag32 position: vec3f respawn: bool @@ -754,23 +920,23 @@ packet_set_player_game_type: packet_player_list: !id: 0x3f - !bound: server + !bound: client records: PlayerRecords packet_simple_event: !id: 0x40 - !bound: server + !bound: client event_type: lu16 packet_spawn_experience_orb: !id: 0x42 - !bound: server + !bound: client position: vec3f count: zigzag32 packet_clientbound_map_item_data: !id: 0x43 - !bound: server + !bound: client mapinfo: MapInfo packet_map_info_request: @@ -785,7 +951,7 @@ packet_request_chunk_radius: packet_chunk_radius_update: !id: 0x46 - !bound: server + !bound: client chunk_radius: zigzag32 packet_item_frame_drop_item: @@ -795,52 +961,137 @@ packet_item_frame_drop_item: packet_game_rules_changed: !id: 0x48 - !bound: server + !bound: client rules: GameRules packet_camera: !id: 0x49 - !bound: server + !bound: client unknown1: zigzag64 unknown2: zigzag64 packet_boss_event: !id: 0x4a - !bound: server + !bound: both boss_entity_id: zigzag64 - event_type: varint + type: varint => + # S2C: Shows the boss-bar to the player. + 0: show_bar + # C2S: Registers a player to a boss fight. + 1: register_player + # S2C: Removes the boss-bar from the client. + 2: hide_bar + # C2S: Unregisters a player from a boss fight. + 3: unregister_player + # S2C: Sets the bar percentage. + 4: set_bar_progress + # S2C: Sets title of the bar. + 5: set_bar_title + # S2C: darkens the sky + 6: update_properties + # S2C: Not implemented :( Intended to alter bar appearance, but these currently produce no effect on client-side whatsoever. + 7: texture + _: type? + if register_player or unregister_player: + player_id: zigzag64 + if show: + title: string + bar_progress: lf32 + if update_properties: + darkness_factor: li16 + if texture: + color: varint + overlay: varint + if set_bar_progress: + bar_progress: lf32 + if set_bar_title: + title: string packet_show_credits: !id: 0x4b - !bound: server + !bound: client runtime_entity_id: varint status: zigzag32 packet_available_commands: !id: 0x4c - !bound: server + !bound: client + # enum_values: string[]varint + # suffixes: string[]varint + # enums: []varint + # name: string + # # The length of the array below + # values_len: varint + # # Not read from stream: instead calculated from the `values_len` field + # # If the values_len < 0xff => byte + # # If the values_len < 0xffff => short + # # If the values_len < 0xffffff => int + # enum_typex: u8 => + # 0: byte + # 1: short + # 2: int + # valuex: []varint + # # S: bool + # ix: ../enum_typex? + # if byte: u8 + # if short: lu16 + # if int: lu32 +# CommandRequest is sent by the client to request the execution of a server-side command. Although some +# servers support sending commands using the Text packet, this packet is guaranteed to have the correct +# result. packet_command_request: !id: 0x4d - !bound: client + !bound: server + # CommandLine is the raw entered command line. The client does no parsing of the command line by itself + # (unlike it did in the early stages), but lets the server do that. command: string - command_type: varint - unknown_uuid: uuid - request_id: string - unknown: bool + # Origin holds information about the command sender that will be returnd back in the command response + origin: CommandOrigin + # Internal specifies if the command request internal. Setting it to false seems to work and the usage of + # this field is not known. + interval: bool + packet_command_block_update: !id: 0x4e - !bound: client + !bound: server is_block: bool packet_command_output: !id: 0x4f - !bound: server + !bound: client + # CommandOrigin is the data specifying the origin of the command. In other words, the source that the + # command request was from, such as the player itself or a websocket server. The client forwards the + # messages in this packet to the right origin, depending on what is sent here. + origin: CommandOrigin + # OutputType specifies the type of output that is sent. The OutputType sent by vanilla games appears to + # be 3, which seems to work. + output_type: i8 + # SuccessCount is the amount of times that a command was executed successfully as a result of the command + # that was requested. For servers, this is usually a rather meaningless fields, but for vanilla, this is + # applicable for commands created with Functions. + success_count: varint + # OutputMessages is a list of all output messages that should be sent to the player. Whether they are + # shown or not, depends on the type of the messages. + output: []varint + # Success indicates if the output message was one of a successful command execution. If set to true, the + # output message is by default coloured white, whereas if set to false, the message is by default + # coloured red. + success: bool + # Message is the message that is sent to the client in the chat window. It may either be simply a + # message or a translated built-in string like 'commands.tp.success.coordinates', combined with specific + # parameters below. + message_id: string + # Parameters is a list of parameters that serve to supply the message sent with additional information, + # such as the position that a player was teleported to or the effect that was applied to an entity. + # These parameters only apply for the Minecraft built-in command output. + paramaters: string[]varint + packet_update_trade: !id: 0x50 - !bound: server + !bound: client window_id: u8 window_type: u8 unknown0: varint @@ -854,7 +1105,7 @@ packet_update_trade: packet_update_equipment: !id: 0x51 - !bound: server + !bound: client window_id: u8 window_type: u8 unknown: u8 @@ -863,7 +1114,7 @@ packet_update_equipment: packet_resource_pack_data_info: !id: 0x52 - !bound: server + !bound: client package_id: string max_chunk_size: lu32 chunk_count: lu32 @@ -874,7 +1125,7 @@ packet_resource_pack_data_info: packet_resource_pack_chunk_data: !id: 0x53 - !bound: server + !bound: client package_id: string chunk_index: lu32 progress: lu64 @@ -882,19 +1133,19 @@ packet_resource_pack_chunk_data: packet_resource_pack_chunk_request: !id: 0x54 - !bound: client + !bound: server package_id: string chunk_index: lu32 packet_transfer: !id: 0x55 - !bound: server + !bound: client server_address: string port: lu16 packet_play_sound: !id: 0x56 - !bound: server + !bound: client name: string coordinates: BlockCoordinates volume: lf32 @@ -902,13 +1153,13 @@ packet_play_sound: packet_stop_sound: !id: 0x57 - !bound: server + !bound: client name: string stop_all: bool packet_set_title: !id: 0x58 - !bound: server + !bound: client type: zigzag32 text: string fade_in_time: zigzag32 @@ -917,22 +1168,22 @@ packet_set_title: packet_add_behavior_tree: !id: 0x59 - !bound: server + !bound: client behaviortree: string packet_structure_block_update: !id: 0x5a - !bound: server + !bound: client packet_show_store_offer: !id: 0x5b - !bound: server + !bound: client unknown0: string unknown1: bool packet_purchase_receipt: !id: 0x5c - !bound: client + !bound: server packet_player_skin: !id: 0x5d @@ -945,21 +1196,43 @@ packet_player_skin: packet_sub_client_login: !id: 0x5e - !bound: server + !bound: client packet_initiate_web_socket_connection: !id: 0x5f - !bound: server + !bound: client server: string packet_set_last_hurt_by: !id: 0x60 - !bound: server + !bound: client unknown: varint packet_book_edit: !id: 0x61 - !bound: server + !bound: client + type: u8 => + 0: replace_page + 1: add_page + 2: delete_page + 3: swap_pages + 4: sign + slot: u8 + _: type? + if replace_page or add_page: + page_number: u8 + text: string + photo_name: string + if delete_page: + page_number: u8 + if swap_pages: + page1: u8 + page2: u8 + if sign: + title: string + author: string + xuid: string + packet_npc_request: !id: 0x62 @@ -971,51 +1244,51 @@ packet_npc_request: packet_photo_transfer: !id: 0x63 - !bound: client + !bound: server file_name: string image_data: string unknown2: string packet_modal_form_request: !id: 0x64 - !bound: server + !bound: client form_id: varint data: string packet_modal_form_response: !id: 0x65 - !bound: client + !bound: server form_id: varint data: string packet_server_settings_request: !id: 0x66 - !bound: client + !bound: server packet_server_settings_response: !id: 0x67 - !bound: server + !bound: client form_id: varint data: string packet_show_profile: !id: 0x68 - !bound: server + !bound: client xuid: string packet_set_default_game_type: !id: 0x69 - !bound: server + !bound: client gamemode: varint packet_remove_objective: !id: 0x6a - !bound: server + !bound: client objective_name: string packet_set_display_objective: !id: 0x6b - !bound: server + !bound: client display_slot: string objective_name: string display_name: string @@ -1024,7 +1297,7 @@ packet_set_display_objective: packet_set_score: !id: 0x6c - !bound: server + !bound: client entries: ScoreEntries packet_lab_table: @@ -1038,7 +1311,7 @@ packet_lab_table: packet_update_block_synced: !id: 0x6e - !bound: server + !bound: client coordinates: BlockCoordinates block_runtime_id: varint block_priority: varint @@ -1048,23 +1321,23 @@ packet_update_block_synced: packet_move_entity_delta: !id: 0x6f - !bound: server + !bound: client runtime_entity_id: varint flags: lu16 packet_set_scoreboard_identity: !id: 0x70 - !bound: server + !bound: client entries: ScoreboardIdentityEntries packet_set_local_player_as_initialized: !id: 0x71 - !bound: client + !bound: server runtime_entity_id: varint packet_update_soft_enum: !id: 0x72 - !bound: server + !bound: client packet_network_stack_latency: !id: 0x73 @@ -1080,7 +1353,7 @@ packet_script_custom_event: packet_spawn_particle_effect: !id: 0x76 - !bound: server + !bound: client dimension_id: u8 entity_id: zigzag64 position: vec3f @@ -1088,7 +1361,7 @@ packet_spawn_particle_effect: packet_available_entity_identifiers: !id: 0x77 - !bound: server + !bound: client nbt: nbt packet_level_sound_event_v2: @@ -1103,13 +1376,13 @@ packet_level_sound_event_v2: packet_network_chunk_publisher_update: !id: 0x79 - !bound: server + !bound: client coordinates: BlockCoordinates radius: varint packet_biome_definition_list: !id: 0x7a - !bound: server + !bound: client nbt: nbt packet_level_sound_event: @@ -1124,15 +1397,15 @@ packet_level_sound_event: packet_level_event_generic: !id: 0x7c - !bound: server + !bound: client packet_lectern_update: !id: 0x7d - !bound: server + !bound: client packet_video_stream_connect: !id: 0x7e - !bound: server + !bound: client server_uri: string frame_send_frequency: lf32 action: u8 @@ -1146,32 +1419,32 @@ packet_client_cache_status: packet_on_screen_texture_animation: !id: 0x82 - !bound: server + !bound: client packet_map_create_locked_copy: !id: 0x83 - !bound: server + !bound: client packet_structure_template_data_export_request: !id: 0x84 - !bound: server + !bound: client packet_structure_template_data_export_response: !id: 0x85 - !bound: server + !bound: client packet_update_block_properties: !id: 0x86 - !bound: server + !bound: client nbt: nbt packet_client_cache_blob_status: !id: 0x87 - !bound: server + !bound: client packet_client_cache_miss_response: !id: 0x88 - !bound: server + !bound: client packet_network_settings: !id: 0x8f @@ -1181,31 +1454,31 @@ packet_network_settings: packet_creative_content: !id: 0x91 - !bound: server + !bound: client items: ItemStacks packet_player_enchant_options: !id: 0x92 - !bound: server + !bound: client enchant_options: EnchantOptions packet_item_stack_request: !id: 0x93 - !bound: client + !bound: server requests: ItemStackRequests packet_item_stack_response: !id: 0x94 - !bound: server + !bound: client responses: ItemStackResponses packet_update_player_game_type: !id: 0x97 - !bound: client + !bound: server packet_packet_violation_warning: !id: 0x9c - !bound: client + !bound: server violation_type: zigzag32 severity: zigzag32 packet_id: zigzag32 @@ -1213,11 +1486,11 @@ packet_packet_violation_warning: packet_item_component: !id: 0xa2 - !bound: server + !bound: client entries: ItemComponentList packet_filter_text_packet: !id: 0xa3 - !bound: server + !bound: client text: string from_server: bool diff --git a/data/new/types.yaml b/data/new/types.yaml index f53f36d..528a0ba 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -104,27 +104,146 @@ vec2f: z: lf32 MetadataDictionary: []varint - key: varint + # https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/entity/Entity.php#L101 + key: varint => + 0: index + 1: health #int (minecart/boat) + 2: variant #int + 3: color #byte + 4: nametag #string + 5: owner_eid #long + 6: target_eid #long + 7: air #short + 8: potion_color #int (ARGB!) + 9: potion_ambient #byte + 10: jump_duration #long + 11: hurt_time #int (minecart/boat) + 12: hurt_direction #int (minecart/boat) + 13: paddle_time_left #float + 14: paddle_time_right #float + 15: experience_value #int (xp orb) + 16: minecart_display_block #int (id | (data << 16)) + 17: minecart_display_offset #int + 18: minecart_has_display #byte (must be 1 for minecart to show block inside) + 20: old_swell + 21: swell_dir + 22: charge_amount + 23: enderman_held_runtime_id #short + 24: entity_age #short + 26: player_flags + 27: player_index + 28: player_bed_position #block coords + 29: fireball_power_x #float + 30: fireball_power_y + 31: fireball_power_z + 32: aux_power + 33: fish_x + 34: fish_z + 35: fish_angle + 36: potion_aux_value #short + 37: lead_holder_eid #long + 38: scale + 39: interactive_tag #string + 40: npc_skin_id #string + 41: url_tag #string + 42: max_airdata_max_air + 43: mark_variant #int + 44: container_type #byte + 45: container_base_size #int + 46: container_extra_slots_per_strength #int + 47: block_target + 48: wither_invulnerable_ticks #int + 49: wither_target_1 #long + 50: wither_target_2 #long + 51: wither_target_3 #long + 52: aerial_attack + 53: boundingbox_width + 54: boundingbox_height + 55: fuse_length + 56: rider_seat_position #vector3f + 57: rider_rotation_locked #byte + 58: rider_max_rotation #float + 59: rider_min_rotation #float + 60: area_effect_cloud_radius #float + 61: area_effect_cloud_waiting #int + 62: area_effect_cloud_particle_id #int + 63: shulker_peek_id #int + 64: shulker_attach_face #byte + 65: shulker_attached #short + 66: shulker_attach_pos + 67: trading_player_eid #long + 68: trading_career + 69: has_command_block + 70: command_block_command #string + 71: command_block_last_output #string + 72: command_block_track_output #byte + 73: controlling_rider_seat_number #byte + 74: strength #int + 75: max_strength #int + 76: spell_casting_color #int + 77: limited_life + 78: armor_stand_pose_index # int + 79: ender_crystal_time_offset # int + 80: always_show_nametag # byte + 81: color_2 # byte + 82: name_author + 83: score_tag #String + 84: balloon_attached_entity # long + 85: pufferfish_size + 86: bubble_time + 87: agent + 88: sitting_amount + 89: sitting_amount_previous + 90: eating_counter + 91: flags_extended + 92: laying_amount + 93: laying_amount_previous + 94: duration + 95: spawn_time + 96: change_rate + 97: change_on_pickup + 98: pickup_count + 99: interact_text + 100: trade_tier + 101: max_trade_tier + 102: trade_experience + 103: skin_id + 104: spawning_frames + 105: command_block_tick_delay + 106: command_block_execute_on_first_tick + 107: ambient_sound_interval + 108: ambient_sound_interval_range + 109: ambient_sound_event_name + 110: fall_damage_multiplier + 111: name_raw_text + 112: can_ride_target + 113: low_tier_cured_discount + 114: high_tier_cured_discount + 115: nearby_cured_discount + 116: nearby_cured_discount_timestamp + 117: hitbox + 118: is_buoyant + 119: buoyancy_data type: varint => - 0: BYTE - 1: SHORT - 2: INT - 3: FLOAT - 4: STRING - 5: COMPOUND_TAG - 6: POS - 7: LONG - 8: VECTOR3F + 0: byte + 1: short + 2: int + 3: float + 4: string + 5: compound + 6: vec3i + 7: long + 8: vec3f value: type? - if BYTE: i8 - if SHORT: li16 - if INT: zigzag32 - if FLOAT: lf32 - if STRING: string - if COMPOUND_TAG: nbt - if POS: vec3i - if LONG: zigzag64 - if VECTOR3F: li32 + if byte: i8 + if short: li16 + if int: zigzag32 + if float: lf32 + if string: string + if compound: nbt + if vec3i: vec3i + if long: zigzag64 + if vec3f: vec3f Links: []varint ridden_entity_id: zigzag64 @@ -455,4 +574,37 @@ ItemStackResponses: []varint ItemComponentList: []varint name: string - nbt: nbt \ No newline at end of file + nbt: nbt + +CommandOrigin: + # Origin is one of the values above that specifies the origin of the command. The origin may change, + # depending on what part of the client actually called the command. The command may be issued by a + # websocket server, for example. + type: varint => + 0: player + 1: block + 2: minecart_block + 3: dev_console + 4: test + 5: automation_player + 6: client_automation + 7: dedicated_server + 8: entity + 9: virtual + 10: game_argument + 11: entity_server + # UUID is the UUID of the command called. This UUID is a bit odd as it is not specified by the server. It + # is not clear what exactly this UUID is meant to identify, but it is unique for each command called. + uuid: uuid + # RequestID is an ID that identifies the request of the client. The server should send a CommandOrigin + # with the same request ID to ensure it can be matched with the request by the caller of the command. + # This is especially important for websocket servers and it seems that this field is only non-empty for + # these websocket servers. + request_id: string + # PlayerUniqueID is an ID that identifies the player, the same as the one found in the AdventureSettings + # packet. Filling it out with 0 seems to work. + # PlayerUniqueID is only written if Origin is CommandOriginDevConsole or CommandOriginTest. + player_entity_id: type? + if dev_console or test: + player_entity_id: zigzag64 + diff --git a/data/newproto.json b/data/newproto.json index f2a320f..7a6f93e 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -433,7 +433,132 @@ [ { "name": "key", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "index", + "1": "health", + "2": "variant", + "3": "color", + "4": "nametag", + "5": "owner_eid", + "6": "target_eid", + "7": "air", + "8": "potion_color", + "9": "potion_ambient", + "10": "jump_duration", + "11": "hurt_time", + "12": "hurt_direction", + "13": "paddle_time_left", + "14": "paddle_time_right", + "15": "experience_value", + "16": "minecart_display_block", + "17": "minecart_display_offset", + "18": "minecart_has_display", + "20": "old_swell", + "21": "swell_dir", + "22": "charge_amount", + "23": "enderman_held_runtime_id", + "24": "entity_age", + "26": "player_flags", + "27": "player_index", + "28": "player_bed_position", + "29": "fireball_power_x", + "30": "fireball_power_y", + "31": "fireball_power_z", + "32": "aux_power", + "33": "fish_x", + "34": "fish_z", + "35": "fish_angle", + "36": "potion_aux_value", + "37": "lead_holder_eid", + "38": "scale", + "39": "interactive_tag", + "40": "npc_skin_id", + "41": "url_tag", + "42": "max_airdata_max_air", + "43": "mark_variant", + "44": "container_type", + "45": "container_base_size", + "46": "container_extra_slots_per_strength", + "47": "block_target", + "48": "wither_invulnerable_ticks", + "49": "wither_target_1", + "50": "wither_target_2", + "51": "wither_target_3", + "52": "aerial_attack", + "53": "boundingbox_width", + "54": "boundingbox_height", + "55": "fuse_length", + "56": "rider_seat_position", + "57": "rider_rotation_locked", + "58": "rider_max_rotation", + "59": "rider_min_rotation", + "60": "area_effect_cloud_radius", + "61": "area_effect_cloud_waiting", + "62": "area_effect_cloud_particle_id", + "63": "shulker_peek_id", + "64": "shulker_attach_face", + "65": "shulker_attached", + "66": "shulker_attach_pos", + "67": "trading_player_eid", + "68": "trading_career", + "69": "has_command_block", + "70": "command_block_command", + "71": "command_block_last_output", + "72": "command_block_track_output", + "73": "controlling_rider_seat_number", + "74": "strength", + "75": "max_strength", + "76": "spell_casting_color", + "77": "limited_life", + "78": "armor_stand_pose_index", + "79": "ender_crystal_time_offset", + "80": "always_show_nametag", + "81": "color_2", + "82": "name_author", + "83": "score_tag", + "84": "balloon_attached_entity", + "85": "pufferfish_size", + "86": "bubble_time", + "87": "agent", + "88": "sitting_amount", + "89": "sitting_amount_previous", + "90": "eating_counter", + "91": "flags_extended", + "92": "laying_amount", + "93": "laying_amount_previous", + "94": "duration", + "95": "spawn_time", + "96": "change_rate", + "97": "change_on_pickup", + "98": "pickup_count", + "99": "interact_text", + "100": "trade_tier", + "101": "max_trade_tier", + "102": "trade_experience", + "103": "skin_id", + "104": "spawning_frames", + "105": "command_block_tick_delay", + "106": "command_block_execute_on_first_tick", + "107": "ambient_sound_interval", + "108": "ambient_sound_interval_range", + "109": "ambient_sound_event_name", + "110": "fall_damage_multiplier", + "111": "name_raw_text", + "112": "can_ride_target", + "113": "low_tier_cured_discount", + "114": "high_tier_cured_discount", + "115": "nearby_cured_discount", + "116": "nearby_cured_discount_timestamp", + "117": "hitbox", + "118": "is_buoyant", + "119": "buoyancy_data" + } + } + ] }, { "name": "type", @@ -442,15 +567,15 @@ { "type": "varint", "mappings": { - "0": "BYTE", - "1": "SHORT", - "2": "INT", - "3": "FLOAT", - "4": "STRING", - "5": "COMPOUND_TAG", - "6": "POS", - "7": "LONG", - "8": "VECTOR3F" + "0": "byte", + "1": "short", + "2": "int", + "3": "float", + "4": "string", + "5": "compound", + "6": "vec3i", + "7": "long", + "8": "vec3f" } } ] @@ -462,15 +587,15 @@ { "compareTo": "type", "fields": { - "BYTE": "i8", - "SHORT": "li16", - "INT": "zigzag32", - "FLOAT": "lf32", - "STRING": "string", - "COMPOUND_TAG": "nbt", - "POS": "vec3i", - "LONG": "zigzag64", - "VECTOR3F": "li32" + "byte": "i8", + "short": "li16", + "int": "zigzag32", + "float": "lf32", + "string": "string", + "compound": "nbt", + "vec3i": "vec3i", + "long": "zigzag64", + "vec3f": "vec3f" }, "default": "void" } @@ -2008,6 +2133,72 @@ ] } ], + "CommandOrigin": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "player", + "1": "block", + "2": "minecart_block", + "3": "dev_console", + "4": "test", + "5": "automation_player", + "6": "client_automation", + "7": "dedicated_server", + "8": "entity", + "9": "virtual", + "10": "game_argument", + "11": "entity_server" + } + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "request_id", + "type": "string" + }, + { + "name": "player_entity_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "dev_console": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ], + "test": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], "mcpe_packet": [ "container", [ @@ -2500,7 +2691,7 @@ "container", [ { - "name": "sourceName", + "name": "source_name", "type": "string" } ] @@ -2509,7 +2700,7 @@ "container", [ { - "name": "sourceName", + "name": "source_name", "type": "string" } ] @@ -2518,7 +2709,7 @@ "container", [ { - "name": "sourceName", + "name": "source_name", "type": "string" } ] @@ -3300,8 +3491,76 @@ "container", [ { - "name": "event_id", - "type": "zigzag32" + "name": "event", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "1000": "sound_click", + "1001": "sound_click_fail", + "1002": "sound_shoot", + "1003": "sound_door", + "1004": "sound_fizz", + "1005": "sound_ignite", + "1007": "sound_ghast", + "1008": "sound_ghast_shoot", + "1009": "sound_blaze_shoot", + "1010": "sound_door_bump", + "1012": "sound_door_crash", + "1018": "sound_enderman_teleport", + "1020": "sound_anvil_break", + "1021": "sound_anvil_use", + "1022": "sound_anvil_fall", + "1030": "sound_pop", + "1032": "sound_portal", + "1040": "sound_itemframe_add_item", + "1041": "sound_itemframe_remove", + "1042": "sound_itemframe_place", + "1043": "sound_itemframe_remove_item", + "1044": "sound_itemframe_rotate_item", + "1050": "sound_camera", + "1051": "sound_orb", + "1052": "sound_totem", + "1060": "sound_armor_stand_break", + "1061": "sound_armor_stand_hit", + "1062": "sound_armor_stand_fall", + "1063": "sound_armor_stand_place", + "2000": "particle_shoot", + "2001": "particle_destroy", + "2002": "particle_splash", + "2003": "particle_eye_despawn", + "2004": "particle_spawn", + "2006": "guardian_curse", + "2008": "particle_block_force_field", + "2009": "particle_projectile_hit", + "2013": "particle_enderman_teleport", + "2014": "particle_punch_block", + "3001": "start_rain", + "3002": "start_thunder", + "3003": "stop_rain", + "3004": "stop_thunder", + "3005": "pause_game", + "3006": "pause_game_no_screen", + "3007": "set_game_speed", + "3500": "redstone_trigger", + "3501": "cauldron_explode", + "3502": "cauldron_dye_armor", + "3503": "cauldron_clean_armor", + "3504": "cauldron_fill_potion", + "3505": "cauldron_take_potion", + "3506": "cauldron_fill_water", + "3507": "cauldron_take_water", + "3508": "cauldron_add_dye", + "3509": "cauldron_clean_banner", + "3600": "block_start_break", + "3601": "block_stop_break", + "4000": "set_data", + "9800": "players_sleeping", + "16384": "add_particle_mask" + } + } + ] }, { "name": "position", @@ -3317,15 +3576,24 @@ "container", [ { - "name": "coordinates", + "name": "position", "type": "BlockCoordinates" }, { - "name": "case_1", - "type": "zigzag32" + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "sound", + "1": "change_state" + } + } + ] }, { - "name": "case_2", + "name": "data", "type": "zigzag32" } ] @@ -3339,7 +3607,68 @@ }, { "name": "event_id", - "type": "u8" + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "jump", + "2": "hurt_animation", + "3": "death_animation", + "4": "arm_swing", + "5": "stop_attack", + "6": "tame_fail", + "7": "tame_success", + "8": "shake_wet", + "9": "use_item", + "10": "eat_grass_animation", + "11": "fish_hook_bubble", + "12": "fish_hook_position", + "13": "fish_hook_hook", + "14": "fish_hook_tease", + "15": "squid_ink_cloud", + "16": "zombie_villager_cure", + "18": "respawn", + "19": "iron_golem_offer_flower", + "20": "iron_golem_withdraw_flower", + "21": "love_particles", + "22": "villager_angry", + "23": "villager_happy", + "24": "witch_spell_particles", + "25": "firework_particles", + "26": "in_love_particles", + "27": "silverfish_spawn_animation", + "28": "guardian_attack", + "29": "witch_drink_potion", + "30": "witch_throw_potion", + "31": "minecart_tnt_prime_fuse", + "32": "creeper_prime_fuse", + "33": "air_supply_expired", + "34": "player_add_xp_levels", + "35": "elder_guardian_curse", + "36": "agent_arm_swing", + "37": "ender_dragon_death", + "38": "dust_particles", + "39": "arrow_shake", + "57": "eating_item", + "60": "baby_animal_feed", + "61": "death_smoke_cloud", + "62": "complete_trade", + "63": "remove_leash", + "65": "consume_totem", + "66": "player_check_treasure_hunter_achievement", + "67": "entity_spawn", + "68": "dragon_puke", + "69": "item_entity_merge", + "70": "start_swim", + "71": "balloon_pop", + "72": "treasure_hunt", + "73": "agent_summon", + "74": "charged_crossbow", + "75": "fall" + } + } + ] }, { "name": "data", @@ -3511,11 +3840,44 @@ "type": "varint" }, { - "name": "action_id", - "type": "zigzag32" + "name": "action", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "start_break", + "1": "abort_break", + "2": "stop_break", + "3": "get_updated_block", + "4": "drop_item", + "5": "start_sleeping", + "6": "stop_sleeping", + "7": "respawn", + "8": "jump", + "9": "start_sprint", + "10": "stop_sprint", + "11": "start_sneak", + "12": "stop_sneak", + "13": "creative_player_destroy_block", + "14": "dimension_change_ack", + "15": "start_glide", + "16": "stop_glide", + "17": "build_denied", + "18": "continue_break", + "19": "change_skin", + "20": "set_enchatnment_seed", + "21": "swimming", + "22": "stop_swimming", + "23": "start_spin_attack", + "24": "stop_spin_attack", + "25": "ineract_block" + } + } + ] }, { - "name": "coordinates", + "name": "position", "type": "BlockCoordinates" }, { @@ -3837,7 +4199,7 @@ "container", [ { - "name": "coordinates", + "name": "position", "type": "BlockCoordinates" }, { @@ -3871,11 +4233,11 @@ "container", [ { - "name": "chunk_x", + "name": "x", "type": "zigzag32" }, { - "name": "chunk_z", + "name": "z", "type": "zigzag32" }, { @@ -4038,8 +4400,106 @@ "type": "zigzag64" }, { - "name": "event_type", - "type": "varint" + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "show_bar", + "1": "register_player", + "2": "hide_bar", + "3": "unregister_player", + "4": "set_bar_progress", + "5": "set_bar_title", + "6": "update_properties", + "7": "texture" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "register_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "unregister_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "show": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "bar_progress", + "type": "lf32" + } + ] + ], + "update_properties": [ + "container", + [ + { + "name": "darkness_factor", + "type": "li16" + } + ] + ], + "texture": [ + "container", + [ + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], + "set_bar_progress": [ + "container", + [ + { + "name": "bar_progress", + "type": "lf32" + } + ] + ], + "set_bar_title": [ + "container", + [ + { + "name": "title", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] } ] ], @@ -4068,19 +4528,11 @@ "type": "string" }, { - "name": "command_type", - "type": "varint" + "name": "origin", + "type": "CommandOrigin" }, { - "name": "unknown_uuid", - "type": "uuid" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "unknown", + "name": "interval", "type": "bool" } ] @@ -4096,7 +4548,52 @@ ], "packet_command_output": [ "container", - [] + [ + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "output_type", + "type": "i8" + }, + { + "name": "success_count", + "type": "varint" + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "success", + "type": "bool" + }, + { + "name": "message_id", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + } + ] ], "packet_update_trade": [ "container", @@ -4386,7 +4883,113 @@ ], "packet_book_edit": [ "container", - [] + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "replace_page", + "1": "add_page", + "2": "delete_page", + "3": "swap_pages", + "4": "sign" + } + } + ] + }, + { + "name": "slot", + "type": "u8" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "replace_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "add_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "delete_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + } + ] + ], + "swap_pages": [ + "container", + [ + { + "name": "page1", + "type": "u8" + }, + { + "name": "page2", + "type": "u8" + } + ] + ], + "sign": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "author", + "type": "string" + }, + { + "name": "xuid", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] + } + ] ], "packet_npc_request": [ "container", From b6f8fff01e3f35ff9f16a85790279feded9501fc Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 16 Feb 2021 23:31:19 -0500 Subject: [PATCH 096/458] disable some logging --- src/auth/chains.js | 6 +---- src/auth/constants.js | 3 +-- src/auth/encryption.js | 11 ++++----- src/client.js | 10 ++++---- src/connection.js | 3 ++- src/transforms/encryption.js | 45 +++++++++++------------------------- 6 files changed, 28 insertions(+), 50 deletions(-) diff --git a/src/auth/chains.js b/src/auth/chains.js index 5208b9f..5083a03 100644 --- a/src/auth/chains.js +++ b/src/auth/chains.js @@ -1,11 +1,7 @@ const JWT = require('jsonwebtoken') const constants = require('./constants') -const fs = require('fs') -const { decode } = require('jwt-simple') -// import jwt from 'jwt-simple'; -// const jwt = require('jwt-simple') -// 💗 web archive +// Refer to the docs: // https://web.archive.org/web/20180917171505if_/https://confluence.yawk.at/display/PEPROTOCOL/Game+Packets#GamePackets-Login function mcPubKeyToPem(mcPubKeyBuffer) { diff --git a/src/auth/constants.js b/src/auth/constants.js index 3d04d67..2ffbe1d 100644 --- a/src/auth/constants.js +++ b/src/auth/constants.js @@ -1,4 +1,3 @@ module.exports = { - PUBLIC_KEY: 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V', - secret_key: 'nwOn35gXIfEfgZPIrjNJ+cAxODD/XIpjs3YG7FO1pmwbzpRSlac', + PUBLIC_KEY: 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V' } diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 956eede..8402497 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -31,11 +31,10 @@ function Encrypt(client, server, options) { const secretHash = crypto.createHash('sha256') secretHash.update(SALT) secretHash.update(client.sharedSecret) - console.log('---- SHARED SECRET', client.sharedSecret) - + console.log('[encrypt] Shared secret', client.sharedSecret) client.secretKeyBytes = secretHash.digest() - console.log('Hash', client.secretKeyBytes) + console.log('[encrypt] Shared hash', client.secretKeyBytes) const x509 = writeX509PublicKey(alice.getPublicKey()) const token = JWT.sign({ salt: toBase64(SALT), @@ -54,7 +53,7 @@ function Encrypt(client, server, options) { } function startServerboundEncryption(token) { - console.warn('Starting serverbound encryption', token) + console.warn('[encrypt] Starting serverbound encryption', token) const jwt = token?.token if (!jwt) { // TODO: allow connecting to servers without encryption @@ -67,7 +66,7 @@ function Encrypt(client, server, options) { const body = JSON.parse(String(payload)) const serverPublicKey = readX509PublicKey(head.x5u) client.sharedSecret = alice.computeSecret(serverPublicKey) - console.log('------ SHARED SECRET', client.sharedSecret) + console.log('[encrypt] Shared secret', client.sharedSecret) const salt = Buffer.from(body.salt, 'base64') @@ -76,7 +75,7 @@ function Encrypt(client, server, options) { secretHash.update(client.sharedSecret) client.secretKeyBytes = secretHash.digest() - console.log('Hash', client.secretKeyBytes) + console.log('[encrypt] Shared hash', client.secretKeyBytes) const initial = client.secretKeyBytes.slice(0, 16) client.startEncryption(initial) diff --git a/src/client.js b/src/client.js index acba7a6..8d21ead 100644 --- a/src/client.js +++ b/src/client.js @@ -34,7 +34,7 @@ class Client extends Connection { } onEncapsulated = (encapsulated, inetAddr) => { - log(inetAddr.address, ': Encapsulated', encapsulated) + // log(inetAddr.address, ': Encapsulated', encapsulated) const buffer = encapsulated.buffer this.handle(buffer) } @@ -102,9 +102,11 @@ class Client extends Connection { } readPacket(packet) { - console.log('packet', packet) + // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) - console.info('->', des) + console.log('->',des) + const pakData = { name: des.data.name, params: des.data.params } + // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) switch (des.data.name) { case 'server_to_client_handshake': this.emit('client.server_handshake', des.data.params) @@ -118,7 +120,7 @@ class Client extends Connection { case 'start_game': fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k,v) => typeof v == 'bigint' ? v.toString() : v)) default: - console.log('Sending to listeners') + // console.log('Sending to listeners') } this.emit(des.data.name, des.data.params) diff --git a/src/connection.js b/src/connection.js index e6eef5a..f266ebf 100644 --- a/src/connection.js +++ b/src/connection.js @@ -87,7 +87,7 @@ class Connection extends EventEmitter { handle(buffer) { // handle encapsulated if (buffer[0] == 0xfe) { // wrapper if (this.encryptionEnabled) { - // console.log('READING ENCRYPTED PACKET', buffer) + console.log('Reading encrypted packet', buffer) this.decrypt(buffer.slice(1)) } else { const stream = new BinaryStream(buffer) @@ -100,6 +100,7 @@ class Connection extends EventEmitter { } } } + console.log('[client] procesed ', buffer) } } diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index f9cf293..26896c4 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -126,47 +126,28 @@ function createDecryptor(client, iv) { // console.log(computedCheckSum2, computedCheckSum3) console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') client.receiveCounter++ - // if (checksum.toString("hex") == computedCheckSum.toString("hex")) { - this.push(packet) - // console.log('🔵 Decriphered', checksum) - // const inflated = Zlib.inflateRawSync(chunk, { - // chunkSize: 1024 * 1024 * 2 - // }) - // console.log('🔵 Inflated') - // client.onDecryptedPacket(inflated) - // } else { - // // console.log('🔴 Not OK') - // throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) - // } - cb() - } - }) - - const inflator = new Transform({ - transform(chunk, enc, cb) { - console.log('🔵 Inflating') const inflated = Zlib.inflateRawSync(chunk, { chunkSize: 1024 * 1024 * 2 }) - console.log('🔵 Inflated') - this.push(inflated) - cb() - // Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buf) => { - // console.log('🔵 INF') - // if (err) throw err - // this.push(buf) - // cb() - // }) + if (checksum.toString("hex") == computedCheckSum.toString("hex")) { + this.push(packet) + console.log('🔵 Decriphered', checksum) + + console.log('🔵 Inflated') + client.onDecryptedPacket(inflated) + } else { + console.log(`🔴 Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) + client.onDecryptedPacket(inflated) // allow it anyway + // throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) + } + cb() } }) + client.decipher.pipe(verifyChecksum) - .pipe(inflator) - // .pipe(Zlib.createInflateRaw({ chunkSize: 1024 * 1024 * 2 })) - .on('data', (...args) => client.onDecryptedPacket(...args)) - // .on('end', () => console.log('Decryptor: finish pipeline')) // Not sure why, but sending two packets to the decryption pipe before // the other is completed breaks the checksum check. From 4e3c5f8e3139bca8b5c3fc6660c077379ad9ce8f Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 16 Feb 2021 23:32:57 -0500 Subject: [PATCH 097/458] implement command packet --- data/new/compile.js | 2 +- data/new/proto.yml | 94 ++++++++--- data/newproto.json | 238 +++++++++++++++++++++++++++- src/datatypes/compiler-minecraft.js | 113 +++++++++---- test/serialization.js | 55 ++++++- 5 files changed, 445 insertions(+), 57 deletions(-) diff --git a/data/new/compile.js b/data/new/compile.js index 6df30d9..7ffca0e 100644 --- a/data/new/compile.js +++ b/data/new/compile.js @@ -18,9 +18,9 @@ fs.unlinkSync('./protocol.json') //remove temp file function createProtocol() { const compiler = new ProtoDefCompiler() const protocol = require('../newproto.json').types - compiler.addTypesToCompile(protocol) compiler.addTypes(require('../../src/datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) + compiler.addTypesToCompile(protocol) fs.writeFileSync('../read.js', 'module.exports = ' + compiler.readCompiler.generate()) fs.writeFileSync('../write.js', 'module.exports = ' + compiler.writeCompiler.generate()) diff --git a/data/new/proto.yml b/data/new/proto.yml index 9727a76..b24839e 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -1013,29 +1013,83 @@ packet_show_credits: runtime_entity_id: varint status: zigzag32 +# This packet sends a list of commands to the client. Commands can have +# arguments, and some of those arguments can have 'enum' values, which are a list of possible +# values for the argument. The serialization is rather complex and involves palettes like chunks. +## In bedrock-protocol, listen to on('client.commands') for a simpler representation packet_available_commands: !id: 0x4c !bound: client - # enum_values: string[]varint - # suffixes: string[]varint - # enums: []varint - # name: string - # # The length of the array below - # values_len: varint - # # Not read from stream: instead calculated from the `values_len` field - # # If the values_len < 0xff => byte - # # If the values_len < 0xffff => short - # # If the values_len < 0xffffff => int - # enum_typex: u8 => - # 0: byte - # 1: short - # 2: int - # valuex: []varint - # # S: bool - # ix: ../enum_typex? - # if byte: u8 - # if short: lu16 - # if int: lu32 + # Here all the enum values for all of the possible commands are stored to one array palette + enum_values: string[]varint + # Integer paramaters may sometimes have a prefix, such as the XP command: + # /xp [player: target] <- here, the xp command gives experience points + # /xp L [player: target] <- here, the xp command gives experience levels + # This is the palette of suffixes + suffixes: string[]varint + # The list of enum objects + enums: []varint + # The name of the enum + name: string + # The length of the array below + values_len: varint + # Not read from stream: instead calculated from the `values_len` field + # If the values_len < 0xff => byte + # If the values_len < 0xffff => short + # If the values_len < 0xffffff => int + _enum_type: '["enum_size_based_on_values_len"]' + # The values in the enum + values: []$values_len + # The indexes to value in the palette + _: ../_enum_type? + if byte: u8 + if short: lu16 + if int: lu32 + command_data: []varint + name: string + description: string + flags: u8 + permission_level: u8 + alias: li32 + # The list of overload paramaters for this command + overloads: []varint + # Each of the paramaters gets an array of posible overloads + _: []varint + # The name of the paramater shown to the user (the `amount` in `/xp `) + paramater_name: string + # Bitfield: If FLAG_ENUM is set, the lower 16 bits act as an index to enums array + # If FLAG_SUFFIX is set, the lower 16 bits act as an index to the suffix palette + # and the client interperts the type as just `int` as in the example above + paramater_type: li32 + # Is this paramater required? + optional: bool + # Additinal options for this command (thanks macroshaft...) + flags: CommandFlags + # There are two types of enums: static enums which cannot be changed after sending AvaliableCommands, + # (unless you resend the whole packet) and 'soft' or 'dynamic' enums like below which is an array + # that can be updated with the UpdateSoftEnum packet + dynamic_enums: []varint + name: string + values: string[]varint + enum_constraints: []varint + value_index: li32 + enum_index: li32 + constraints: []varint + constraint: u8 => + 0: cheats_enabled + +# ParamOptionCollapseEnum specifies if the enum (only if the Type is actually an enum type. If not, +# setting this to true has no effect) should be collapsed. This means that the options of the enum are +# never shown in the actual usage of the command, but only as auto-completion, like it automatically does +# with enums that have a big amount of options. To illustrate, it can make +# <$Name: bool>. +CommandFlags: [ "bitfield", [ + { "name": "unused", "size": 1, "signed": false }, + { "name": "collapse_enum", "size": 1, "signed": false }, + { "name": "has_semantic_constraint", "size": 1, "signed": false } +]] + +# enum_size_based_on_values_len: native # CommandRequest is sent by the client to request the execution of a server-side command. Although some # servers support sending commands using the Text packet, this packet is guaranteed to have the correct diff --git a/data/newproto.json b/data/newproto.json index 7a6f93e..ead075d 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -4518,7 +4518,223 @@ ], "packet_available_commands": [ "container", - [] + [ + { + "name": "enum_values", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + }, + { + "name": "suffixes", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + }, + { + "name": "enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values_len", + "type": "varint" + }, + { + "name": "_enum_type", + "type": [ + "enum_size_based_on_values_len" + ] + }, + { + "name": "values", + "type": [ + "array", + { + "count": "values_len", + "type": [ + "switch", + { + "compareTo": "../_enum_type", + "fields": { + "byte": "u8", + "short": "lu16", + "int": "lu32" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "command_data", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "description", + "type": "string" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "permission_level", + "type": "u8" + }, + { + "name": "alias", + "type": "li32" + }, + { + "name": "overloads", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "paramater_name", + "type": "string" + }, + { + "name": "paramater_type", + "type": "li32" + }, + { + "name": "optional", + "type": "bool" + }, + { + "name": "flags", + "type": "CommandFlags" + } + ] + ] + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "dynamic_enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "enum_constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "value_index", + "type": "li32" + }, + { + "name": "enum_index", + "type": "li32" + }, + { + "name": "constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "constraint", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "cheats_enabled" + } + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] ], "packet_command_request": [ "container", @@ -5546,6 +5762,26 @@ { "countType": "li32" } + ], + "CommandFlags": [ + "bitfield", + [ + { + "name": "unused", + "size": 1, + "signed": false + }, + { + "name": "collapse_enum", + "size": 1, + "signed": false + }, + { + "name": "has_semantic_constraint", + "size": 1, + "signed": false + } + ] ] } } \ No newline at end of file diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index 7dc6ea4..7130749 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -1,39 +1,84 @@ const UUID = require('uuid-1345') const minecraft = require('./minecraft') -module.exports = { - Read: { - uuid: ['native', (buffer, offset) => { - return { - value: UUID.stringify(buffer.slice(offset, 16 + offset)), - size: 16 - } - }], - restBuffer: ['native', (buffer, offset) => { - return { - value: buffer.slice(offset), - size: buffer.length - offset - } - }], - nbt: ['native', minecraft.nbt[0]] - }, - Write: { - uuid: ['native', (value, buffer, offset) => { - const buf = UUID.parse(value) - buf.copy(buffer, offset) - return offset + 16 - }], - restBuffer: ['native', (value, buffer, offset) => { - value.copy(buffer, offset) - return offset + value.length - }], - nbt: ['native', minecraft.nbt[1]] - }, - SizeOf: { - uuid: ['native', 16], - restBuffer: ['native', (value) => { - return value.length - }], - nbt: ['native', minecraft.nbt[2]] +const Read = {} +const Write = {} +const SizeOf = {} + +/** + * UUIDs + */ +Read.uuid = ['native', (buffer, offset) => { + return { + value: UUID.stringify(buffer.slice(offset, 16 + offset)), + size: 16 } +}] +Write.uuid = ['native', (value, buffer, offset) => { + const buf = UUID.parse(value) + buf.copy(buffer, offset) + return offset + 16 +}] +SizeOf.uuid = ['native', 16] + +/** + * Rest of buffer + */ +Read.restBuffer = ['native', (buffer, offset) => { + return { + value: buffer.slice(offset), + size: buffer.length - offset + } +}] +Write.restBuffer = ['native', (value, buffer, offset) => { + value.copy(buffer, offset) + return offset + value.length +}] +SizeOf.restBuffer = ['native', (value) => { + return value.length +}] + +/** + * NBT + */ +Read.nbt = ['native', minecraft.nbt[0]] +Write.nbt = ['native', minecraft.nbt[1]] +SizeOf.nbt = ['native', minecraft.nbt[2]] + +/** + * Command Packet + * - used for determining the size of the following enum + */ +Read.enum_size_based_on_values_len = ['parametrizable', (compiler, array) => { + return compiler.wrapCode(js(() => { + if (values_len <= 0xff) return { value: 'byte', size: 0 } + if (values_len <= 0xffff) return { value: 'short', size: 0 } + if (values_len <= 0xffffff) return { value: 'int', size: 0 } + })) +}] +Write.enum_size_based_on_values_len = ['parametrizable', (compiler, array) => { + return str(() => { + if (value.values_len <= 0xff) _enum_type = 'byte' + else if (value.values_len <= 0xffff) _enum_type = 'short' + else if (value.values_len <= 0xffffff) _enum_type = 'int' + return offset + }) +}] +SizeOf.enum_size_based_on_values_len = ['parametrizable', (compiler, array) => { + return str(() => { + if (value.values_len <= 0xff) _enum_type = 'byte' + else if (value.values_len <= 0xffff) _enum_type = 'short' + else if (value.values_len <= 0xffffff) _enum_type = 'int' + return 0 + }) +}] + +function js(fn) { + return fn.toString().split('\n').slice(1, -1).join('\n').trim() } + +function str(fn) { + return fn.toString() + ')();(()=>{}' +} + +module.exports = { Read, Write, SizeOf } \ No newline at end of file diff --git a/test/serialization.js b/test/serialization.js index c7588ca..a15441f 100644 --- a/test/serialization.js +++ b/test/serialization.js @@ -110,8 +110,61 @@ function test() { console.log(JSON.stringify(d)) } + async function availableCommands() { + var avaliable = { + enum_values: ['true', 'false'], + suffixes: ['L'], + enums: [ + { + name: 'Boolean', + values_len: 2, + values: [0, 1] + } + ], + command_data: [ + { + name: 'give', + description: 'Gives you items', + flags: 0, + permission_level: 0, + alias: -1, + overloads: [ + [ + { paramater_name: 'player id', paramater_type: 2, optional: false, flags: { "collapse_enum": 1 } } + ], + [ + { paramater_name: 'item id', paramater_type: 2, optional: false, flags: 0 }, + ] + ], + }, + { + name: 'xp', + description: 'Gives you xp', + flags: 0, permission_level: 0, alias: -1, + overloads: [ + [{ paramater_name: 'player id', paramater_type: 2, optional: false, flags: 0 }] + ] + } + ], + enum_constraints: [ + { + value_index: 2, enum_index: 3, constraints: [ + { constraint: 'cheats_enabled' } + ] + }, + ], + dynamic_enums: [ + { name: 'Hello', values: ['yolo', 'yee'] } + ] + } - creativeTst() + var s = write('available_commands', avaliable) + var d = read(s).data.params + console.log(JSON.stringify(d, null, 2)) + } + + // creativeTst() + availableCommands() } if (!module.parent) { From fe05a3d64546ff97ecb8d0ef8bd7bddaee2ad5dc Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 18 Feb 2021 01:41:00 -0500 Subject: [PATCH 098/458] fix decryption --- src/client/auth.js | 1 - src/transforms/encryption.js | 122 +++++++++++++++++++++++------------ 2 files changed, 79 insertions(+), 44 deletions(-) diff --git a/src/client/auth.js b/src/client/auth.js index bb83897..5502b43 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -36,7 +36,6 @@ async function postAuthenticate (client, options, chains) { client.username = profile.name client.accessToken = chains client.emit('session', profile) - client.connect() } /** diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 26896c4..f911fb2 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -61,7 +61,7 @@ function computeCheckSum(packetPlaintext, sendCounter, secretKeyBytes) { digest.update(packetPlaintext); digest.update(secretKeyBytes); let hash = digest.digest(); - + // console.log('Hash', hash.toString('hex')) return hash.slice(0, 8); } @@ -117,54 +117,90 @@ function createDecryptor(client, iv) { client.decipher = createDecipher(client.secretKeyBytes, iv) client.receiveCounter = client.receiveCounter || 0n - const verifyChecksum = new Transform({ // verify checksum - transform(chunk, encoding, cb) { - console.log('Decryptor: checking checksum', client.receiveCounter, chunk) - const packet = chunk.slice(0, chunk.length - 8); - const checksum = chunk.slice(chunk.length - 8); - const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) - // console.log(computedCheckSum2, computedCheckSum3) - console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') - client.receiveCounter++ + function verify(chunk) { + console.log('Decryptor: checking checksum', client.receiveCounter, chunk) - const inflated = Zlib.inflateRawSync(chunk, { - chunkSize: 1024 * 1024 * 2 - }) + // First try to zlib decompress, then see how much bytes get read + const { buffer, engine } = Zlib.inflateRawSync(chunk, { + chunkSize: 1024 * 1024 * 2, + info: true + }) - if (checksum.toString("hex") == computedCheckSum.toString("hex")) { - this.push(packet) - console.log('🔵 Decriphered', checksum) - - console.log('🔵 Inflated') - client.onDecryptedPacket(inflated) - } else { - console.log(`🔴 Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) - client.onDecryptedPacket(inflated) // allow it anyway - // throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) - } - cb() + // Holds how much bytes we read, also where the checksum (should) start + const inflatedLen = engine.bytesRead + // It appears that mc sends extra bytes past the checksum. I don't think this is a raknet + // issue (as we are able to decipher properly, zlib works and should also have a checksum) so + // there needs to be more investigation done. If you know what's wrong here, please make an issue :) + const extraneousLen = chunk.length - inflatedLen - 8 + if (extraneousLen > 0) { // Extra bytes + // Info for debugging, todo: use debug() + const extraneousBytes = chunk.slice(inflatedLen + 8) + console.debug('Extraneous bytes!', extraneousLen, extraneousBytes.toString('hex')) + } else if (extraneousLen < 0) { + // No checksum or decompression failed + console.warn('Failed to decrypt', chunk.toString('hex')) + throw new Error('Decrypted packet is missing checksum') } + + console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex')) + + const packet = chunk.slice(0, inflatedLen); + const checksum = chunk.slice(inflatedLen, inflatedLen + 8); + console.log("packet, checksum", packet, checksum) + const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) + // // console.log(computedCheckSum2, computedCheckSum3) + // console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') + client.receiveCounter++ + + + // // const infLen = Zlib.inflateRawSync(chunk, { + // // chunkSize: 1024 * 1024 * 2, + // // info: true + // // }) + // console.log('infLen', engine) + + // const cReadLen = engine.bytesRead + // const diff = chunk.length - cReadLen + // const newPacket = chunk.slice(0, cReadLen) + // const newExpectedSum = chunk.slice(cReadLen, cReadLen+8) + // const newComputedChecksum = computeCheckSum(newPacket, client.receiveCounter - 1n, client.secretKeyBytes) + // if (diff > 8) { + // const remaining = chunk.slice(cReadLen + 8) + // console.log('Extraneous bytes:', remaining.toString('hex')) + // const inflated2 = Zlib.inflateRawSync(remaining, { + // // info: true + // }) + // console.log('inflated', inflated2.toString('hex')) + // } + // console.log('New', newExpectedSum, newComputedChecksum) + + // console.log('Decrypted len ', chunk.length, buffer.length, engine.bytesRead) + + if (checksum.toString("hex") == computedCheckSum.toString("hex")) { + console.log('🔵 Inflated') + client.onDecryptedPacket(buffer) + // client.emit('decrypted', inflated) + } else { + console.log(`🔴 Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) + + // const sums = [] + // for (var i = 0n; i < 20n; i++) { + // sums.push(computeCheckSum(packet, i, client.secretKeyBytes).toString('hex')) + // } + // console.log('Tried', sums) + + // client.onDecryptedPacket(inflated) // allow it anyway + // client.emit('decrypted', inflated) + throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) + } + } + + client.decipher.on('data', (buffer) => { + verify(buffer) }) - - client.decipher.pipe(verifyChecksum) - - // Not sure why, but sending two packets to the decryption pipe before - // the other is completed breaks the checksum check. - // TODO: Refactor the logic here to be async so we can await a promise - // queue - let decQ = [] - setInterval(() => { - if (decQ.length) { - let pak = decQ.shift() - console.log('🟡 DECRYPTING', pak) - client.decipher.write(pak) - } - }, 500) - return (blob) => { - decQ.push(blob) - // client.decipher.write(blob) + client.decipher.write(blob) } } From 8db7305eed053a8bfcf45843230b981005f66301 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 18 Feb 2021 01:50:46 -0500 Subject: [PATCH 099/458] move raknet to worker --- src/ConnWorker.js | 64 ++++++++++++++++++++++++++++++ src/client.js | 59 +++++++++++++++++---------- src/connection.js | 32 +++++++++------ src/{ => datatypes}/BatchPacket.js | 0 4 files changed, 121 insertions(+), 34 deletions(-) create mode 100644 src/ConnWorker.js rename src/{ => datatypes}/BatchPacket.js (100%) diff --git a/src/ConnWorker.js b/src/ConnWorker.js new file mode 100644 index 0000000..f6d38d3 --- /dev/null +++ b/src/ConnWorker.js @@ -0,0 +1,64 @@ +const RakClient = require('@jsprismarine/raknet/client') +const { Worker, isMainThread, parentPort } = require('worker_threads') +const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') + +function connect(hostname, port) { + if (isMainThread) { + const worker = new Worker(__filename) + worker.postMessage({ type: 'connect', hostname, port }) + return worker + } +} + +var raknet + +function main() { + parentPort.on('message', (evt) => { + if (evt.type == 'connect') { + console.warn('-------- ', evt) + const { hostname, port } =evt + raknet = new RakClient(hostname, port) + + raknet.connect().then(() => { + console.log('Raknet Connected!') + }) + + raknet.on('connecting', () => { + console.log(`[client] connecting to ${hostname}/${port}`) + parentPort.postMessage('message', { type: 'connecting' }) + console.log('Raknet', raknet) + }) + + raknet.once('connected', (connection) => { + console.log(`[worker] connected!`) + globalThis.raknetConnection = connection + parentPort.postMessage({ type: 'connected' }) + }) + + raknet.on('encapsulated', (...args) => { + // console.log('-> ENCAP BUF', args) + setTimeout(() => { + parentPort.postMessage({ type: 'encapsulated', args }) + }, 100) + }) + + raknet.on('raw', (buffer, inetAddr) => { + console.log('Raw packet', buffer, inetAddr) + }) + } else if (evt.type == 'queueEncapsulated') { + console.log('SEND' , globalThis.raknetConnection, evt.packet) + + const sendPacket = new EncapsulatedPacket() + sendPacket.reliability = 0 + sendPacket.buffer = evt.packet + + globalThis.raknetConnection?.addEncapsulatedToQueue(sendPacket) + if (evt.immediate) { + globalThis.raknetConnection?.sendQueue() + } + } + }) +} + +if (!isMainThread) main() +module.exports = { connect } \ No newline at end of file diff --git a/src/client.js b/src/client.js index 8d21ead..b7b2ed5 100644 --- a/src/client.js +++ b/src/client.js @@ -1,12 +1,14 @@ const RakClient = require('@jsprismarine/raknet/client') const { Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') +const ConnWorker = require('./ConnWorker') const { Encrypt } = require('./auth/encryption') const auth = require('./client/auth') const Options = require('./options') const fs = require('fs') const log = console.log +const useWorkers = true class Client extends Connection { constructor(options) { @@ -25,6 +27,7 @@ class Client extends Connection { } this.on('session', this.connect) + // this.on('decrypted', this.onDecryptedPacket) } validateOptions() { @@ -35,32 +38,46 @@ class Client extends Connection { onEncapsulated = (encapsulated, inetAddr) => { // log(inetAddr.address, ': Encapsulated', encapsulated) - const buffer = encapsulated.buffer + const buffer = Buffer.from(encapsulated.buffer) this.handle(buffer) } connect = async (sessionData) => { - console.log('Got session data', sessionData) + if (useWorkers) { + this.worker = ConnWorker.connect('127.0.0.1', 19132) + this.worker.on('message', (evt) => { + switch (evt.type) { + case 'connected': + this.sendLogin() + break + case 'encapsulated': + this.onEncapsulated(...evt.args) + break + } + }) - if (this.raknet) return + } else { + if (this.raknet) return - this.raknet = new RakClient('127.0.0.1', 19132) - await this.raknet.connect() + this.raknet = new RakClient('127.0.0.1', 19132) + await this.raknet.connect() - this.raknet.on('connecting', () => { - // console.log(`[client] connecting to ${hostname}/${port}`) - }) - this.raknet.on('connected', (connection) => { - console.log(`[client] connected!`) - this.connection = connection - this.sendLogin() - }) + this.raknet.on('connecting', () => { + // console.log(`[client] connecting to ${hostname}/${port}`) + }) + this.raknet.on('connected', (connection) => { + console.log(`[client] connected!`) + this.connection = connection + this.sendLogin() + }) - this.raknet.on('encapsulated', this.onEncapsulated) + this.raknet.on('encapsulated', this.onEncapsulated) + + this.raknet.on('raw', (buffer, inetAddr) => { + console.log('Raw packet', buffer, inetAddr) + }) + } - this.raknet.on('raw', (buffer, inetAddr) => { - console.log('Raw packet', buffer, inetAddr) - }) } sendLogin() { @@ -104,7 +121,7 @@ class Client extends Connection { readPacket(packet) { // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) - console.log('->',des) + console.log('->', des) const pakData = { name: des.data.name, params: des.data.params } // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) switch (des.data.name) { @@ -115,12 +132,12 @@ class Client extends Connection { this.onDisconnectRequest(des.data.params) break case 'crafting_data': - fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k,v) => typeof v == 'bigint' ? v.toString() : v)) + fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) break case 'start_game': - fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k,v) => typeof v == 'bigint' ? v.toString() : v)) + fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) default: - // console.log('Sending to listeners') + // console.log('Sending to listeners') } this.emit(des.data.name, des.data.params) diff --git a/src/connection.js b/src/connection.js index f266ebf..58a51c8 100644 --- a/src/connection.js +++ b/src/connection.js @@ -1,5 +1,5 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default -const BatchPacket = require('./BatchPacket') +const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') @@ -48,12 +48,7 @@ class Connection extends EventEmitter { sendDecryptedBatch(batch) { const buf = batch.encode() // send to raknet - const sendPacket = new EncapsulatedPacket(); - sendPacket.reliability = 0; - sendPacket.buffer = buf - - this.connection.addEncapsulatedToQueue(sendPacket) - this.connection.sendQueue() + this.sendMCPE(buf, true) } sendEncryptedBatch(batch) { @@ -62,15 +57,26 @@ class Connection extends EventEmitter { this.encrypt(buf) } + sendMCPE(buffer, immediate) { + if (this.worker) { + console.log('-> buf', buffer) + this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) + } else { + const sendPacket = new EncapsulatedPacket(); + sendPacket.reliability = 0 + sendPacket.buffer = buffer + this.connection.addEncapsulatedToQueue(sendPacket) + if (immediate) this.connection.sendQueue() + } + } + // These are callbacks called from encryption.js onEncryptedPacket = (buf) => { console.log('ENC BUF', buf) const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header - const sendPacket = new EncapsulatedPacket(); - sendPacket.reliability = 0 - sendPacket.buffer = packet + console.log('Sending wrapped encrypted batch', packet) - this.connection.addEncapsulatedToQueue(sendPacket) + this.sendMCPE(packet) } onDecryptedPacket = (buf) => { @@ -87,7 +93,7 @@ class Connection extends EventEmitter { handle(buffer) { // handle encapsulated if (buffer[0] == 0xfe) { // wrapper if (this.encryptionEnabled) { - console.log('Reading encrypted packet', buffer) + console.trace('Reading encrypted packet', buffer.toString('hex')) this.decrypt(buffer.slice(1)) } else { const stream = new BinaryStream(buffer) @@ -100,7 +106,7 @@ class Connection extends EventEmitter { } } } - console.log('[client] procesed ', buffer) + console.log('[client] handled incoming ', buffer) } } diff --git a/src/BatchPacket.js b/src/datatypes/BatchPacket.js similarity index 100% rename from src/BatchPacket.js rename to src/datatypes/BatchPacket.js From 0ed5a8d0611cf289074fab7dece791b14b313f40 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 18 Feb 2021 13:30:19 -0500 Subject: [PATCH 100/458] protocol updates, packet dumping --- .gitignore | 5 ++- data/new/proto.yml | 58 ++++++++++++++++--------- data/newproto.json | 81 +++++++++++++++++++++++++---------- src/client.js | 17 ++++++-- src/clientTest.js | 2 +- src/connection.js | 5 +-- src/{ => old}/createClient.js | 0 src/{ => old}/createServer.js | 0 src/transforms/encryption.js | 50 ++------------------- test/serialization.js | 12 +++++- 10 files changed, 131 insertions(+), 99 deletions(-) rename src/{ => old}/createClient.js (100%) rename src/{ => old}/createServer.js (100%) diff --git a/.gitignore b/.gitignore index 570a59b..4f37984 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ node_modules/ npm-debug.log __* -data/*.js \ No newline at end of file +data/*.js +src/**/*.json +src/*.txt +dist/ \ No newline at end of file diff --git a/data/new/proto.yml b/data/new/proto.yml index b24839e..3440313 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -240,7 +240,7 @@ packet_start_game: # Specifies if the world has education edition features enabled, such as the blocks or entities # specific to education edition. has_edu_features_enabled: bool - edu_product_uuid_: string + edu_product_uuid: string # The level specifying the Intensity of the rain falling. When set to 0, no rain falls at all. rain_level: lf32 lightning_level: lf32 @@ -306,7 +306,7 @@ packet_start_game: game_version: string limited_world_width: li32 limited_world_length: li32 - is_new_nether_: bool + is_new_nether: bool experimental_gameplay_override: bool # A base64 encoded world ID that is used to identify the world. level_id: string @@ -820,7 +820,7 @@ packet_player_hotbar: !bound: both selected_slot: varint window_id: u8 - select_slot_: bool + select_slot: bool packet_inventory_content: !id: 0x31 @@ -1020,8 +1020,15 @@ packet_show_credits: packet_available_commands: !id: 0x4c !bound: client + # The length of the enums for all the command paramaters in this packet + values_len: varint + # Not read from stream: instead calculated from the `values_len` field + # If the values_len < 0xff => byte + # If the values_len < 0xffff => short + # If the values_len < 0xffffff => int + _enum_type: '["enum_size_based_on_values_len"]' # Here all the enum values for all of the possible commands are stored to one array palette - enum_values: string[]varint + enum_values: string[]$values_len # Integer paramaters may sometimes have a prefix, such as the XP command: # /xp [player: target] <- here, the xp command gives experience points # /xp L [player: target] <- here, the xp command gives experience levels @@ -1031,15 +1038,8 @@ packet_available_commands: enums: []varint # The name of the enum name: string - # The length of the array below - values_len: varint - # Not read from stream: instead calculated from the `values_len` field - # If the values_len < 0xff => byte - # If the values_len < 0xffff => short - # If the values_len < 0xffffff => int - _enum_type: '["enum_size_based_on_values_len"]' # The values in the enum - values: []$values_len + values: []varint # The indexes to value in the palette _: ../_enum_type? if byte: u8 @@ -1056,15 +1056,31 @@ packet_available_commands: # Each of the paramaters gets an array of posible overloads _: []varint # The name of the paramater shown to the user (the `amount` in `/xp `) - paramater_name: string - # Bitfield: If FLAG_ENUM is set, the lower 16 bits act as an index to enums array - # If FLAG_SUFFIX is set, the lower 16 bits act as an index to the suffix palette - # and the client interperts the type as just `int` as in the example above - paramater_type: li32 + paramater_name: string + value_type: lu16 => + 1: int + 2: float + 3: value + 4: wildcard_int + 5: operator + 6: target + 14: file_path + 29: string + 37: position + 41: message + 43: raw_text + 46: json + 53: command + # In MC, this + prior field are combined to one 32bit bitfield + enum_type: lu16 => + 0x10: valid + 0x20: enum + 0x100: suffixed + 0x400: soft_enum # Is this paramater required? optional: bool # Additinal options for this command (thanks macroshaft...) - flags: CommandFlags + options: CommandFlags # There are two types of enums: static enums which cannot be changed after sending AvaliableCommands, # (unless you resend the whole packet) and 'soft' or 'dynamic' enums like below which is an array # that can be updated with the UpdateSoftEnum packet @@ -1084,9 +1100,9 @@ packet_available_commands: # with enums that have a big amount of options. To illustrate, it can make # <$Name: bool>. CommandFlags: [ "bitfield", [ - { "name": "unused", "size": 1, "signed": false }, - { "name": "collapse_enum", "size": 1, "signed": false }, - { "name": "has_semantic_constraint", "size": 1, "signed": false } + { "name": "unused", "size": 6, "signed": false }, # 6 unused upper bits + { "name": "has_semantic_constraint", "size": 1, "signed": false }, + { "name": "collapse_enum", "size": 1, "signed": false } ]] # enum_size_based_on_values_len: native diff --git a/data/newproto.json b/data/newproto.json index ead075d..6be7328 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -2912,7 +2912,7 @@ "type": "bool" }, { - "name": "edu_product_uuid_", + "name": "edu_product_uuid", "type": "string" }, { @@ -3020,7 +3020,7 @@ "type": "li32" }, { - "name": "is_new_nether_", + "name": "is_new_nether", "type": "bool" }, { @@ -4060,7 +4060,7 @@ "type": "u8" }, { - "name": "select_slot_", + "name": "select_slot", "type": "bool" } ] @@ -4519,12 +4519,22 @@ "packet_available_commands": [ "container", [ + { + "name": "values_len", + "type": "varint" + }, + { + "name": "_enum_type", + "type": [ + "enum_size_based_on_values_len" + ] + }, { "name": "enum_values", "type": [ "array", { - "countType": "varint", + "count": "values_len", "type": "string" } ] @@ -4552,22 +4562,12 @@ "name": "name", "type": "string" }, - { - "name": "values_len", - "type": "varint" - }, - { - "name": "_enum_type", - "type": [ - "enum_size_based_on_values_len" - ] - }, { "name": "values", "type": [ "array", { - "count": "values_len", + "countType": "varint", "type": [ "switch", { @@ -4635,15 +4635,50 @@ "type": "string" }, { - "name": "paramater_type", - "type": "li32" + "name": "value_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "1": "int", + "2": "float", + "3": "value", + "4": "wildcard_int", + "5": "operator", + "6": "target", + "14": "file_path", + "29": "string", + "37": "position", + "41": "message", + "43": "raw_text", + "46": "json", + "53": "command" + } + } + ] + }, + { + "name": "enum_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "16": "valid", + "32": "enum", + "256": "suffixed", + "1024": "soft_enum" + } + } + ] }, { "name": "optional", "type": "bool" }, { - "name": "flags", + "name": "options", "type": "CommandFlags" } ] @@ -5768,6 +5803,11 @@ [ { "name": "unused", + "size": 6, + "signed": false + }, + { + "name": "has_semantic_constraint", "size": 1, "signed": false }, @@ -5775,11 +5815,6 @@ "name": "collapse_enum", "size": 1, "signed": false - }, - { - "name": "has_semantic_constraint", - "size": 1, - "signed": false } ] ] diff --git a/src/client.js b/src/client.js index b7b2ed5..bd2da33 100644 --- a/src/client.js +++ b/src/client.js @@ -1,10 +1,11 @@ -const RakClient = require('@jsprismarine/raknet/client') +const RakClient = require('jsp-raknet/client') const { Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') const ConnWorker = require('./ConnWorker') const { Encrypt } = require('./auth/encryption') const auth = require('./client/auth') const Options = require('./options') +const debug = require('debug')('minecraft-protocol') const fs = require('fs') const log = console.log @@ -93,7 +94,7 @@ class Client extends Connection { const bodyLength = this.clientUserChain.length + encodedChain.length + 8 - console.log('Auth chain', chain) + debug('Auth chain', chain) this.write('login', { protocol_version: this.options.version, @@ -121,9 +122,15 @@ class Client extends Connection { readPacket(packet) { // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) - console.log('->', des) const pakData = { name: des.data.name, params: des.data.params } + console.log('->', pakData.name, serialize(pakData.params).slice(0, 100)) // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) + try { + if (!fs.existsSync(`./packets/${pakData.name}.json`)) { + fs.writeFileSync(`./packets/${pakData.name}.json`, serialize(pakData.params, 2)) + fs.writeFileSync(`./packets/${pakData.name}.txt`, packet.toString('hex')) + } + } catch {} switch (des.data.name) { case 'server_to_client_handshake': this.emit('client.server_handshake', des.data.params) @@ -144,4 +151,8 @@ class Client extends Connection { } } +function serialize(obj = {}, fmt) { + return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) +} + module.exports = { Client } \ No newline at end of file diff --git a/src/clientTest.js b/src/clientTest.js index d0ba45f..39bb310 100644 --- a/src/clientTest.js +++ b/src/clientTest.js @@ -1,4 +1,4 @@ -process.env.DEBUG = 'minecraft-protocol raknet' +// process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('./client') // console.log = () => diff --git a/src/connection.js b/src/connection.js index 58a51c8..1ecbee2 100644 --- a/src/connection.js +++ b/src/connection.js @@ -80,7 +80,7 @@ class Connection extends EventEmitter { } onDecryptedPacket = (buf) => { - console.log('🟢 Decrypted', buf) + // console.log('🟢 Decrypted', buf) const stream = new BinaryStream(buf) const packets = BatchPacket.getPackets(stream) @@ -93,7 +93,6 @@ class Connection extends EventEmitter { handle(buffer) { // handle encapsulated if (buffer[0] == 0xfe) { // wrapper if (this.encryptionEnabled) { - console.trace('Reading encrypted packet', buffer.toString('hex')) this.decrypt(buffer.slice(1)) } else { const stream = new BinaryStream(buffer) @@ -106,7 +105,7 @@ class Connection extends EventEmitter { } } } - console.log('[client] handled incoming ', buffer) + // console.log('[client] handled incoming ', buffer) } } diff --git a/src/createClient.js b/src/old/createClient.js similarity index 100% rename from src/createClient.js rename to src/old/createClient.js diff --git a/src/createServer.js b/src/old/createServer.js similarity index 100% rename from src/createServer.js rename to src/old/createServer.js diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index f911fb2..670d8a9 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -74,7 +74,7 @@ function createEncryptor(client, iv) { const addChecksum = new Transform({ // append checksum transform(chunk, enc, cb) { - console.log('Encryptor: checking checksum', chunk) + // console.log('Encryptor: checking checksum', chunk) // Here we concat the payload + checksum before the encryption const packet = Buffer.concat([chunk, computeCheckSum(chunk, client.sendCounter, client.secretKeyBytes)]) client.sendCounter++ @@ -118,7 +118,7 @@ function createDecryptor(client, iv) { client.receiveCounter = client.receiveCounter || 0n function verify(chunk) { - console.log('Decryptor: checking checksum', client.receiveCounter, chunk) + // console.log('Decryptor: checking checksum', client.receiveCounter, chunk) // First try to zlib decompress, then see how much bytes get read const { buffer, engine } = Zlib.inflateRawSync(chunk, { @@ -142,62 +142,20 @@ function createDecryptor(client, iv) { throw new Error('Decrypted packet is missing checksum') } - console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex')) - const packet = chunk.slice(0, inflatedLen); const checksum = chunk.slice(inflatedLen, inflatedLen + 8); - console.log("packet, checksum", packet, checksum) const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) - // // console.log(computedCheckSum2, computedCheckSum3) - // console.assert(checksum.toString("hex") == computedCheckSum.toString("hex"), 'checksum mismatch') client.receiveCounter++ - - // // const infLen = Zlib.inflateRawSync(chunk, { - // // chunkSize: 1024 * 1024 * 2, - // // info: true - // // }) - // console.log('infLen', engine) - - // const cReadLen = engine.bytesRead - // const diff = chunk.length - cReadLen - // const newPacket = chunk.slice(0, cReadLen) - // const newExpectedSum = chunk.slice(cReadLen, cReadLen+8) - // const newComputedChecksum = computeCheckSum(newPacket, client.receiveCounter - 1n, client.secretKeyBytes) - // if (diff > 8) { - // const remaining = chunk.slice(cReadLen + 8) - // console.log('Extraneous bytes:', remaining.toString('hex')) - // const inflated2 = Zlib.inflateRawSync(remaining, { - // // info: true - // }) - // console.log('inflated', inflated2.toString('hex')) - // } - // console.log('New', newExpectedSum, newComputedChecksum) - - // console.log('Decrypted len ', chunk.length, buffer.length, engine.bytesRead) - if (checksum.toString("hex") == computedCheckSum.toString("hex")) { - console.log('🔵 Inflated') client.onDecryptedPacket(buffer) - // client.emit('decrypted', inflated) } else { - console.log(`🔴 Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) - - // const sums = [] - // for (var i = 0n; i < 20n; i++) { - // sums.push(computeCheckSum(packet, i, client.secretKeyBytes).toString('hex')) - // } - // console.log('Tried', sums) - - // client.onDecryptedPacket(inflated) // allow it anyway - // client.emit('decrypted', inflated) + console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex')) throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) } } - client.decipher.on('data', (buffer) => { - verify(buffer) - }) + client.decipher.on('data', verify) return (blob) => { client.decipher.write(blob) diff --git a/test/serialization.js b/test/serialization.js index a15441f..8250f14 100644 --- a/test/serialization.js +++ b/test/serialization.js @@ -1,3 +1,4 @@ +const fs = require('fs') const { createDeserializer, createSerializer } = require('../src/transforms/serializer') function test() { @@ -163,8 +164,17 @@ function test() { console.log(JSON.stringify(d, null, 2)) } + async function avaliableCmd() { + const buffer = Buffer.from(fs.readFileSync('./serialization/available_commands.txt', 'utf8'), 'hex') + const readed = read(buffer) + const recipes = readed.data.params.enums + console.log('read', recipes) + fs.writeFileSync('commands.json', JSON.stringify(readed.data,null,2)) + } + // creativeTst() - availableCommands() + // availableCommands() + // avaliableCmd() } if (!module.parent) { From 8c409108093b7addbf70cf181df318ceb2aa12f7 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 20 Feb 2021 01:08:38 -0500 Subject: [PATCH 101/458] protocol updates --- data/new/proto.yml | 222 ++++++++++++++++++++--- data/new/types.yaml | 78 ++++---- data/newproto.json | 424 ++++++++++++++++++++++++++++++++------------ 3 files changed, 554 insertions(+), 170 deletions(-) diff --git a/data/new/proto.yml b/data/new/proto.yml index 3440313..6bbb0d5 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -230,7 +230,7 @@ packet_start_game: # Defines if achievements are disabled in the world. The client crashes if this value is set # to true while the player's or the world's game mode is creative, and it's recommended to simply # always set this to false as a server. - has_achievements_disabled: bool + achievements_disabled: bool # The time at which the day cycle was locked if the day cycle is disabled using the respective # game rule. The client will maIntain this time as Boolean as the day cycle is disabled. day_cycle_stop_time: zigzag32 @@ -239,7 +239,7 @@ packet_start_game: edu_offer: zigzag32 # Specifies if the world has education edition features enabled, such as the blocks or entities # specific to education edition. - has_edu_features_enabled: bool + edu_features_enabled: bool edu_product_uuid: string # The level specifying the Intensity of the rain falling. When set to 0, no rain falls at all. rain_level: lf32 @@ -459,7 +459,7 @@ packet_move_player: packet_rider_jump: !id: 0x14 !bound: both - unknown: zigzag32 + jump_strength: zigzag32 packet_update_block: !id: 0x15 @@ -765,13 +765,12 @@ packet_set_entity_motion: runtime_entity_id: varint velocity: vec3f +# SetActorLink is sent by the server to initiate an entity link client-side, meaning one entity will start +# riding another. packet_set_entity_link: !id: 0x29 !bound: client - ridden_id: zigzag64 - rider_id: zigzag64 - link_type: u8 - unknown: u8 + link: Link packet_set_health: !id: 0x2a @@ -781,10 +780,12 @@ packet_set_health: packet_set_spawn_position: !id: 0x2b !bound: client - spawn_type: zigzag32 - coordinates: BlockCoordinates + spawn_type: zigzag32 => + 0: player + 1: world + player_position: BlockCoordinates dimension: zigzag32 - unknown_coordinates: BlockCoordinates + world_position: BlockCoordinates packet_animate: !id: 0x2c @@ -888,13 +889,37 @@ packet_player_input: jumping: bool sneaking: bool + +# LevelChunk is sent by the server to provide the client with a chunk of a world data (16xYx16 blocks). +# Typically a certain amount of chunks is sent to the client before sending it the spawn PlayStatus packet, +# so that the client spawns in a loaded world. packet_level_chunk: !id: 0x3a !bound: client + # ChunkX is the X coordinate of the chunk sent. (To translate a block's X to a chunk's X: x >> 4) x: zigzag32 + # ChunkZ is the Z coordinate of the chunk sent. (To translate a block's Z to a chunk's Z: z >> 4) z: zigzag32 + # SubChunkCount is the amount of sub chunks that are part of the chunk sent. Depending on if the cache + # is enabled, a list of blob hashes will be sent, or, if disabled, the sub chunk data. sub_chunk_count: varint - column: Chunks + # CacheEnabled specifies if the client blob cache should be enabled. This system is based on hashes of + # blobs which are consistent and saved by the client in combination with that blob, so that the server + # does not have to send the same chunk multiple times. If the client does not yet have a blob with the hash sent, + # it will send a ClientCacheBlobStatus packet containing the hashes is does not have the data of. + cache_enabled: bool + blobs: cache_enabled? + if true: + # BlobHashes is a list of all blob hashes used in the chunk. It is composed of SubChunkCount + 1 hashes, + # with the first SubChunkCount hashes being those of the sub chunks and the last one that of the biome + # of the chunk. + # If CacheEnabled is set to false, BlobHashes can be left empty. + hashes: lu64[]varint + # RawPayload is a serialised string of chunk data. The data held depends on if CacheEnabled is set to + # true. If set to false, the payload is composed of multiple sub-chunks, each of which carry a version + # which indicates the way they are serialised, followed by biomes, border blocks and tile entities. If + # CacheEnabled is true, the payload consists out of the border blocks and tile entities only. + payload: string packet_set_commands_enabled: !id: 0x3b @@ -964,11 +989,17 @@ packet_game_rules_changed: !bound: client rules: GameRules +# Camera is sent by the server to use an Education Edition camera on a player. It produces an image +# client-side. packet_camera: !id: 0x49 !bound: client - unknown1: zigzag64 - unknown2: zigzag64 + # CameraEntityUniqueID is the unique ID of the camera entity from which the picture was taken. + camera_entity_unique_id: zigzag64 + # TargetPlayerUniqueID is the unique ID of the target player. The unique ID is a value that remains + # consistent across different sessions of the same world, but most servers simply fill the runtime ID of + # the player out for this field. + target_player_unique_id: zigzag64 packet_boss_event: !id: 0x4a @@ -1071,6 +1102,97 @@ packet_available_commands: 43: raw_text 46: json 53: command + # 15: unknown15 + # 16: unknown16 + # 125: unknown125 + # 126: unknown126 + # 22: unknown22 + # 10: unknown10 + # 39: unknown39 + # 18: unknown18 + # 20: unknown20 + # 19: unknown19 + # 7: unknown7 + # 23: unknown23 + # 24: unknown24 + # 13: unknown13 + # 25: unknown25 + # 40: unknown40 + # 56: unknown56 + # 26: unknown26 + # 27: unknown27 + # 28: unknown28 + # 31: unknown31 + # 30: unknown30 + # 0: unknown0 + # 32: unknown32 + # 49: unknown49 + # 12: unknown12 + # 35: unknown35 + # 36: unknown36 + # 38: unknown38 + # 44: unknown44 + # 47: unknown47 + # 45: unknown45 + # 48: unknown48 + # 55: unknown55 + # 54: unknown54 + # 50: unknown50 + # 51: unknown51 + # 52: unknown52 + # 9: unknown9 + # 123: unknown123 + # 57: unknown57 + # 58: unknown58 + # 59: unknown59 + # 60: unknown60 + # 61: unknown61 + # 63: unknown63 + # 75: unknown75 + # 64: unknown64 + # 67: unknown67 + # 66: unknown66 + # 73: unknown73 + # 72: unknown72 + # 74: unknown74 + # 62: unknown62 + # 68: unknown68 + # 69: unknown69 + # 65: unknown65 + # 70: unknown70 + # 71: unknown71 + # 76: unknown76 + # 77: unknown77 + # 79: unknown79 + # 78: unknown78 + # 80: unknown80 + # 81: unknown81 + # 82: unknown82 + # 83: unknown83 + # 84: unknown84 + # 87: unknown87 + # 88: unknown88 + # 92: unknown92 + # 89: unknown89 + # 90: unknown90 + # 91: unknown91 + # 93: unknown93 + # 95: unknown95 + # 94: unknown94 + # 98: unknown98 + # 96: unknown96 + # 97: unknown97 + # 99: unknown99 + # 100: unknown100 + # 101: unknown101 + # 102: unknown102 + # 103: unknown103 + # 104: unknown104 + # 105: unknown105 + # 106: unknown106 + # 107: unknown107 + # 108: unknown108 + # 124: unknown124 # In MC, this + prior field are combined to one 32bit bitfield enum_type: lu16 => 0x10: valid @@ -1159,28 +1281,64 @@ packet_command_output: paramaters: string[]varint +# UpdateTrade is sent by the server to update the trades offered by a villager to a player. It is sent at the +# moment that a player interacts with a villager. packet_update_trade: !id: 0x50 !bound: client + # WindowID is the ID that identifies the trading window that the client currently has opened. window_id: u8 + # WindowType is an identifier specifying the type of the window opened. In vanilla, it appears this is + # always filled out with 15. window_type: u8 - unknown0: varint - unknown1: varint - unknown2: varint - is_willing: bool - trader_entity_id: zigzag64 - player_entity_id: zigzag64 + # Size is the amount of trading options that the villager has. + size: varint + # TradeTier is the tier of the villager that the player is trading with. The tier starts at 0 with a + # first two offers being available, after which two additional offers are unlocked each time the tier + # becomes one higher. + trade_tier: varint + # VillagerUniqueID is the unique ID of the villager entity that the player is trading with. The + # TradeTier sent above applies to this villager. + villager_unique_id: varint64 + # EntityUniqueID is the unique ID of the entity (usually a player) for which the trades are updated. The + # updated trades may apply only to this entity. + entity_unique_id: varint64 + # DisplayName is the name displayed at the top of the trading UI. It is usually used to represent the + # profession of the villager in the UI. display_name: string - nbt: nbt + # NewTradeUI specifies if the villager should be using the new trade UI (The one added in 1.11.) rather + # than the old one. This should usually be set to true. + new_trading_ui: bool + # Trading based on Minecraft economy - specifies if the prices of the villager's offers are modified by an increase in + # demand for the item. (A mechanic added in 1.11.) Buying more of the same item will increase the price + # of that particular item. + # https://minecraft.gamepedia.com/Trading#Economics + economic_trades: bool + # NBT serialised compound of offers that the villager has. + offers: nbt +# UpdateEquip is sent by the server to the client upon opening a horse inventory. It is used to set the +# content of the inventory and specify additional properties, such as the items that are allowed to be put +# in slots of the inventory. packet_update_equipment: !id: 0x51 !bound: client + # WindowID is the identifier associated with the window that the UpdateEquip packet concerns. It is the + # ID sent for the horse inventory that was opened before this packet was sent. window_id: u8 + # WindowType is the type of the window that was opened. Generally, this is the type of a horse inventory, + # as the packet is specifically made for that. window_type: u8 - unknown: u8 + # Size is the size of the horse inventory that should be opened. A bigger size does, in fact, change the + # amount of slots displayed. + size: u8 + # EntityUniqueID is the unique ID of the entity whose equipment was 'updated' to the player. It is + # typically the horse entity that had its inventory opened. entity_id: zigzag64 - nbt: nbt + # `inventory` is a network NBT serialised compound holding the content of the inventory of + # the entity (the equipment) and additional data such as the allowed items for a particular slot, used to + # make sure only saddles can be put in the saddle slot etc. + inventory: nbt packet_resource_pack_data_info: !id: 0x52 @@ -1508,19 +1666,35 @@ packet_update_block_properties: !bound: client nbt: nbt +# ClientCacheBlobStatus is part of the blob cache protocol. It is sent by the client to let the server know +# what blobs it needs and which blobs it already has, in an ACK type system. packet_client_cache_blob_status: !id: 0x87 !bound: client + # A list of blob hashes that the client does not have a blob available for. The server + # should send the blobs matching these hashes as soon as possible. + missing: lu64[]varint + # A list of hashes that the client does have a cached blob for. Server doesn't need to send. + have: lu64[]varint +# ClientCacheMissResponse is part of the blob cache protocol. It is sent by the server in response to a +# ClientCacheBlobStatus packet and contains the blob data of all blobs that the client acknowledged not to +# have yet. packet_client_cache_miss_response: !id: 0x88 !bound: client + blobs: Blob[]varint + +# NetworkSettings is sent by the server to update a variety of network settings. These settings modify the +# way packets are sent over the network stack. packet_network_settings: !id: 0x8f !bound: both - unknown: u8 - compression_threshold: u8 + # CompressionThreshold is the minimum size of a packet that is compressed when sent. If the size of a + # packet is under this value, it is not compressed. + # When set to 0, all packets will be left uncompressed. + compression_threshold: u16 packet_creative_content: !id: 0x91 diff --git a/data/new/types.yaml b/data/new/types.yaml index 528a0ba..a0835b1 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -48,12 +48,15 @@ GameRule: GameRules: GameRule[]varint -Chunks: - cache_enabled: bool - _: cache_enabled? - if true: void # TODO - if false: void - +# CacheBlob represents a blob as used in the client side blob cache protocol. It holds a hash of its data and +# the full data of it. +Blob: + # Hash is the hash of the blob. The hash is computed using xxHash, and must be deterministic for the same + # chunk data. + hash: lu64 + # Payload is the data of the blob. When sent, the client will associate the Hash of the blob with the + # Payload in it. + payload: string BlockPalette: []varint name: string @@ -245,13 +248,15 @@ MetadataDictionary: []varint if long: zigzag64 if vec3f: vec3f -Links: []varint +Link: ridden_entity_id: zigzag64 rider_entity_id: zigzag64 type: u8 immediate: bool rider_initiated: bool +Links: Link[]varint + EntityAttributes: []varint name: string min: lf32 @@ -276,7 +281,16 @@ PlayerAttributes: []varint name: string Transaction: + # LegacyRequestID is an ID that is only non-zero at times when sent by the client. The server should + # always send 0 for this. When this field is not 0, the LegacySetItemSlots slice below will have values + # in it. + # LegacyRequestID ties in with the ItemStackResponse packet. If this field is non-0, the server should + # respond with an ItemStackResponse packet. Some inventory actions such as dropping an item out of the + # hotbar are still one using this packet, and the ItemStackResponse packet needs to tie in with it. legacy_request_id: zigzag32 + # `legacy_transactions` are only present if the LegacyRequestID is non-zero. These item slots inform the + # server of the slots that were changed during the inventory transaction, and the server should send + # back an ItemStackResponse packet with these slots present in it. (Or false with no slots, if rejected.) legacy_transactions: legacy_request_id? if 0: void default: []varint @@ -284,37 +298,37 @@ Transaction: changed_slots: []varint slot_id: u8 transaction_type: varint => - 0: TYPE_NORMAL - 1: TYPE_INVENTORY_MISMATCH - 2: TYPE_ITEM_USE - 3: TYPE_ITEM_USE_ON_ENTITY - 4: TYPE_ITEM_RELEASE - has_network_ids: bool + 0: normal + 1: inventory_mismatch + 2: item_use + 3: item_use_on_entity + 4: item_release + network_ids: bool inventory_actions: []varint source_type: varint => - "0": "INV_SOURCE_TYPE_CONTAINER" - "1": "INV_SOURCE_TYPE_GLOBAL" - "2": "INV_SOURCE_TYPE_WORLD_INTERACTION" - "3": "INV_SOURCE_TYPE_CREATIVE" - "100": "INV_SOURCE_TYPE_CRAFT_SLOT" - "99999": "INV_SOURCE_TYPE_CRAFT" + 0: container + 1: global + 2: world_interaction + 3: creative + 100: craft_slot + 99999: craft _: source_type? - if INV_SOURCE_TYPE_CONTAINER or INV_SOURCE_TYPE_CREATIVE: + if container or creative: inventory_id: varint - if INV_SOURCE_TYPE_WORLD_INTERACTION: + if world_interaction: flags: varint - if INV_SOURCE_TYPE_CRAFT or INV_SOURCE_TYPE_CRAFT_SLOT: + if craft or craft_slot: action: varint default: void slot: varint old_item: Item new_item: Item - new_item_stack_id: ../has_network_ids? + new_item_stack_id: ../network_ids? if true: zigzag32 default: void transaction_data: transaction_type? - if TYPE_NORMAL or TYPE_INVENTORY_MISMATCH: void - if TYPE_ITEM_USE: + if normal or inventory_mismatch: void + if item_use: action_type: varint face: varint hotbar_slot: varint @@ -322,14 +336,14 @@ Transaction: player_pos: vec3f click_pos: vec3f block_runtime_id: varint - if TYPE_ITEM_USE_ON_ENTITY: + if item_use_on_entity: entity_runtime_id: varint64 action_type: varint hotbar_slot: zigzag32 item_in_hand: Item player_pos: vec3f click_pos: vec3f - if TYPE_ITEM_RELEASE: + if item_release: action_type: varint hotbar_slot: zigzag32 item_in_hand: Item @@ -369,11 +383,11 @@ Recipes: []varint # `furnace`, except it has an input item with a specific metadata value, instead of any metadata value. '3': 'furnace_with_metadata' # 'ENTRY_FURNACE_DATA', // has metadata '4': 'multi' #'ENTRY_MULTI', //TODO - '5': 'shapeless' #'ENTRY_SHULKER_BOX', //TODO - '6': 'shapeless' #'ENTRY_SHAPELESS_CHEMISTRY', //TODO - '7': 'shaped' #'ENTRY_SHAPED_CHEMISTRY', //TODO + '5': 'shulker_box' #'ENTRY_SHULKER_BOX', //TODO + '6': 'shapeless_chemistry' #'ENTRY_SHAPELESS_CHEMISTRY', //TODO + '7': 'shaped_chemistry' #'ENTRY_SHAPED_CHEMISTRY', //TODO recipe: type? - if shapeless: + if shapeless or shulker_box or shapeless_chemistry: recipe_id: string input: RecipeIngredient[]varint output: Item[]varint @@ -381,7 +395,7 @@ Recipes: []varint block: string priority: zigzag32 network_id: zigzag32 - if shaped: + if shaped or shaped_chemistry: recipe_id: string width: zigzag32 height: zigzag32 diff --git a/data/newproto.json b/data/newproto.json index 6be7328..671b939 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -186,26 +186,16 @@ "type": "GameRule" } ], - "Chunks": [ + "Blob": [ "container", [ { - "name": "cache_enabled", - "type": "bool" + "name": "hash", + "type": "lu64" }, { - "anon": true, - "type": [ - "switch", - { - "compareTo": "cache_enabled", - "fields": { - "true": "void", - "false": "void" - }, - "default": "void" - } - ] + "name": "payload", + "type": "string" } ] ], @@ -605,35 +595,36 @@ ] } ], + "Link": [ + "container", + [ + { + "name": "ridden_entity_id", + "type": "zigzag64" + }, + { + "name": "rider_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "immediate", + "type": "bool" + }, + { + "name": "rider_initiated", + "type": "bool" + } + ] + ], "Links": [ "array", { "countType": "varint", - "type": [ - "container", - [ - { - "name": "ridden_entity_id", - "type": "zigzag64" - }, - { - "name": "rider_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "immediate", - "type": "bool" - }, - { - "name": "rider_initiated", - "type": "bool" - } - ] - ] + "type": "Link" } ], "EntityAttributes": [ @@ -787,17 +778,17 @@ { "type": "varint", "mappings": { - "0": "TYPE_NORMAL", - "1": "TYPE_INVENTORY_MISMATCH", - "2": "TYPE_ITEM_USE", - "3": "TYPE_ITEM_USE_ON_ENTITY", - "4": "TYPE_ITEM_RELEASE" + "0": "normal", + "1": "inventory_mismatch", + "2": "item_use", + "3": "item_use_on_entity", + "4": "item_release" } } ] }, { - "name": "has_network_ids", + "name": "network_ids", "type": "bool" }, { @@ -816,12 +807,12 @@ { "type": "varint", "mappings": { - "0": "INV_SOURCE_TYPE_CONTAINER", - "1": "INV_SOURCE_TYPE_GLOBAL", - "2": "INV_SOURCE_TYPE_WORLD_INTERACTION", - "3": "INV_SOURCE_TYPE_CREATIVE", - "100": "INV_SOURCE_TYPE_CRAFT_SLOT", - "99999": "INV_SOURCE_TYPE_CRAFT" + "0": "container", + "1": "global", + "2": "world_interaction", + "3": "creative", + "100": "craft_slot", + "99999": "craft" } } ] @@ -833,7 +824,7 @@ { "compareTo": "source_type", "fields": { - "INV_SOURCE_TYPE_CONTAINER": [ + "container": [ "container", [ { @@ -842,7 +833,7 @@ } ] ], - "INV_SOURCE_TYPE_CREATIVE": [ + "creative": [ "container", [ { @@ -851,7 +842,7 @@ } ] ], - "INV_SOURCE_TYPE_WORLD_INTERACTION": [ + "world_interaction": [ "container", [ { @@ -860,7 +851,7 @@ } ] ], - "INV_SOURCE_TYPE_CRAFT": [ + "craft": [ "container", [ { @@ -869,7 +860,7 @@ } ] ], - "INV_SOURCE_TYPE_CRAFT_SLOT": [ + "craft_slot": [ "container", [ { @@ -900,7 +891,7 @@ "type": [ "switch", { - "compareTo": "../has_network_ids", + "compareTo": "../network_ids", "fields": { "true": "zigzag32" }, @@ -920,9 +911,9 @@ { "compareTo": "transaction_type", "fields": { - "TYPE_NORMAL": "void", - "TYPE_INVENTORY_MISMATCH": "void", - "TYPE_ITEM_USE": [ + "normal": "void", + "inventory_mismatch": "void", + "item_use": [ "container", [ { @@ -955,7 +946,7 @@ } ] ], - "TYPE_ITEM_USE_ON_ENTITY": [ + "item_use_on_entity": [ "container", [ { @@ -984,7 +975,7 @@ } ] ], - "TYPE_ITEM_RELEASE": [ + "item_release": [ "container", [ { @@ -1142,9 +1133,9 @@ "2": "furnace", "3": "furnace_with_metadata", "4": "multi", - "5": "shapeless", - "6": "shapeless", - "7": "shaped" + "5": "shulker_box", + "6": "shapeless_chemistry", + "7": "shaped_chemistry" } } ] @@ -1201,6 +1192,96 @@ } ] ], + "shulker_box": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "shapeless_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], "shaped": [ "container", [ @@ -1260,6 +1341,65 @@ } ] ], + "shaped_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], "furnace": [ "container", [ @@ -2896,7 +3036,7 @@ "type": "BlockCoordinates" }, { - "name": "has_achievements_disabled", + "name": "achievements_disabled", "type": "bool" }, { @@ -2908,7 +3048,7 @@ "type": "zigzag32" }, { - "name": "has_edu_features_enabled", + "name": "edu_features_enabled", "type": "bool" }, { @@ -3394,7 +3534,7 @@ "container", [ { - "name": "unknown", + "name": "jump_strength", "type": "zigzag32" } ] @@ -3929,20 +4069,8 @@ "container", [ { - "name": "ridden_id", - "type": "zigzag64" - }, - { - "name": "rider_id", - "type": "zigzag64" - }, - { - "name": "link_type", - "type": "u8" - }, - { - "name": "unknown", - "type": "u8" + "name": "link", + "type": "Link" } ] ], @@ -3960,10 +4088,19 @@ [ { "name": "spawn_type", - "type": "zigzag32" + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "player", + "1": "world" + } + } + ] }, { - "name": "coordinates", + "name": "player_position", "type": "BlockCoordinates" }, { @@ -3971,7 +4108,7 @@ "type": "zigzag32" }, { - "name": "unknown_coordinates", + "name": "world_position", "type": "BlockCoordinates" } ] @@ -4245,8 +4382,39 @@ "type": "varint" }, { - "name": "column", - "type": "Chunks" + "name": "cache_enabled", + "type": "bool" + }, + { + "name": "blobs", + "type": [ + "switch", + { + "compareTo": "cache_enabled", + "fields": { + "true": [ + "container", + [ + { + "name": "hashes", + "type": [ + "array", + { + "countType": "varint", + "type": "lu64" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "payload", + "type": "string" } ] ], @@ -4383,11 +4551,11 @@ "container", [ { - "name": "unknown1", + "name": "camera_entity_unique_id", "type": "zigzag64" }, { - "name": "unknown2", + "name": "target_player_unique_id", "type": "zigzag64" } ] @@ -4858,35 +5026,35 @@ "type": "u8" }, { - "name": "unknown0", + "name": "size", "type": "varint" }, { - "name": "unknown1", + "name": "trade_tier", "type": "varint" }, { - "name": "unknown2", - "type": "varint" + "name": "villager_unique_id", + "type": "varint64" }, { - "name": "is_willing", - "type": "bool" - }, - { - "name": "trader_entity_id", - "type": "zigzag64" - }, - { - "name": "player_entity_id", - "type": "zigzag64" + "name": "entity_unique_id", + "type": "varint64" }, { "name": "display_name", "type": "string" }, { - "name": "nbt", + "name": "new_trading_ui", + "type": "bool" + }, + { + "name": "economic_trades", + "type": "bool" + }, + { + "name": "offers", "type": "nbt" } ] @@ -4903,7 +5071,7 @@ "type": "u8" }, { - "name": "unknown", + "name": "size", "type": "u8" }, { @@ -4911,7 +5079,7 @@ "type": "zigzag64" }, { - "name": "nbt", + "name": "inventory", "type": "nbt" } ] @@ -5678,22 +5846,50 @@ ], "packet_client_cache_blob_status": [ "container", - [] + [ + { + "name": "missing", + "type": [ + "array", + { + "countType": "varint", + "type": "lu64" + } + ] + }, + { + "name": "have", + "type": [ + "array", + { + "countType": "varint", + "type": "lu64" + } + ] + } + ] ], "packet_client_cache_miss_response": [ "container", - [] + [ + { + "name": "blobs", + "type": [ + "array", + { + "countType": "varint", + "type": "Blob" + } + ] + } + ] ], "packet_network_settings": [ "container", [ - { - "name": "unknown", - "type": "u8" - }, { "name": "compression_threshold", - "type": "u8" + "type": "u16" } ] ], From 57290cd1807e7665fce56570c93a067f51c17e64 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 20 Feb 2021 01:14:59 -0500 Subject: [PATCH 102/458] client packet verification --- src/ConnWorker.js | 2 +- src/client.js | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/clientTest.js | 42 ++++++++++++++++++++++++++++++++---------- src/connection.js | 22 +++++++++++++++++++--- 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/src/ConnWorker.js b/src/ConnWorker.js index f6d38d3..81e7507 100644 --- a/src/ConnWorker.js +++ b/src/ConnWorker.js @@ -1,4 +1,4 @@ -const RakClient = require('@jsprismarine/raknet/client') +const RakClient = require('jsp-raknet/client') const { Worker, isMainThread, parentPort } = require('worker_threads') const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') diff --git a/src/client.js b/src/client.js index bd2da33..e83d8db 100644 --- a/src/client.js +++ b/src/client.js @@ -119,18 +119,55 @@ class Client extends Connection { process.exit(1) } + tryRencode(name, params, actual) { + if (name == 'level_chunk') { + console.log("Skipping chunk validation, it's broken right now") + return + } + const packet = this.serializer.createPacketBuffer({ name, params }) + + console.assert(packet.toString('hex') == actual.toString('hex')) + if (packet.toString('hex') !== actual.toString('hex')) { + + const ours = packet.toString('hex').match(/.{1,16}/g).join('\n') + const theirs = actual.toString('hex').match(/.{1,16}/g).join('\n') + + fs.writeFileSync('ours.txt', ours) + fs.writeFileSync('theirs.txt', theirs) + fs.writeFileSync('ours.json', serialize(params)) + fs.writeFileSync('theirs.json', serialize(this.deserializer.parsePacketBuffer(packet).data.params)) + + throw new Error(name + ' Packet comparison failed!') + } + } + readPacket(packet) { // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } console.log('->', pakData.name, serialize(pakData.params).slice(0, 100)) + + // No idea what this exotic 0xA0 packet is, it's not implemented anywhere + // and seems empty. Possible gibberish from the raknet impl + if (pakData.name == '160' || !pakData.name) { // eslint-ignore-line + console.warn('?? Ignoring extraneous packet ', des) + return + } + + // Packet verifying (decode + re-encode + match test) + if (pakData.name) { + this.tryRencode(pakData.name, pakData.params, packet) + } + // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) + // Packet dumping try { if (!fs.existsSync(`./packets/${pakData.name}.json`)) { fs.writeFileSync(`./packets/${pakData.name}.json`, serialize(pakData.params, 2)) fs.writeFileSync(`./packets/${pakData.name}.txt`, packet.toString('hex')) } - } catch {} + } catch { } + switch (des.data.name) { case 'server_to_client_handshake': this.emit('client.server_handshake', des.data.params) @@ -143,6 +180,10 @@ class Client extends Connection { break case 'start_game': fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) + break + case 'level_chunk': + fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) + break default: // console.log('Sending to listeners') } @@ -151,6 +192,8 @@ class Client extends Connection { } } +var chunks = 0; + function serialize(obj = {}, fmt) { return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) } diff --git a/src/clientTest.js b/src/clientTest.js index 39bb310..43af281 100644 --- a/src/clientTest.js +++ b/src/clientTest.js @@ -1,20 +1,42 @@ // process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('./client') - +const fs = require('fs') // console.log = () => async function test() { - const client = new Client({ - hostname: '127.0.0.1', - port: 19132 + const client = new Client({ + hostname: '127.0.0.1', + port: 19132 + }) + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] }) - - client.once('resource_packs_info', (packet) => { - client.write('resource_pack_client_response', { - response_status: 'completed', - resourcepackids: [] - }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) }) + + // client.once('resource_packs_info', (packet) => { + // client.write('resource_pack_client_response', { + // response_status: 'completed', + // resourcepackids: [] + // }) + // }) + }) + + + + // var read = 0; + // client.on('level_chunk', (packet) => { + // read++ + // fs.writeFileSync(`level_chunk-${read}.json`, JSON.stringify(packet, null, 2)) + // }) } test() \ No newline at end of file diff --git a/src/connection.js b/src/connection.js index 1ecbee2..3fa2475 100644 --- a/src/connection.js +++ b/src/connection.js @@ -2,8 +2,8 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') -const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') - +const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') +const debug = require('debug')('minecraft-protocol') class Connection extends EventEmitter { startEncryption(iv) { @@ -15,8 +15,10 @@ class Connection extends EventEmitter { write(name, params) { // TODO: Batch console.log('Need to encode', name, params) + // console.log('<-', name) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) + console.log('Sending buf', packet.toString('hex')) batch.addEncodedPacket(packet) if (this.encryptionEnabled) { @@ -45,6 +47,19 @@ class Connection extends EventEmitter { } } + /** + * Sends a MCPE packet buffer + */ + sendBuffer(buffer) { + const batch = new BatchPacket() + batch.addEncodedPacket(buffer) + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + sendDecryptedBatch(batch) { const buf = batch.encode() // send to raknet @@ -53,10 +68,11 @@ class Connection extends EventEmitter { sendEncryptedBatch(batch) { const buf = batch.stream.getBuffer() - console.log('Sending encrypted batch', batch) + debug('Sending encrypted batch', batch) this.encrypt(buf) } + // TODO: Rename this to sendEncapsulated sendMCPE(buffer, immediate) { if (this.worker) { console.log('-> buf', buffer) From f3604fa9b543d554ccffef2ecfaca298b6e9a8ee Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 21 Feb 2021 15:22:04 -0500 Subject: [PATCH 103/458] protocol updates Add some updates --- data/new/proto.yml | 142 +++++++++++++++- data/new/types.yaml | 65 +++++++- data/newproto.json | 248 ++++++++++++++++++++++++++-- src/datatypes/compiler-minecraft.js | 58 ++++++- 4 files changed, 479 insertions(+), 34 deletions(-) diff --git a/data/new/proto.yml b/data/new/proto.yml index 6bbb0d5..b209d4f 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -200,7 +200,18 @@ packet_start_game: # The runtime ID of the player. The runtime ID is unique for each world session, # and entities are generally identified in packets using this runtime ID. runtime_entity_id: varint64 - player_gamemode: zigzag32 + # PlayerGameMode is the game mode the player currently has. It is a value from 0-4, with 0 being + # survival mode, 1 being creative mode, 2 being adventure mode, 3 being survival spectator and 4 being + # creative spectator. + # This field may be set to 5 to make the client fall back to the game mode set in the WorldGameMode + # field. + player_gamemode: zigzag32 => + 0: survival + 1: creative + 2: adventure + 3: survival_spectator + 4: creative_spectator + 5: fallback # The spawn position of the player in the world. In servers this is often the same as the # world's spawn position found below. spawn: vec3f @@ -680,11 +691,25 @@ packet_mob_armor_equipment: leggings: Item boots: Item +# Interact is sent by the client when it interacts with another entity in some way. It used to be used for +# normal entity and block interaction, but this is no longer the case now. packet_interact: !id: 0x21 !bound: both - action_id: u8 + # Action type is the ID of the action that was executed by the player. It is one of the constants that + # may be found above. + action_id: u8 => + 3: leave_vehicle + 4: mouse_over_entity + 6: open_inventory + # TargetEntityRuntimeID is the runtime ID of the entity that the player interacted with. This is empty + # for the InteractActionOpenInventory action type. target_runtime_entity_id: varint + # Position associated with the ActionType above. For the InteractActionMouseOverEntity, this is the + # position relative to the entity moused over over which the player hovered with its mouse/touch. For the + # InteractActionLeaveVehicle, this is the position that the player spawns at after leaving the vehicle. + position: action_id ? + if mouse_over_entity or leave_vehicle: vec3f packet_block_pick_request: !id: 0x22 @@ -865,16 +890,75 @@ packet_gui_data_pick_item: !id: 0x36 !bound: client + +# AdventureSettings is sent by the server to update game-play related features, in particular permissions to +# access these features for the client. It includes allowing the player to fly, build and mine, and attack +# entities. Most of these flags should be checked server-side instead of using this packet only. +# The client may also send this packet to the server when it updates one of these settings through the +# in-game settings interface. The server should verify if the player actually has permission to update those +# settings. packet_adventure_settings: !id: 0x37 !bound: both - flags: varint - command_permission: varint - action_permissions: varint - permission_level: varint + # Flags is a set of flags that specify certain properties of the player, such as whether or not it can + # fly and/or move through blocks. It is one of the AdventureFlag constants above. + flags: AdventureFlags + # CommandPermissionLevel is a permission level that specifies the kind of commands that the player is + # allowed to use. + command_permission: varint32 => + 0: normal + 1: operator + 2: host + 3: automation + 4: admin + # ActionPermissions is, much like Flags, a set of flags that specify actions that the player is allowed + # to undertake, such as whether it is allowed to edit blocks, open doors etc. It is a combination of the + # ActionPermission constants above. + action_permissions: ActionPermissions + # PermissionLevel is the permission level of the player as it shows up in the player list built up using + # the PlayerList packet. It is one of the PermissionLevel constants above. + permission_level: varint => + 0: visitor + 1: member + 2: operator + 3: custom + # Custom permissions custom_stored_permissions: varint + # PlayerUniqueID is a unique identifier of the player. It appears it is not required to fill this field + # out with a correct value. Simply writing 0 seems to work. user_id: li64 +AdventureFlags: [ "bitflags", + { + "type": "varint", + "flags": { + "world_immutable": 1, + "no_pvp": 2, + "auto_jump": 0x20, + "allow_flight": 0x40, + "no_clip": 0x80, + "world_builder": 0x100, + "flying": 0x200, + "muted": 0x400 + } + } +] + +ActionPermissions: [ "bitflags", + { + "type": "varint", + "flags": { + "build_and_mine": 0x10001, + "doors_and_switches": 0x10002, + "open_containers": 0x10004, + "attack_players": 0x10008, + "attack_mobs": 0x10010, + "operator": 0x10020, + "teleport": 0x10080, + } + } +] + packet_block_entity_data: !id: 0x38 !bound: both @@ -1547,21 +1631,61 @@ packet_update_block_synced: unknown0: varint unknown1: varint +# MoveActorDelta is sent by the server to move an entity. The packet is specifically optimised to save as +# much space as possible, by only writing non-zero fields. +# As of 1.16.100, this packet no longer actually contains any deltas. packet_move_entity_delta: !id: 0x6f !bound: client - runtime_entity_id: varint - flags: lu16 + # EntityRuntimeID is the runtime ID of the entity that is being moved. The packet works provided a + # non-player entity with this runtime ID is present. + runtime_entity_id: varint64 + # Flags is a list of flags that specify what data is in the packet. + flags: DeltaMoveFlags + x: flags.has_x? + if true: lf32 + y: flags.has_y? + if true: lf32 + z: flags.has_z? + if true: lf32 + rot_x: flags.has_rot_x? + if true: u8 # TODO: * implement ByteFloat + rot_y: flags.has_rot_y? + if true: u8 + rot_z: flags.has_rot_z? + if true: u8 + +DeltaMoveFlags: [ "bitflags", + { + "type": "lu16", + "flags": { + "has_x": 0x01, + "has_y": 0x02, + "has_z": 0x04, + "has_rot_x": 0x08, + "has_rot_y": 0x10, + "has_rot_z": 0x20, + "on_ground": 0x40, + "teleport": 0x80, + "force_move": 0x100 + } + } +] packet_set_scoreboard_identity: !id: 0x70 !bound: client entries: ScoreboardIdentityEntries +# SetLocalPlayerAsInitialised is sent by the client in response to a PlayStatus packet with the status set +# to spawn. The packet marks the moment at which the client is fully initialised and can receive any packet +# without discarding it. packet_set_local_player_as_initialized: !id: 0x71 !bound: server - runtime_entity_id: varint + # EntityRuntimeID is the entity runtime ID the player was assigned earlier in the login sequence in the + # StartGame packet. + runtime_entity_id: varint64 packet_update_soft_enum: !id: 0x72 diff --git a/data/new/types.yaml b/data/new/types.yaml index a0835b1..8f6b109 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -328,25 +328,76 @@ Transaction: default: void transaction_data: transaction_type? if normal or inventory_mismatch: void + # UseItemTransactionData represents an inventory transaction data object sent when the client uses an item on + # a block. if item_use: - action_type: varint + # ActionType is the type of the UseItem inventory transaction. It is one of the action types found above, + # and specifies the way the player interacted with the block. + action_type: varint => + 0: click_block + 1: click_air + 2: break_block + # BlockPosition is the position of the block that was interacted with. This is only really a correct + # block position if ActionType is not UseItemActionClickAir. + block_position: BlockCoordinates + # BlockFace is the face of the block that was interacted with. When clicking the block, it is the face + # clicked. When breaking the block, it is the face that was last being hit until the block broke. face: varint + # HotBarSlot is the hot bar slot that the player was holding while clicking the block. It should be used + # to ensure that the hot bar slot and held item are correctly synchronised with the server. hotbar_slot: varint - item_in_hand: Item + # HeldItem is the item that was held to interact with the block. The server should check if this item + # is actually present in the HotBarSlot. + held_item: Item + # Position is the position of the player at the time of interaction. For clicking a block, this is the + # position at that time, whereas for breaking the block it is the position at the time of breaking. player_pos: vec3f + # ClickedPosition is the position that was clicked relative to the block's base coordinate. It can be + # used to find out exactly where a player clicked the block. click_pos: vec3f + # BlockRuntimeID is the runtime ID of the block that was clicked. It may be used by the server to verify + # that the player's world client-side is synchronised with the server's. block_runtime_id: varint + # UseItemOnEntityTransactionData represents an inventory transaction data object sent when the client uses + # an item on an entity. if item_use_on_entity: + # TargetEntityRuntimeID is the entity runtime ID of the target that was clicked. It is the runtime ID + # that was assigned to it in the AddEntity packet. entity_runtime_id: varint64 - action_type: varint + # ActionType is the type of the UseItemOnEntity inventory transaction. It is one of the action types + # found in the constants above, and specifies the way the player interacted with the entity. + action_type: varint => + 0: interact + 1: attack + # HotBarSlot is the hot bar slot that the player was holding while clicking the entity. It should be used + # to ensure that the hot bar slot and held item are correctly synchronised with the server. hotbar_slot: zigzag32 - item_in_hand: Item + # HeldItem is the item that was held to interact with the entity. The server should check if this item + # is actually present in the HotBarSlot. + held_item: Item + # Position is the position of the player at the time of clicking the entity. player_pos: vec3f - click_pos: vec3f + # ClickedPosition is the position that was clicked relative to the entity's base coordinate. It can be + # used to find out exactly where a player clicked the entity. + click_pos: vec3f + # ReleaseItemTransactionData represents an inventory transaction data object sent when the client releases + # the item it was using, for example when stopping while eating or stopping the charging of a bow. if item_release: - action_type: varint + # ActionType is the type of the ReleaseItem inventory transaction. It is one of the action types found + # in the constants above, and specifies the way the item was released. + # As of 1.13, the ActionType is always 0. This field can be ignored, because releasing food (by consuming + # it) or releasing a bow (to shoot an arrow) is essentially the same. + action_type: varint => + 0: release + 1: consume + # HotBarSlot is the hot bar slot that the player was holding while releasing the item. It should be used + # to ensure that the hot bar slot and held item are correctly synchronised with the server. hotbar_slot: zigzag32 - item_in_hand: Item + # HeldItem is the item that was released. The server should check if this item is actually present in the + # HotBarSlot. + held_item: Item + # HeadPosition is the position of the player's head at the time of releasing the item. This is used + # mainly for purposes such as spawning eating particles at that position. head_pos: vec3f ItemStacks: []varint diff --git a/data/newproto.json b/data/newproto.json index 671b939..689ff79 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -918,7 +918,21 @@ [ { "name": "action_type", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "click_block", + "1": "click_air", + "2": "break_block" + } + } + ] + }, + { + "name": "block_position", + "type": "BlockCoordinates" }, { "name": "face", @@ -929,7 +943,7 @@ "type": "varint" }, { - "name": "item_in_hand", + "name": "held_item", "type": "Item" }, { @@ -955,14 +969,23 @@ }, { "name": "action_type", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "interact", + "1": "attack" + } + } + ] }, { "name": "hotbar_slot", "type": "zigzag32" }, { - "name": "item_in_hand", + "name": "held_item", "type": "Item" }, { @@ -980,14 +1003,23 @@ [ { "name": "action_type", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "release", + "1": "consume" + } + } + ] }, { "name": "hotbar_slot", "type": "zigzag32" }, { - "name": "item_in_hand", + "name": "held_item", "type": "Item" }, { @@ -2993,7 +3025,20 @@ }, { "name": "player_gamemode", - "type": "zigzag32" + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "survival", + "1": "creative", + "2": "adventure", + "3": "survival_spectator", + "4": "creative_spectator", + "5": "fallback" + } + } + ] }, { "name": "spawn", @@ -3926,11 +3971,35 @@ [ { "name": "action_id", - "type": "u8" + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "3": "leave_vehicle", + "4": "mouse_over_entity", + "6": "open_inventory" + } + } + ] }, { "name": "target_runtime_entity_id", "type": "varint" + }, + { + "name": "position", + "type": [ + "switch", + { + "compareTo": "action_id", + "fields": { + "mouse_over_entity": "vec3f", + "leave_vehicle": "vec3f" + }, + "default": "void" + } + ] } ] ], @@ -4308,19 +4377,42 @@ [ { "name": "flags", - "type": "varint" + "type": "AdventureFlags" }, { "name": "command_permission", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint32", + "mappings": { + "0": "normal", + "1": "operator", + "2": "host", + "3": "automation", + "4": "admin" + } + } + ] }, { "name": "action_permissions", - "type": "varint" + "type": "ActionPermissions" }, { "name": "permission_level", - "type": "varint" + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "visitor", + "1": "member", + "2": "operator", + "3": "custom" + } + } + ] }, { "name": "custom_stored_permissions", @@ -5611,11 +5703,89 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "flags", - "type": "lu16" + "type": "DeltaMoveFlags" + }, + { + "name": "x", + "type": [ + "switch", + { + "compareTo": "flags.has_x", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "y", + "type": [ + "switch", + { + "compareTo": "flags.has_y", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "z", + "type": [ + "switch", + { + "compareTo": "flags.has_z", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "rot_x", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_x", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_y", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_y", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_z", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_z", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] } ] ], @@ -5633,7 +5803,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" } ] ], @@ -5994,6 +6164,37 @@ "countType": "li32" } ], + "AdventureFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "world_immutable": 1, + "no_pvp": 2, + "auto_jump": 32, + "allow_flight": 64, + "no_clip": 128, + "world_builder": 256, + "flying": 512, + "muted": 1024 + } + } + ], + "ActionPermissions": [ + "bitflags", + { + "type": "varint", + "flags": { + "build_and_mine": 65537, + "doors_and_switches": 65538, + "open_containers": 65540, + "attack_players": 65544, + "attack_mobs": 65552, + "operator": 65568, + "teleport": 65664 + } + } + ], "CommandFlags": [ "bitfield", [ @@ -6013,6 +6214,23 @@ "signed": false } ] + ], + "DeltaMoveFlags": [ + "bitflags", + { + "type": "lu16", + "flags": { + "has_x": 1, + "has_y": 2, + "has_z": 4, + "has_rot_x": 8, + "has_rot_y": 16, + "has_rot_z": 32, + "on_ground": 64, + "teleport": 128, + "force_move": 256 + } + } ] } } \ No newline at end of file diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index 7130749..8d1e10f 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -45,18 +45,70 @@ Read.nbt = ['native', minecraft.nbt[0]] Write.nbt = ['native', minecraft.nbt[1]] SizeOf.nbt = ['native', minecraft.nbt[2]] +/** + * Bits + */ +// nvm, +// Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { + // return compiler.wrapCode(` + // const { value, size } = ${compiler.callType('buffer, offset', type)} + // const val = {} + // for (let i = 0; i < size; i++) { + // const hi = (value >> i) & 1 + // if () + // const v = value & + // if (flags[i]) + // } + // ` +// }] + +Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { + return compiler.wrapCode(` + const { value: _value, size } = ${compiler.callType(type, 'offset')} + const value = { _value } + const flags = ${JSON.stringify(flags)} + for (const key in flags) { + value[key] = (_value & flags[key]) == flags[key] + } + return { value, size } + `.trim()) +}] + + +Write.bitflags = ['parametrizable', (compiler, { type, flags }) => { + return compiler.wrapCode(` + const flags = ${JSON.stringify(flags)} + let val = value._value + for (const key in flags) { + if (value[key]) val |= flags[key] + } + return (ctx.${type})(val, buffer, offset) + `.trim()) +}] + +SizeOf.bitflags = ['parametrizable', (compiler, { type, flags }) => { + return compiler.wrapCode(` + const flags = ${JSON.stringify(flags)} + let val = value._value + for (const key in flags) { + if (value[key]) val |= flags[key] + } + return (ctx.${type})(val) + `.trim()) +}] + /** * Command Packet * - used for determining the size of the following enum */ -Read.enum_size_based_on_values_len = ['parametrizable', (compiler, array) => { +Read.enum_size_based_on_values_len = ['parametrizable', (compiler) => { return compiler.wrapCode(js(() => { if (values_len <= 0xff) return { value: 'byte', size: 0 } if (values_len <= 0xffff) return { value: 'short', size: 0 } if (values_len <= 0xffffff) return { value: 'int', size: 0 } })) }] -Write.enum_size_based_on_values_len = ['parametrizable', (compiler, array) => { +Write.enum_size_based_on_values_len = ['parametrizable', (compiler) => { return str(() => { if (value.values_len <= 0xff) _enum_type = 'byte' else if (value.values_len <= 0xffff) _enum_type = 'short' @@ -64,7 +116,7 @@ Write.enum_size_based_on_values_len = ['parametrizable', (compiler, array) => { return offset }) }] -SizeOf.enum_size_based_on_values_len = ['parametrizable', (compiler, array) => { +SizeOf.enum_size_based_on_values_len = ['parametrizable', (compiler) => { return str(() => { if (value.values_len <= 0xff) _enum_type = 'byte' else if (value.values_len <= 0xffff) _enum_type = 'short' From 4035295cdd2855b1105758de36738e2ea3d9c6ca Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 21 Feb 2021 15:26:34 -0500 Subject: [PATCH 104/458] packet batching + working client/server spawning --- src/client.js | 9 +--- src/clientTest.js | 5 ++ src/connection.js | 48 +++++++++++++---- src/server.js | 112 ++++++--------------------------------- src/serverPlayer.js | 126 ++++++++++++++++++++++++++++++++++++++++++++ src/serverTest.js | 125 ++++++++++++++++++++++++++++++------------- 6 files changed, 275 insertions(+), 150 deletions(-) create mode 100644 src/serverPlayer.js diff --git a/src/client.js b/src/client.js index e83d8db..6ceca76 100644 --- a/src/client.js +++ b/src/client.js @@ -28,6 +28,7 @@ class Client extends Connection { } this.on('session', this.connect) + this.startQueue() // this.on('decrypted', this.onDecryptedPacket) } @@ -104,14 +105,6 @@ class Client extends Connection { }) } - // After sending Server to Client Handshake, this handles the client's - // Client to Server handshake response. This indicates successful encryption - onHandshake() { - // https://wiki.vg/Bedrock_Protocol#Play_Status - this.write('play_status', { status: PLAY_STATUS.LoginSuccess }) - this.emit('join') - } - onDisconnectRequest(packet) { // We're talking over UDP, so there is no connection to close, instead // we stop communicating with the server diff --git a/src/clientTest.js b/src/clientTest.js index 43af281..75a621d 100644 --- a/src/clientTest.js +++ b/src/clientTest.js @@ -28,6 +28,11 @@ async function test() { // resourcepackids: [] // }) // }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) diff --git a/src/connection.js b/src/connection.js index 3fa2475..44f3891 100644 --- a/src/connection.js +++ b/src/connection.js @@ -18,7 +18,7 @@ class Connection extends EventEmitter { // console.log('<-', name) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) - console.log('Sending buf', packet.toString('hex')) + // console.log('Sending buf', packet.toString('hex').) batch.addEncodedPacket(packet) if (this.encryptionEnabled) { @@ -28,6 +28,33 @@ class Connection extends EventEmitter { } } + queue(name, params) { + console.log('<- ', name) + const packet = this.serializer.createPacketBuffer({ name, params }) + this.q.push(packet) + } + + startQueue() { + this.q = [] + this.loop = setInterval(() => { + if (this.q.length) { + //TODO: can we just build Batch before the queue loop? + const batch = new BatchPacket() + // For now, we're over conservative so send max 3 packets + // per batch and hold the rest for the next tick + for (let i = 0; i < 3 && i < this.q.length; i++) { + const packet = this.q.shift() + batch.addEncodedPacket(packet) + } + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + }, 100) + } + writeRaw(name, buffer) { // skip protodef serializaion // temporary hard coded stuff const batch = new BatchPacket() @@ -37,7 +64,6 @@ class Connection extends EventEmitter { stream.writeUnsignedVarInt(0x7a) stream.append(buffer) batch.addEncodedPacket(stream.getBuffer()) - // console.log('----- SENDING BIOME DEFINITIONS') } if (this.encryptionEnabled) { @@ -50,13 +76,17 @@ class Connection extends EventEmitter { /** * Sends a MCPE packet buffer */ - sendBuffer(buffer) { - const batch = new BatchPacket() - batch.addEncodedPacket(buffer) - if (this.encryptionEnabled) { - this.sendEncryptedBatch(batch) + sendBuffer(buffer, immediate = false) { + if (immediate) { + const batch = new BatchPacket() + batch.addEncodedPacket(buffer) + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } } else { - this.sendDecryptedBatch(batch) + this.q.push(buffer) } } @@ -78,7 +108,7 @@ class Connection extends EventEmitter { console.log('-> buf', buffer) this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) } else { - const sendPacket = new EncapsulatedPacket(); + const sendPacket = new EncapsulatedPacket() sendPacket.reliability = 0 sendPacket.buffer = buffer this.connection.addEncapsulatedToQueue(sendPacket) diff --git a/src/server.js b/src/server.js index 7db207d..f94b573 100644 --- a/src/server.js +++ b/src/server.js @@ -1,90 +1,10 @@ -const Listener = require('@jsprismarine/raknet/listener') +const Listener = require('jsp-raknet/listener') const { EventEmitter } = require('events') const { createDeserializer, createSerializer } = require('./transforms/serializer') -const { Encrypt } = require('./auth/encryption') -const { decodeLoginJWT } = require('./auth/chains') -const { Connection } = require('./connection') +const { Player } = require('./serverPlayer') + const Options = require('./options') - -const log = (...args) => console.log(...args) - -class Player extends Connection { - constructor(server, connection, options) { - super() - this.server = server - this.serializer = server.serializer - this.connection = connection - Encrypt(this, server, options) - } - - getData() { - return this.userData - } - - onLogin(packet) { - let body = packet.data - console.log('Body', body) - - const clientVer = body.protocol_version - if (this.server.options.version) { - if (this.server.options.version < clientVer) { - this.sendDisconnectStatus(failed_client) - return - } - } else if (clientVer < MIN_VERSION) { - this.sendDisconnectStatus(failed_client) - return - } - - // Parse login data - const authChain = JSON.parse(body.params.chain) - const skinChain = body.params.client_data - - try { - var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) - } catch (e) { - console.error(e) - throw new Error('Failed to verify user') - } - console.log('Verified user', 'got pub key', key, userData) - - this.emit('login', { user: userData.extraData }) // emit events for user - this.emit('server.client_handshake', { key }) // internal so we start encryption - - this.userData = userData.extraData - this.version = clientVer - } - - sendDisconnectStatus(play_status) { - this.write('play_status', { status: play_status }) - this.connection.close() - } - - // After sending Server to Client Handshake, this handles the client's - // Client to Server handshake response. This indicates successful encryption - onHandshake() { - // https://wiki.vg/Bedrock_Protocol#Play_Status - this.write('play_status', { status: 'login_success' }) - this.emit('join') - } - - readPacket(packet) { - console.log('packet', packet) - const des = this.server.deserializer.parsePacketBuffer(packet) - console.log('->', des) - switch (des.data.name) { - case 'login': - console.log(des) - this.onLogin(des) - return - case 'client_to_server_handshake': - this.onHandshake() - default: - console.log('ignoring, unhandled') - } - this.emit(des.data.name, des.data.params) - } -} +const debug = require('debug')('minecraft-protocol') class Server extends EventEmitter { constructor(options) { @@ -102,27 +22,23 @@ class Server extends EventEmitter { } } - getAddrHash(inetAddr) { - return inetAddr.address + '/' + inetAddr.port - } - onOpenConnection = (conn) => { - log('new connection', conn) + debug('new connection', conn) const player = new Player(this, conn) - this.clients[this.getAddrHash(conn.address)] = player + this.clients[hash(conn.address)] = player this.emit('connect', { client: player }) } onCloseConnection = (inetAddr, reason) => { - log('close connection', inetAddr, reason) - delete this.clients[this.getAddrHash(inetAddr)] + debug('close connection', inetAddr, reason) + delete this.clients[hash(inetAddr)] } onEncapsulated = (encapsulated, inetAddr) => { - log(inetAddr.address, ': Encapsulated', encapsulated) + debug(inetAddr.address, 'Encapsulated', encapsulated) const buffer = encapsulated.buffer - const client = this.clients[this.getAddrHash(inetAddr)] + const client = this.clients[hash(inetAddr)] if (!client) { throw new Error(`packet from unknown inet addr: ${inetAddr.address}/${inetAddr.port}`) } @@ -132,16 +48,18 @@ class Server extends EventEmitter { async create(serverIp, port) { this.listener = new Listener(this) this.raknet = await this.listener.listen(serverIp, port) - log('Listening on', serverIp, port) + console.debug('Listening on', serverIp, port) this.raknet.on('openConnection', this.onOpenConnection) this.raknet.on('closeConnection', this.onCloseConnection) this.raknet.on('encapsulated', this.onEncapsulated) this.raknet.on('raw', (buffer, inetAddr) => { - console.log('Raw packet', buffer, inetAddr) + debug('Raw packet', buffer, inetAddr) }) } } -module.exports = { Server, Player } \ No newline at end of file +const hash = (inetAddr) => inetAddr.address + '/' + inetAddr.port + +module.exports = { Server } \ No newline at end of file diff --git a/src/serverPlayer.js b/src/serverPlayer.js new file mode 100644 index 0000000..86d10bc --- /dev/null +++ b/src/serverPlayer.js @@ -0,0 +1,126 @@ +const { Encrypt } = require('./auth/encryption') +const { decodeLoginJWT } = require('./auth/chains') +const { Connection } = require('./connection') +const fs = require('fs') +const debug = require('debug')('minecraft-protocol') + +const ClientStatus = { + Authenticating: 0, + Initializing: 1, + Initialized: 2 +} + +class Player extends Connection { + constructor(server, connection, options) { + super() + this.server = server + this.serializer = server.serializer + this.connection = connection + Encrypt(this, server, options) + + this.startQueue() + this.status = ClientStatus.Authenticating + } + + getData() { + return this.userData + } + + onLogin(packet) { + let body = packet.data + debug('Body', body) + this.emit('loggingIn', body) + + const clientVer = body.protocol_version + if (this.server.options.version) { + if (this.server.options.version < clientVer) { + this.sendDisconnectStatus(failed_client) + return + } + } else if (clientVer < MIN_VERSION) { + this.sendDisconnectStatus(failed_client) + return + } + + // Parse login data + const authChain = JSON.parse(body.params.chain) + const skinChain = body.params.client_data + + try { + var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) + } catch (e) { + console.error(e) + throw new Error('Failed to verify user') + } + console.log('Verified user', 'got pub key', key, userData) + + this.emit('login', { user: userData.extraData }) // emit events for user + this.emit('server.client_handshake', { key }) // internal so we start encryption + + this.userData = userData.extraData + this.version = clientVer + } + + + /** + * Disconnects a client before it has joined + * @param {string} play_status + */ + sendDisconnectStatus(play_status) { + this.write('play_status', { status: play_status }) + this.connection.close() + } + + /** + * Disconnects a client after it has joined + */ + disconnect(reason, hide = false) { + this.write('disconnect', { + hide_disconnect_screen: hide, + message: reason + }) + this.connection.close() + } + + // After sending Server to Client Handshake, this handles the client's + // Client to Server handshake response. This indicates successful encryption + onHandshake() { + // https://wiki.vg/Bedrock_Protocol#Play_Status + this.write('play_status', { status: 'login_success' }) + this.status = ClientStatus.Initializing + this.emit('join') + } + + readPacket(packet) { + // console.log('packet', packet) + try { + var des = this.server.deserializer.parsePacketBuffer(packet) + } catch (e) { + this.disconnect('Server error') + console.warn('Packet parsing failed! Writing dump to ./packetdump.bin') + fs.writeFileSync('packetdump.bin', packet) + fs.writeFileSync('packetdump.txt', packet.toString('hex')) + throw e + } + + console.log('->', des) + switch (des.data.name) { + case 'login': + console.log(des) + this.onLogin(des) + return + case 'client_to_server_handshake': + // Emit the 'join' event + this.onHandshake() + case 'set_local_player_as_initialized': + this.state = ClientStatus.Initialized + // Emit the 'spawn' event + this.emit('spawn') + default: + console.log('ignoring, unhandled') + } + this.emit(des.data.name, des.data.params) + } +} + +module.exports = { Player, ClientStatus } \ No newline at end of file diff --git a/src/serverTest.js b/src/serverTest.js index 0d733f6..ad54097 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -1,3 +1,4 @@ +// process.env.DEBUG = 'minecraft-protocol raknet' const { Server } = require('./server') const CreativeItems = require('../data/creativeitems.json') const NBT = require('prismarine-nbt') @@ -24,7 +25,7 @@ server.on('connect', ({ client }) => { 'texture_packs': [] }) - client.once('resource_pack_client_response', (packet) => { + client.once('resource_pack_client_response', async (packet) => { // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs // should be applied (and downloaded) by the client. client.write('resource_pack_stack', { @@ -37,45 +38,97 @@ server.on('connect', ({ client }) => { }) client.once('resource_pack_client_response', async (packet) => { - ran = true - let items = [] - let ids = 0 - for (var item of CreativeItems) { - let creativeitem = { runtime_id: items.length } - const has_nbt = !!item.nbt_b64 - if (item.id != 0) { - creativeitem.item = { - network_id: item.id, - auxiliary_value: item.damage || 0, - has_nbt, - nbt: { - version: 1, - }, - blocking_tick: 0, - can_destroy: [], - can_place_on: [] - } - if (has_nbt) { - let nbtBuf = Buffer.from(item.nbt_b64, 'base64') - let { parsed } = await NBT.parse(nbtBuf, 'little') - creativeitem.item.nbt.nbt = parsed - } - } - items.push(creativeitem) - // console.log(creativeitem) - } + // ran = true + // let items = [] + // let ids = 0 + // for (var item of CreativeItems) { + // let creativeitem = { runtime_id: items.length } + // const has_nbt = !!item.nbt_b64 + // if (item.id != 0) { + // creativeitem.item = { + // network_id: item.id, + // auxiliary_value: item.damage || 0, + // has_nbt, + // nbt: { + // version: 1, + // }, + // blocking_tick: 0, + // can_destroy: [], + // can_place_on: [] + // } + // if (has_nbt) { + // let nbtBuf = Buffer.from(item.nbt_b64, 'base64') + // let { parsed } = await NBT.parse(nbtBuf, 'little') + // creativeitem.item.nbt.nbt = parsed + // } + // } + // items.push(creativeitem) + // // console.log(creativeitem) + // } - console.log(items, ids) + // console.log(items, ids) - client.write('creative_content', { items }) + // client.write('creative_content', { items }) // wait a bit just for easier debugging - setTimeout(() => { - const biomeDefs = fs.readFileSync('../data/biome_definitions.nbt') - client.writeRaw('biome_definition_list', biomeDefs) + // setTimeout(() => { + // const biomeDefs = fs.readFileSync('../data/biome_definitions.nbt') + // client.writeRaw('biome_definition_list', biomeDefs) + + // // TODO: send chunks so we can spawn player + // }, 1000) - // TODO: send chunks so we can spawn player - }, 1000) }) + + client.write('network_settings', { + compression_threshold: 1 + }) + + for (let i = 0; i < 3; i++) { + client.queue('inventory_slot', {"inventory_id":120,"slot":i,"uniqueid":0,"item":{"network_id":0}}) + } + + client.queue('inventory_transaction', require('./packets/inventory_transaction.json')) + client.queue('player_list', require('./packets/player_list.json')) + client.queue('start_game', require('./packets/start_game.json')) + client.queue('item_component', {"entries":[]}) + client.queue('set_time', { time: 5433771 }) + client.queue('set_difficulty', { difficulty: 1 }) + client.queue('set_commands_enabled', { enabled: true }) + client.queue('adventure_settings', require('./packets/adventure_settings.json')) + + client.queue('biome_definition_list', require('./packets/biome_definition_list.json')) + client.queue('available_entity_identifiers', require('./packets/available_entity_identifiers.json')) + + client.queue('update_attributes', require('./packets/update_attributes.json')) + client.queue('creative_content', require('./packets/creative_content.json')) + client.queue('player_hotbar', {"selected_slot":3,"window_id":0,"select_slot":true}) + + client.queue('crafting_data', require('./packets/crafting_data.json')) + client.queue('available_commands', require('./packets/available_commands.json')) + + client.queue('game_rules_changed', require('./packets/game_rules_changed.json')) + client.queue('respawn', {"x":646.9405517578125,"y":65.62001037597656,"z":77.86255645751953,"state":0,"runtime_entity_id":0}) + + for (const file of fs.readdirSync('chunks')) { + const buffer = Buffer.from(fs.readFileSync('./chunks/' + file, 'utf8'), 'hex') + // console.log('Sending chunk', chunk) + client.sendBuffer(buffer) + } + + setInterval(() => { + client.write('network_chunk_publisher_update', {"coordinates":{"x":646,"y":130,"z":77},"radius":64}) + }, 9500) + + + setTimeout(() => { + client.write('play_status', { status: 'player_spawn' }) + }, 8000) }) }) -}) \ No newline at end of file +}) + +async function sleep(ms) { + return new Promise(res => { + setTimeout(() => { res() }, ms) + }) +} \ No newline at end of file From 93ab3064ab30e19e7b54f86bd7d6d56f263ab3a3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 21 Feb 2021 15:36:36 -0500 Subject: [PATCH 105/458] update raknet path --- package.json | 1 + src/auth/encryption.js | 1 - src/datatypes/BatchPacket.js | 8 +++- test/serialization.js | 77 ++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f0cd2f0..175c491 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", + "jsp-raknet": "github:extremeheat/raknet#client", "jwt-simple": "^0.5.6", "lodash.merge": "^4.4.0", "minecraft-folder-path": "^1.1.0", diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 8402497..375fc27 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -11,7 +11,6 @@ function Encrypt(client, server, options) { client.ecdhKeyPair.generateKeys() client.clientX509 = writeX509PublicKey(client.ecdhKeyPair.getPublicKey()) - function startClientboundEncryption(publicKey) { console.warn('[encrypt] Pub key base64: ', publicKey) const pubKeyBuf = readX509PublicKey(publicKey.key) diff --git a/src/datatypes/BatchPacket.js b/src/datatypes/BatchPacket.js index cdd9296..52f4320 100644 --- a/src/datatypes/BatchPacket.js +++ b/src/datatypes/BatchPacket.js @@ -5,12 +5,17 @@ const NETWORK_ID = 0xfe // This is not a real MCPE packet, it's a wrapper that contains compressed/encrypted batched packets class BatchPacket { - constructor(stream) { + // Shared this.payload = Buffer.alloc(0) this.stream = stream || new BinaryStream() + + // Decoding this.packets = [] + + // Encoding this.compressionLevel = 7 + this.count = 0 } decode() { @@ -43,6 +48,7 @@ class BatchPacket { addEncodedPacket(packet) { this.stream.writeUnsignedVarInt(packet.byteLength) this.stream.append(packet) + this.count++ } getPackets() { diff --git a/test/serialization.js b/test/serialization.js index 8250f14..6c1cbe5 100644 --- a/test/serialization.js +++ b/test/serialization.js @@ -172,11 +172,88 @@ function test() { fs.writeFileSync('commands.json', JSON.stringify(readed.data,null,2)) } + async function creativeTestNew() { + const json = require('../src/packets/creative_content.json') + const buf = write('creative_content', json) + + const des = read(buf) + fs.writeFileSync('cc.json', serialize(des.data.params, 2)) + console.log('Des', des) + } + + async function biomeDefinitions() { + const json = require('../src/packets/biome_definition_list.json') + const buf = write('biome_definition_list', json) + + const des = read(buf) + fs.writeFileSync('cc.json', serialize(des.data.params, 2)) + console.log('Des', des) + } + + async function playerList() { + const buf = Buffer.from('3f0001cc304faee0c9f37b41c80c39333e3f9cfdffffff5f0c546865496e766973696f6e58103235333534303837333838353837323000070000003f35656236356637332d616631312d343438652d383261612d3162376231363533313661642e706572736f6e612d653139393637326138633161383765302d30000100000001000000040000000000000000000000000000000000056e756c6c0a00000100003f35656236356637332d616631312d343438652d383261612d3162376231363533313661642e706572736f6e612d653139393637326138633161383765302d300477696465092366666666636439360000000000000000000000', 'hex') + const des = read(buf) + console.log(serialize(des.data.params, 2)) + } + + async function startGame() { + const s = '0bfdffffff5f090a32bc2144723d8342a1b99b420000000048ff21c3f6fafadb02000006706c61696e7300020002b006ffff010800c2b79505000000d48ca03e00000000000101060600001b12636f6d6d616e64626c6f636b6f757470757401010f646f6461796c696768746379636c6501010d646f656e7469747964726f707301010a646f666972657469636b010109646f6d6f626c6f6f7401010d646f6d6f62737061776e696e6701010b646f74696c6564726f707301010e646f776561746865726379636c6501010e64726f776e696e6764616d61676501010a66616c6c64616d61676501010a6669726564616d61676501010d6b656570696e76656e746f727901000b6d6f626772696566696e6701010370767001010f73686f77636f6f7264696e617465730100136e61747572616c726567656e65726174696f6e01010b746e746578706c6f64657301011373656e64636f6d6d616e64666565646261636b0101156d6178636f6d6d616e64636861696e6c656e67746802feff070a646f696e736f6d6e6961010114636f6d6d616e64626c6f636b73656e61626c656401010f72616e646f6d7469636b7370656564020212646f696d6d6564696174657265737061776e01001173686f7764656174686d6573736167657301011466756e6374696f6e636f6d6d616e646c696d697402a09c010b737061776e726164697573020a0873686f7774616773010100000000000000020400000000000001000000012a100000001000000000000d426564726f636b206c6576656c0d426564726f636b206c6576656c2430303030303030302d303030302d303030302d303030302d30303030303030303030303000026e5f520000000000e89280c209009207146d696e6563726166743a636f6f6b65645f636f640c0100166d696e6563726166743a7075727075725f626c6f636bc900000d6d696e6563726166743a626f772c0100146d696e6563726166743a656e645f627269636b73ce00000d6d696e6563726166743a61697262ff001c6d696e6563726166743a656e6465726d616e5f737061776e5f656767b80100196d696e6563726166743a6d757369635f646973635f77617264150200106d696e6563726166743a726162626974200100206d696e6563726166743a637265657065725f62616e6e65725f7061747465726e3c0200146d696e6563726166743a656c656d656e745f3235dcff00176d696e6563726166743a6d757368726f6f6d5f73746577040100286d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f736c6162e4fe00196d696e6563726166743a636f6f6b65645f706f726b63686f700701001b6d696e6563726166743a726176616765725f737061776e5f656767eb01001a6d696e6563726166743a73747269707065645f6f616b5f6c6f67f6ff000f6d696e6563726166743a6170706c65010100146d696e6563726166743a656c656d656e745f3530c3ff001a6d696e6563726166743a6d757369635f646973635f63686972700f0200226d696e6563726166743a707269736d6172696e655f627269636b735f737461697273fcff00176d696e6563726166743a636f6f6b65645f726162626974210100146d696e6563726166743a656c656d656e745f3334d3ff00176d696e6563726166743a71756172747a5f627269636b73d0fe00186d696e6563726166743a6974656d2e69726f6e5f646f6f724700000d6d696e6563726166743a636f64080100166d696e6563726166743a676f6c64656e5f6170706c65020100136d696e6563726166743a626f6f6b7368656c662f00001c6d696e6563726166743a676f6c64656e5f686f7273655f61726d6f720a02001e6d696e6563726166743a736d6f6f74685f71756172747a5f73746169727347ff00106d696e6563726166743a706f7461746f180100206d696e6563726166743a656e6368616e7465645f676f6c64656e5f6170706c65030100156d696e6563726166743a6e65746865725f73746172fc0100146d696e6563726166743a656c656d656e745f3135e6ff001c6d696e6563726166743a6974656d2e6461726b5f6f616b5f646f6f72c50000156d696e6563726166743a6c696768745f626c6f636b29ff00226d696e6563726166743a79656c6c6f775f676c617a65645f7465727261636f747461e000001c6d696e6563726166743a73746f6e655f627269636b5f7374616972736d0000106d696e6563726166743a706f7274616c5a0000146d696e6563726166743a676f6c645f696e676f74320100146d696e6563726166743a69726f6e5f696e676f74310100196d696e6563726166743a736c696d655f737061776e5f656767bb01000f6d696e6563726166743a7363757465320200106d696e6563726166743a636f6f6b69650f0100126d696e6563726166743a706f726b63686f70060100176d696e6563726166743a6469616d6f6e645f626c6f636b3900000f6d696e6563726166743a6272656164050100136d696e6563726166743a656c656d656e745f37eeff00166d696e6563726166743a69726f6e5f7069636b6178652901001c6d696e6563726166743a70696c6c616765725f737061776e5f656767e90100146d696e6563726166743a656c656d656e745f3237daff000e6d696e6563726166743a62656566110100196d696e6563726166743a626c617a655f737061776e5f656767c60100106d696e6563726166743a73616c6d6f6e090100226d696e6563726166743a73696c7665725f676c617a65645f7465727261636f747461e40000176d696e6563726166743a74726f706963616c5f666973680a0100156d696e6563726166743a636f636f615f6265616e739a0100156d696e6563726166743a776f6f64656e5f736c61629e0000146d696e6563726166743a656c656d656e745f3136e5ff00126d696e6563726166743a7472697077697265840000136d696e6563726166743a73746f6e655f6178653b01001c6d696e6563726166743a737461696e65645f676c6173735f70616e65a000000f6d696e6563726166743a616e76696c910000176d696e6563726166743a747261707065645f6368657374920000186d696e6563726166743a616e6369656e745f646562726973f1fe00146d696e6563726166743a707566666572666973680b0100106d696e6563726166743a6275636b6574680100176d696e6563726166743a636f6f6b65645f73616c6d6f6e0d0100146d696e6563726166743a656c656d656e745f3631b8ff00126d696e6563726166743a737061726b6c65724d0200156d696e6563726166743a7761727065645f646f6f725d0200146d696e6563726166743a64726965645f6b656c700e0100176d696e6563726166743a62656574726f6f745f736f75701e0100166d696e6563726166743a7265645f6d757368726f6f6d280000186d696e6563726166743a776f6f64656e5f7069636b617865360100176d696e6563726166743a6974656d2e63616d70666972652fff00156d696e6563726166743a6d656c6f6e5f736c696365100100136d696e6563726166743a6861795f626c6f636baa0000176d696e6563726166743a776f6f64656e5f73686f76656c350100186d696e6563726166743a6e617574696c75735f7368656c6c300200136d696e6563726166743a656c656d656e745f31f4ff001b6d696e6563726166743a73746f6e656375747465725f626c6f636b3bff00156d696e6563726166743a636f6f6b65645f62656566120100146d696e6563726166743a636f6d70617261746f72000200106d696e6563726166743a636172726f741701001b6d696e6563726166743a737472696465725f737061776e5f656767ed0100176d696e6563726166743a636f6d6d616e645f626c6f636b890000116d696e6563726166743a636869636b656e130100106d696e6563726166743a706f74696f6ea80100166d696e6563726166743a726f7474656e5f666c657368150100196d696e6563726166743a77697463685f737061776e5f656767c201000e6d696e6563726166743a64697274030000146d696e6563726166743a656c656d656e745f3632b7ff001b6d696e6563726166743a6461796c696768745f6465746563746f72970000146d696e6563726166743a736e6f775f6c617965724e0000156d696e6563726166743a7261626269745f666f6f740602001a6d696e6563726166743a6c696e676572696e675f706f74696f6e280200126d696e6563726166743a63616d7066697265420200106d696e6563726166743a736d6f6b65723aff00166d696e6563726166743a7761727065645f66656e6365fffe00186d696e6563726166743a636f6f6b65645f636869636b656e140100266d696e6563726166743a6c696768745f626c75655f676c617a65645f7465727261636f747461df0000156d696e6563726166743a73746f6e655f73776f7264380100146d696e6563726166743a7370696465725f657965160100196d696e6563726166743a686f7273655f737061776e5f656767c80100166d696e6563726166743a62616b65645f706f7461746f190100176d696e6563726166743a676f6c64656e5f636172726f741b0100176d696e6563726166743a7370727563655f7374616972738600001a6d696e6563726166743a706f69736f6e6f75735f706f7461746f1a0100146d696e6563726166743a656c656d656e745f3133e8ff00126d696e6563726166743a6f6273696469616e310000156d696e6563726166743a70756d706b696e5f7069651c0100196d696e6563726166743a6469616d6f6e645f7069636b6178653e0100116d696e6563726166743a6c616e7465726e30ff00146d696e6563726166743a69726f6e5f73776f7264330100166d696e6563726166743a736d6f6f74685f73746f6e6549ff00126d696e6563726166743a62656574726f6f741d01001a6d696e6563726166743a6d757369635f646973635f7374726164140200146d696e6563726166743a656c656d656e745f3433caff001a6d696e6563726166743a696e76697369626c65626564726f636b5f0000176d696e6563726166743a73776565745f626572726965731f0100156d696e6563726166743a7261626269745f73746577220100156d696e6563726166743a77686561745f73656564732301001b6d696e6563726166743a6974656d2e6372696d736f6e5f646f6f720cff000f6d696e6563726166743a6368657374360000176d696e6563726166743a70756d706b696e5f7365656473240100136d696e6563726166743a656c656d656e745f32f3ff00206d696e6563726166743a636f6d6d616e645f626c6f636b5f6d696e6563617274290200156d696e6563726166743a6d656c6f6e5f7365656473250100136d696e6563726166743a737061776e5f656767660200126d696e6563726166743a69726f6e5f6178652a0100156d696e6563726166743a6e65746865725f77617274260100186d696e6563726166743a62656574726f6f745f7365656473270100146d696e6563726166743a656c656d656e745f3335d2ff00156d696e6563726166743a656c656d656e745f3130348dff00156d696e6563726166743a69726f6e5f73686f76656c280100186d696e6563726166743a6772616e6974655f73746169727357ff00196d696e6563726166743a666c696e745f616e645f737465656c2b01001a6d696e6563726166743a7a6f676c696e5f737061776e5f656767f00100166d696e6563726166743a73746f6e655f73686f76656c390100156d696e6563726166743a6d656c6f6e5f626c6f636b6700000f6d696e6563726166743a6172726f772d01000e6d696e6563726166743a636f616c2e0100216d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c616232b50000126d696e6563726166743a63686172636f616c2f0100196d696e6563726166743a73747261795f737061776e5f656767cc0100116d696e6563726166743a636172726f74738d0000116d696e6563726166743a6469616d6f6e64300100166d696e6563726166743a776f6f64656e5f73776f7264340100196d696e6563726166743a6e65746865726974655f626f6f7473580200196d696e6563726166743a6d757369635f646973635f6d616c6c110200196d696e6563726166743a6461726b5f6f616b5f737461697273a40000146d696e6563726166743a776f6f64656e5f617865370100126d696e6563726166743a6661726d6c616e643c00001a6d696e6563726166743a6372696d736f6e5f74726170646f6f720aff00216d696e6563726166743a7a6f6d6269655f7069676d616e5f737061776e5f656767be0100176d696e6563726166743a73746f6e655f7069636b6178653a0100176d696e6563726166743a73616c6d6f6e5f6275636b65746d0100106d696e6563726166743a706c616e6b730500001a6d696e6563726166743a636861696e6d61696c5f68656c6d6574530100186d696e6563726166743a6469616d6f6e645f73686f76656c3d0100176d696e6563726166743a6469616d6f6e645f73776f72643c0100186d696e6563726166743a736d697468696e675f7461626c6536ff00156d696e6563726166743a6469616d6f6e645f6178653f01000f6d696e6563726166743a737469636b400100176d696e6563726166743a666c6f77696e675f77617465720800000e6d696e6563726166743a626f776c410100166d696e6563726166743a676f6c64656e5f73776f7264420100156d696e6563726166743a686f6e65795f626c6f636b24ff00176d696e6563726166743a676f6c64656e5f73686f76656c430100106d696e6563726166743a656c797472612a02001b6d696e6563726166743a6c69745f72656473746f6e655f6c616d707c0000186d696e6563726166743a676f6c64656e5f7069636b617865440100146d696e6563726166743a676f6c64656e5f617865450100146d696e6563726166743a656c656d656e745f3532c1ff00106d696e6563726166743a737472696e67460100216d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c61623458ff00116d696e6563726166743a66656174686572470100136d696e6563726166743a67756e706f776465724801001e6d696e6563726166743a736b756c6c5f62616e6e65725f7061747465726e3d0200176d696e6563726166743a6163616369615f737461697273a30000146d696e6563726166743a776f6f64656e5f686f65490100196d696e6563726166743a70616e64615f737061776e5f656767e70100136d696e6563726166743a73746f6e655f686f654a0100126d696e6563726166743a69726f6e5f686f654b0100146d696e6563726166743a656c656d656e745f38369fff00156d696e6563726166743a6469616d6f6e645f686f654c0100146d696e6563726166743a676f6c64656e5f686f654d0100156d696e6563726166743a6d6167656e74615f6479659601000f6d696e6563726166743a77686561744e0100186d696e6563726166743a6c6561746865725f68656c6d65744f01001c6d696e6563726166743a6c6561746865725f6368657374706c6174655001001a6d696e6563726166743a6c6561746865725f6c656767696e6773510100206d696e6563726166743a676c6973746572696e675f6d656c6f6e5f736c696365b00100136d696e6563726166743a6c6f646573746f6e6522ff00186d696e6563726166743a62726f776e5f6d757368726f6f6d270000176d696e6563726166743a6c6561746865725f626f6f7473520100156d696e6563726166743a656e645f67617465776179d100001e6d696e6563726166743a636861696e6d61696c5f6368657374706c617465540100176d696e6563726166743a6974656d2e62656574726f6f74f40000156d696e6563726166743a656c656d656e745f31303190ff001c6d696e6563726166743a636861696e6d61696c5f6c656767696e6773550100196d696e6563726166743a636861696e6d61696c5f626f6f7473560100136d696e6563726166743a736f756c5f73616e64580000156d696e6563726166743a69726f6e5f68656c6d6574570100126d696e6563726166743a736e6f7762616c6c740100146d696e6563726166743a656c656d656e745f3439c4ff00196d696e6563726166743a69726f6e5f6368657374706c617465580100106d696e6563726166743a62617272656c35ff00176d696e6563726166743a69726f6e5f6c656767696e6773590100146d696e6563726166743a69726f6e5f626f6f74735a0100216d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c61623359ff00136d696e6563726166743a656e6465725f657965af01001c6d696e6563726166743a6d757369635f646973635f70696773746570600200226d696e6563726166743a737469636b79706973746f6e61726d636f6c6c6973696f6e27ff00176d696e6563726166743a69726f6e5f74726170646f6f72a70000186d696e6563726166743a6469616d6f6e645f68656c6d65745b01001e6d696e6563726166743a73746f6e655f70726573737572655f706c6174654600001c6d696e6563726166743a6469616d6f6e645f6368657374706c6174655c01000e6d696e6563726166743a73616e640c0000276d696e6563726166743a6c696768745f77656967687465645f70726573737572655f706c617465930000106d696e6563726166743a706973746f6e2100001a6d696e6563726166743a6469616d6f6e645f6c656767696e67735d0100146d696e6563726166743a656c656d656e745f3330d7ff00176d696e6563726166743a6469616d6f6e645f626f6f74735e0100176d696e6563726166743a676f6c64656e5f68656c6d65745f0100146d696e6563726166743a656c656d656e745f3531c2ff001c6d696e6563726166743a646f75626c655f776f6f64656e5f736c61629d0000146d696e6563726166743a656c656d656e745f3834a1ff001c6d696e6563726166743a686172645f737461696e65645f676c617373fe00001b6d696e6563726166743a676f6c64656e5f6368657374706c617465600100146d696e6563726166743a7365616c616e7465726ea90000136d696e6563726166743a676c6f7773746f6e65590000196d696e6563726166743a676f6c64656e5f6c656767696e6773610100166d696e6563726166743a676f6c64656e5f626f6f7473620100106d696e6563726166743a736869656c646301001b6d696e6563726166743a6a756e676c655f66656e63655f67617465b90000166d696e6563726166743a666c6f77696e675f6c6176610a0000196d696e6563726166743a6167656e745f737061776e5f656767e50100106d696e6563726166743a636172706574ab00000f6d696e6563726166743a666c696e74640100126d696e6563726166743a7061696e74696e676501001a6d696e6563726166743a68656172745f6f665f7468655f736561310200226d696e6563726166743a6d6f7373795f636f62626c6573746f6e655f7374616972734dff00126d696e6563726166743a6f616b5f7369676e660100196d696e6563726166743a6d757369635f646973635f77616974170200146d696e6563726166743a656c656d656e745f3535beff00156d696e6563726166743a776f6f64656e5f646f6f72670100156d696e6563726166743a6d696c6b5f6275636b6574690100146d696e6563726166743a656c656d656e745f3734abff00166d696e6563726166743a77617465725f6275636b65746a01001b6d696e6563726166743a7368756c6b65725f737061776e5f656767d30100116d696e6563726166743a7265645f6479658a01000e6d696e6563726166743a626f6e659d0100236d696e6563726166743a6d6167656e74615f676c617a65645f7465727261636f747461de0000156d696e6563726166743a6c6176615f6275636b65746b01001e6d696e6563726166743a76696e64696361746f725f737061776e5f656767d80100146d696e6563726166743a636f645f6275636b65746c01001e6d696e6563726166743a74726f706963616c5f666973685f6275636b65746e0100136d696e6563726166743a656c656d656e745f36efff001b6d696e6563726166743a707566666572666973685f6275636b65746f0100196d696e6563726166743a636f6e63726574655f706f77646572ed0000126d696e6563726166743a6d696e6563617274700100106d696e6563726166743a736164646c657101001b6d696e6563726166743a6e65746865725f776172745f626c6f636bd60000156d696e6563726166743a656c656d656e745f31313681ff00176d696e6563726166743a6372696d736f6e5f726f6f747321ff00136d696e6563726166743a69726f6e5f646f6f72720100126d696e6563726166743a72656473746f6e65730100226d696e6563726166743a656c6465725f677561726469616e5f737061776e5f656767d50100126d696e6563726166743a63726f7373626f77350200186d696e6563726166743a616374697661746f725f7261696c7e0000126d696e6563726166743a6f616b5f626f6174750100146d696e6563726166743a656c656d656e745f393794ff00146d696e6563726166743a62697263685f626f6174760100146d696e6563726166743a707269736d6172696e65a80000216d696e6563726166743a706f6c69736865645f6772616e6974655f73746169727354ff00156d696e6563726166743a6a756e676c655f626f61747701001e6d696e6563726166743a73696c766572666973685f737061776e5f656767b90100196d696e6563726166743a6368656d69737472795f7461626c65ee0000156d696e6563726166743a7370727563655f626f6174780100146d696e6563726166743a656c656d656e745f3236dbff00156d696e6563726166743a6163616369615f626f6174790100176d696e6563726166743a6461726b5f6f616b5f626f61747a0100126d696e6563726166743a69726f6e5f6f72650f0000166d696e6563726166743a7772697474656e5f626f6f6bf50100116d696e6563726166743a6c6561746865727b01000e6d696e6563726166743a6b656c707c0100156d696e6563726166743a676f6c645f6e7567676574a701000f6d696e6563726166743a627269636b7d0100136d696e6563726166743a636c61795f62616c6c7e0100146d696e6563726166743a73756761725f63616e657f0100156d696e6563726166743a6c69745f70756d706b696e5b0000196d696e6563726166743a6e65746865726974655f696e676f744f02000f6d696e6563726166743a7061706572800100146d696e6563726166743a656c656d656e745f3233deff000f6d696e6563726166743a636f72616c7dff000e6d696e6563726166743a626f6f6b810100146d696e6563726166743a656e645f706f7274616c770000116d696e6563726166743a74726964656e74180200146d696e6563726166743a736c696d655f62616c6c820100186d696e6563726166743a63686573745f6d696e65636172748301000d6d696e6563726166743a656767840100176d696e6563726166743a636f775f737061776e5f656767b20100196d696e6563726166743a6d757369635f646973635f7374616c130200196d696e6563726166743a6e65746865726974655f73776f7264500200146d696e6563726166743a6974656d2e7265656473530000116d696e6563726166743a636f6d70617373850100186d696e6563726166743a6372696d736f6e5f73746169727302ff00156d696e6563726166743a66697368696e675f726f64860100136d696e6563726166743a726573657276656436ff0000196d696e6563726166743a616e6465736974655f73746169727355ff000f6d696e6563726166743a636c6f636b8701001a6d696e6563726166743a6f63656c6f745f737061776e5f656767c10100176d696e6563726166743a7370727563655f627574746f6e70ff00176d696e6563726166743a7265645f73616e6473746f6e65b30000186d696e6563726166743a676c6f7773746f6e655f64757374880100136d696e6563726166743a626c61636b5f647965890100136d696e6563726166743a677265656e5f6479658b0100156d696e6563726166743a7368756c6b65725f626f78da00000e6d696e6563726166743a64656e79d30000176d696e6563726166743a6265655f737061776e5f656767ec0100136d696e6563726166743a62726f776e5f6479658c0100126d696e6563726166743a626c75655f6479658d01000f6d696e6563726166743a6672616d65f701001b6d696e6563726166743a62726577696e677374616e64626c6f636b750000136d696e6563726166743a6974656d2e63616b655c0000146d696e6563726166743a707572706c655f6479658e01000d6d696e6563726166743a647965640200176d696e6563726166743a6d757369635f646973635f31330c0200126d696e6563726166743a6379616e5f6479658f0100136d696e6563726166743a626c617a655f726f64a50100186d696e6563726166743a6c696768745f677261795f647965900100126d696e6563726166743a677261795f647965910100206d696e6563726166743a7069676c696e5f62727574655f737061776e5f656767f10100146d696e6563726166743a656c656d656e745f3431ccff001a6d696e6563726166743a7261626269745f737061776e5f656767c90100126d696e6563726166743a70696e6b5f647965920100126d696e6563726166743a6c696d655f647965930100146d696e6563726166743a79656c6c6f775f647965940100176d696e6563726166743a626c6173745f6675726e6163653cff00146d696e6563726166743a656c656d656e745f3130ebff00186d696e6563726166743a6c696768745f626c75655f647965950100146d696e6563726166743a747572746c655f65676761ff000d6d696e6563726166743a626564a00100176d696e6563726166743a737461696e65645f676c617373f10000146d696e6563726166743a6f72616e67655f647965970100146d696e6563726166743a656c656d656e745f3134e7ff00136d696e6563726166743a77686974655f647965980100196d696e6563726166743a6974656d2e666c6f7765725f706f748c0000136d696e6563726166743a626f6e655f6d65616c990100176d696e6563726166743a747572746c655f68656c6d6574330200116d696e6563726166743a756e6b6e6f776ecffe00116d696e6563726166743a696e6b5f7361639b01001f6d696e6563726166743a73747269707065645f6372696d736f6e5f7374656d10ff00166d696e6563726166743a6c617069735f6c617a756c699c0100166d696e6563726166743a63686f7275735f6672756974240200106d696e6563726166743a63616d657261460200196d696e6563726166743a737573706963696f75735f737465774302000f6d696e6563726166743a73756761729e01001b6d696e6563726166743a637265657065725f737061776e5f656767b70100126d696e6563726166743a6e616d655f7461671a02000e6d696e6563726166743a63616b659f0100126d696e6563726166743a7265706561746572a10100106d696e6563726166743a626561636f6e8a00001e6d696e6563726166743a6e65746865726974655f6368657374706c617465560200226d696e6563726166743a706f6c69736865645f616e6465736974655f73746169727352ff00146d696e6563726166743a66696c6c65645f6d6170a201001b6d696e6563726166743a64726f776e65645f737061776e5f656767e101001e6d696e6563726166743a756e706f77657265645f636f6d70617261746f72950000106d696e6563726166743a736865617273a30100146d696e6563726166743a656c656d656e745f3331d6ff00156d696e6563726166743a656e6465725f706561726ca401001e6d696e6563726166743a7265645f73616e6473746f6e655f737461697273b40000186d696e6563726166743a6361727665645f70756d706b696e65ff00146d696e6563726166743a67686173745f74656172a60100166d696e6563726166743a676c6173735f626f74746c65a90100176d696e6563726166743a636f6f6b65645f6d7574746f6e1d0200146d696e6563726166743a656c656d656e745f3434c9ff002a6d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f737461697273edfe001f6d696e6563726166743a6a756e676c655f70726573737572655f706c61746567ff001e6d696e6563726166743a6665726d656e7465645f7370696465725f657965aa0100196d696e6563726166743a686f6e6579636f6d625f626c6f636b23ff00166d696e6563726166743a626c617a655f706f77646572ab0100156d696e6563726166743a6d61676d615f637265616dac0100106d696e6563726166743a6a69677361772dff00176d696e6563726166743a62726577696e675f7374616e64ad0100156d696e6563726166743a656c656d656e745f31313186ff00126d696e6563726166743a6361756c64726f6eae01001b6d696e6563726166743a636869636b656e5f737061776e5f656767b10100176d696e6563726166743a7069675f737061776e5f656767b30100196d696e6563726166743a73686565705f737061776e5f656767b401001a6d696e6563726166743a706172726f745f737061776e5f656767dc0100186d696e6563726166743a776f6c665f737061776e5f656767b501001d6d696e6563726166743a6d6f6f7368726f6f6d5f737061776e5f656767b60100146d696e6563726166743a66656e63655f676174656b00001c6d696e6563726166743a736b656c65746f6e5f737061776e5f656767ba01001c6d696e6563726166743a646f75626c655f73746f6e655f736c6162335eff00156d696e6563726166743a627269636b5f626c6f636b2d00001a6d696e6563726166743a7370696465725f737061776e5f656767bc0100106d696e6563726166743a626c656163684902001a6d696e6563726166743a636f6c6f7265645f746f7263685f7267ca00001a6d696e6563726166743a7a6f6d6269655f737061776e5f656767bd0100146d696e6563726166743a656c656d656e745f3231e0ff001c6d696e6563726166743a76696c6c616765725f737061776e5f656767bf0100136d696e6563726166743a636f6d706f737465722bff00196d696e6563726166743a73717569645f737061776e5f656767c001001c6d696e6563726166743a706f77657265645f636f6d70617261746f72960000176d696e6563726166743a6261745f737061776e5f656767c30100196d696e6563726166743a67686173745f737061776e5f656767c40100136d696e6563726166743a656c656d656e745f30240000156d696e6563726166743a6d6f625f737061776e6572340000206d696e6563726166743a63686973656c65645f6e65746865725f627269636b73d2fe001e6d696e6563726166743a6d61676d615f637562655f737061776e5f656767c50100156d696e6563726166743a7761727065645f7369676e5b02000f6d696e6563726166743a636861696e5f0200226d696e6563726166743a7761727065645f66756e6775735f6f6e5f615f737469636b5e02001f6d696e6563726166743a636176655f7370696465725f737061776e5f656767c70100176d696e6563726166743a736f756c5f63616d70666972656202001d6d696e6563726166743a656e6465726d6974655f737061776e5f656767ca01001c6d696e6563726166743a677561726469616e5f737061776e5f656767cb0100176d696e6563726166743a6372696d736f6e5f66656e636500ff00186d696e6563726166743a6875736b5f737061776e5f656767cd01001a6d696e6563726166743a7069676c696e5f737061776e5f656767ef0100176d696e6563726166743a77656570696e675f76696e657319ff00236d696e6563726166743a7769746865725f736b656c65746f6e5f737061776e5f656767ce0100196d696e6563726166743a676c6f77696e676f6273696469616ef60000116d696e6563726166743a6c656176657332a100001a6d696e6563726166743a646f6e6b65795f737061776e5f656767cf0100156d696e6563726166743a7370727563655f7369676e360200146d696e6563726166743a656c656d656e745f3539baff00186d696e6563726166743a6d756c655f737061776e5f656767d00100166d696e6563726166743a646f75626c655f706c616e74af0000156d696e6563726166743a656c656d656e745f31303988ff00226d696e6563726166743a736b656c65746f6e5f686f7273655f737061776e5f656767d101001b6d696e6563726166743a6e65746865726974655f7069636b617865520200116d696e6563726166743a6a756b65626f78540000206d696e6563726166743a7a6f6d6269655f686f7273655f737061776e5f656767d20100176d696e6563726166743a6e70635f737061776e5f656767d40100136d696e6563726166743a69726f6e5f62617273650000146d696e6563726166743a656c656d656e745f3830a5ff001e6d696e6563726166743a706f6c61725f626561725f737061776e5f656767d60100136d696e6563726166743a656e645f73746f6e65790000196d696e6563726166743a6c6c616d615f737061776e5f656767d70100196d696e6563726166743a6974656d2e62697263685f646f6f72c200001a6d696e6563726166743a65766f6b65725f737061776e5f656767d90100176d696e6563726166743a6d757369635f646973635f31311602001a6d696e6563726166743a6c69745f72656473746f6e655f6f72654a0000186d696e6563726166743a6372616674696e675f7461626c653a0000216d696e6563726166743a626c61636b5f676c617a65645f7465727261636f747461eb0000146d696e6563726166743a656c656d656e745f3537bcff001a6d696e6563726166743a7370727563655f77616c6c5f7369676e4aff00176d696e6563726166743a7665785f737061776e5f656767da0100196d696e6563726166743a7761727065645f74726170646f6f7209ff00186d696e6563726166743a7477697374696e675f76696e6573e1fe00246d696e6563726166743a6461796c696768745f6465746563746f725f696e766572746564b20000236d696e6563726166743a7a6f6d6269655f76696c6c616765725f737061776e5f656767db01001a6d696e6563726166743a72617069645f66657274696c697a65724a02000e6d696e6563726166743a636c6179520000216d696e6563726166743a74726f706963616c5f666973685f737061776e5f656767dd0100176d696e6563726166743a7374616e64696e675f7369676e3f0000176d696e6563726166743a636f645f737061776e5f656767de0100146d696e6563726166743a6974656d2e6672616d65c70000186d696e6563726166743a6372696d736f6e5f66756e6775731cff001e6d696e6563726166743a707566666572666973685f737061776e5f656767df01001c6d696e6563726166743a7265645f6d757368726f6f6d5f626c6f636b6400001a6d696e6563726166743a73616c6d6f6e5f737061776e5f656767e00100156d696e6563726166743a7761727065645f736c6162f7fe001c6d696e6563726166743a646f75626c655f73746f6e655f736c616232b600001b6d696e6563726166743a646f6c7068696e5f737061776e5f656767e20100136d696e6563726166743a656c656d656e745f39ecff001a6d696e6563726166743a747572746c655f737061776e5f656767e301001b6d696e6563726166743a7068616e746f6d5f737061776e5f656767e40100146d696e6563726166743a656c656d656e745f3238d9ff001a6d696e6563726166743a6974656d2e6163616369615f646f6f72c40000176d696e6563726166743a6361745f737061776e5f656767e60100176d696e6563726166743a666f785f737061776e5f656767e801001a6d696e6563726166743a636f62626c6573746f6e655f77616c6c8b0000106d696e6563726166743a71756172747a0202001b6d696e6563726166743a636172726f745f6f6e5f615f737469636bfb0100246d696e6563726166743a77616e646572696e675f7472616465725f737061776e5f656767ea0100126d696e6563726166743a74726170646f6f726000001a6d696e6563726166743a686f676c696e5f737061776e5f656767ee01001b6d696e6563726166743a657870657269656e63655f626f74746c65f20100196d696e6563726166743a6a756e676c655f74726170646f6f726cff00156d696e6563726166743a666972655f636861726765f30100146d696e6563726166743a656c656d656e745f3639b0ff00176d696e6563726166743a7772697461626c655f626f6f6bf40100116d696e6563726166743a656d6572616c64f60100146d696e6563726166743a666c6f7765725f706f74f80100106d696e6563726166743a6c6561766573120000136d696e6563726166743a656d7074795f6d6170f901000f6d696e6563726166743a736b756c6cfa0100186d696e6563726166743a6372696d736f6e5f6e796c69756d18ff00196d696e6563726166743a66697265776f726b5f726f636b6574fd0100156d696e6563726166743a656c656d656e745f3130328fff00176d696e6563726166743a66697265776f726b5f73746172fe01001a6d696e6563726166743a636f6c6f7265645f746f7263685f6270cc0000186d696e6563726166743a656e6368616e7465645f626f6f6bff01001a6d696e6563726166743a746f74656d5f6f665f756e6479696e672e0200156d696e6563726166743a6e6574686572627269636b010200166d696e6563726166743a746e745f6d696e6563617274030200146d696e6563726166743a656c656d656e745f3633b6ff00196d696e6563726166743a686f707065725f6d696e6563617274040200176d696e6563726166743a647261676f6e5f627265617468260200156d696e6563726166743a636f62626c6573746f6e65040000106d696e6563726166743a686f70706572050200156d696e6563726166743a7261626269745f686964650702001d6d696e6563726166743a6c6561746865725f686f7273655f61726d6f720802001a6d696e6563726166743a69726f6e5f686f7273655f61726d6f720902001d6d696e6563726166743a6469616d6f6e645f686f7273655f61726d6f720b0200186d696e6563726166743a6d757369635f646973635f6361740d0200156d696e6563726166743a6a756e676c655f646f6f722102001b6d696e6563726166743a6d757369635f646973635f626c6f636b730e0200136d696e6563726166743a73616e6473746f6e65180000176d696e6563726166743a776f6f64656e5f627574746f6e8f0000186d696e6563726166743a6d757369635f646973635f6661721002001c6d696e6563726166743a6d757369635f646973635f6d656c6c6f6869120200166d696e6563726166743a696e666f5f75706461746532f900000e6d696e6563726166743a6c6561641902001d6d696e6563726166743a707269736d6172696e655f6372797374616c731b0200156d696e6563726166743a6163616369615f7369676e390200106d696e6563726166743a6d7574746f6e1c0200146d696e6563726166743a656c656d656e745f3332d5ff00126d696e6563726166743a636f616c5f6f7265100000156d696e6563726166743a61726d6f725f7374616e641e0200156d696e6563726166743a7370727563655f646f6f721f02001a6d696e6563726166743a7068616e746f6d5f6d656d6272616e65340200146d696e6563726166743a62697263685f646f6f72200200156d696e6563726166743a6163616369615f646f6f72220200146d696e6563726166743a656c656d656e745f3432cbff00176d696e6563726166743a6461726b5f6f616b5f646f6f722302001c6d696e6563726166743a6e65746865726974655f6c656767696e67735702001d6d696e6563726166743a706f707065645f63686f7275735f6672756974250200146d696e6563726166743a656c656d656e745f3733acff00176d696e6563726166743a73706c6173685f706f74696f6e270200216d696e6563726166743a6461726b5f6f616b5f70726573737572655f706c61746568ff001a6d696e6563726166743a707269736d6172696e655f73686172642b0200126d696e6563726166743a73656167726173737eff00176d696e6563726166743a7368756c6b65725f7368656c6c2c0200186d696e6563726166743a72656473746f6e655f626c6f636b980000106d696e6563726166743a62616e6e65722d0200156d696e6563726166743a69726f6e5f6e75676765742f0200146d696e6563726166743a656c656d656e745f3338cfff00196d696e6563726166743a636f72616c5f66616e5f68616e673278ff00146d696e6563726166743a62697263685f7369676e370200186d696e6563726166743a636f72616c5f66616e5f646561647aff00116d696e6563726166743a62616c6c6f6f6e4b0200156d696e6563726166743a6a756e676c655f7369676e380200176d696e6563726166743a6461726b5f6f616b5f7369676e3a02001f6d696e6563726166743a666c6f7765725f62616e6e65725f7061747465726e3b0200216d696e6563726166743a706f6c69736865645f64696f726974655f73746169727353ff001f6d696e6563726166743a6d6f6a616e675f62616e6e65725f7061747465726e3e0200156d696e6563726166743a6d6f6e737465725f656767610000266d696e6563726166743a6669656c645f6d61736f6e65645f62616e6e65725f7061747465726e3f02000e6d696e6563726166743a62656c6c32ff00296d696e6563726166743a626f72647572655f696e64656e7465645f62616e6e65725f7061747465726e400200126d696e6563726166743a706f7461746f65738e00001f6d696e6563726166743a7069676c696e5f62616e6e65725f7061747465726e410200146d696e6563726166743a656c656d656e745f3738a7ff00136d696e6563726166743a686f6e6579636f6d624402001a6d696e6563726166743a7265645f6e65746865725f627269636bd70000166d696e6563726166743a686f6e65795f626f74746c65450200126d696e6563726166743a636f6d706f756e64470200126d696e6563726166743a6963655f626f6d62480200126d696e6563726166743a6d65646963696e654c0200176d696e6563726166743a7761727065645f66756e6775731bff00146d696e6563726166743a656c656d656e745f393299ff001a6d696e6563726166743a656e645f706f7274616c5f6672616d65780000146d696e6563726166743a676c6f775f737469636ba60000126d696e6563726166743a626c75655f696365f5ff00146d696e6563726166743a656c656d656e745f3833a2ff001b6d696e6563726166743a6c6f646573746f6e655f636f6d706173734e0200146d696e6563726166743a71756172747a5f6f72659900001a6d696e6563726166743a6e65746865726974655f73686f76656c5102001d6d696e6563726166743a636861696e5f636f6d6d616e645f626c6f636bbd00000e6d696e6563726166743a6c6f6f6d34ff001a6d696e6563726166743a6974656d2e7761727065645f646f6f720bff00176d696e6563726166743a6e65746865726974655f617865530200176d696e6563726166743a6e65746865726974655f686f655402001a6d696e6563726166743a6e65746865726974655f68656c6d6574550200196d696e6563726166743a6e65746865726974655f7363726170590200166d696e6563726166743a6372696d736f6e5f7369676e5a0200126d696e6563726166743a636f6e6372657465ec0000166d696e6563726166743a6372696d736f6e5f646f6f725c0200106d696e6563726166743a73706f6e6765130000186d696e6563726166743a6e65746865725f7370726f7574736102001b6d696e6563726166743a636172746f6772617068795f7461626c6538ff00196d696e6563726166743a626c61636b73746f6e655f736c6162e6fe00226d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f736c6162dbfe000f6d696e6563726166743a73746f6e650100000e6d696e6563726166743a776f6f6c230000176d696e6563726166743a79656c6c6f775f666c6f7765722500001f6d696e6563726166743a737461696e65645f68617264656e65645f636c61799f00000d6d696e6563726166743a6c6f671100000f6d696e6563726166743a66656e6365550000146d696e6563726166743a656c656d656e745f3533c0ff00146d696e6563726166743a73746f6e65627269636b6200001b6d696e6563726166743a6c69745f626c6173745f6675726e6163652aff00156d696e6563726166743a636f72616c5f626c6f636b7cff00246d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b73eefe00156d696e6563726166743a656c656d656e745f31303091ff001b6d696e6563726166743a646f75626c655f73746f6e655f736c61622c00000e6d696e6563726166743a7261696c4200001c6d696e6563726166743a646f75626c655f73746f6e655f736c6162345aff001d6d696e6563726166743a73747269707065645f6163616369615f6c6f67f8ff00206d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c61622b0000136d696e6563726166743a636f72616c5f66616e7bff00246d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627574746f6ed8fe00146d696e6563726166743a7365615f7069636b6c6564ff00296d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f646f75626c655f736c6162dafe00116d696e6563726166743a7361706c696e67060000166d696e6563726166743a7761727065645f726f6f747320ff00146d696e6563726166743a656c656d656e745f3131eaff00146d696e6563726166743a7265645f666c6f776572260000136d696e6563726166743a77617465726c696c796f0000166d696e6563726166743a71756172747a5f626c6f636b9b0000136d696e6563726166743a736f756c5f736f696c14ff001f6d696e6563726166743a6163616369615f70726573737572655f706c6174656aff00136d696e6563726166743a74616c6c67726173731f0000156d696e6563726166743a656c656d656e745f3130338eff001e6d696e6563726166743a62726f776e5f6d757368726f6f6d5f626c6f636b6300000e6d696e6563726166743a6c6f6732a20000116d696e6563726166743a636f6e6475697463ff000f6d696e6563726166743a6d61676d61d50000146d696e6563726166743a656c656d656e745f3232dfff001c6d696e6563726166743a756e647965645f7368756c6b65725f626f78cd00001e6d696e6563726166743a7370727563655f7374616e64696e675f7369676e4bff00176d696e6563726166743a737469636b795f706973746f6e1d0000106d696e6563726166743a62616d626f6f5dff00126d696e6563726166743a6f62736572766572fb0000156d696e6563726166743a73636166666f6c64696e675bff00146d696e6563726166743a6772696e6473746f6e653dff00116d696e6563726166743a656e645f726f64d00000196d696e6563726166743a666c65746368696e675f7461626c6537ff00156d696e6563726166743a6974656d2e686f707065729a00000e6d696e6563726166743a776f6f642cff000d6d696e6563726166743a746e742e0000216d696e6563726166743a686172645f737461696e65645f676c6173735f70616e65bf00000f6d696e6563726166743a736c696d65a50000116d696e6563726166743a70756d706b696e560000166d696e6563726166743a6372696d736f6e5f736c6162f8fe00136d696e6563726166743a656c656d656e745f33f2ff00136d696e6563726166743a656c656d656e745f34f1ff00156d696e6563726166743a656e6465725f6368657374820000136d696e6563726166743a656c656d656e745f35f0ff00136d696e6563726166743a656c656d656e745f38edff00146d696e6563726166743a656c656d656e745f3132e9ff00146d696e6563726166743a656c656d656e745f3137e4ff00146d696e6563726166743a656c656d656e745f3138e3ff00146d696e6563726166743a656c656d656e745f3139e2ff00146d696e6563726166743a656c656d656e745f3230e1ff00146d696e6563726166743a656c656d656e745f3234ddff00146d696e6563726166743a656c656d656e745f3239d8ff00146d696e6563726166743a656c656d656e745f3333d4ff00146d696e6563726166743a656c656d656e745f3336d1ff000d6d696e6563726166743a6963654f0000146d696e6563726166743a656c656d656e745f3337d0ff00146d696e6563726166743a656c656d656e745f3339ceff00146d696e6563726166743a656c656d656e745f3430cdff00146d696e6563726166743a656c656d656e745f3435c8ff00146d696e6563726166743a656c656d656e745f3436c7ff00146d696e6563726166743a656c656d656e745f3437c6ff00146d696e6563726166743a656c656d656e745f3438c5ff00146d696e6563726166743a656c656d656e745f3534bfff00146d696e6563726166743a656c656d656e745f3536bdff00146d696e6563726166743a656c656d656e745f3538bbff00146d696e6563726166743a656c656d656e745f3630b9ff00146d696e6563726166743a656c656d656e745f3634b5ff00146d696e6563726166743a656c656d656e745f3635b4ff00146d696e6563726166743a656c656d656e745f3636b3ff00146d696e6563726166743a656c656d656e745f3637b2ff00146d696e6563726166743a656c656d656e745f3638b1ff00146d696e6563726166743a656c656d656e745f3730afff00146d696e6563726166743a656c656d656e745f3731aeff00146d696e6563726166743a656c656d656e745f3732adff00146d696e6563726166743a656c656d656e745f3735aaff00146d696e6563726166743a656c656d656e745f3736a9ff00196d696e6563726166743a6461726b5f6f616b5f627574746f6e72ff00146d696e6563726166743a656c656d656e745f3737a8ff00186d696e6563726166743a72656473746f6e655f746f7263684c0000186d696e6563726166743a64696f726974655f73746169727356ff00146d696e6563726166743a656c656d656e745f3739a6ff00146d696e6563726166743a656c656d656e745f3831a4ff00146d696e6563726166743a656c656d656e745f3832a3ff00226d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f77616c6cd7fe00146d696e6563726166743a656c656d656e745f3835a0ff00146d696e6563726166743a656c656d656e745f38379eff00146d696e6563726166743a656c656d656e745f38389dff00146d696e6563726166743a656c656d656e745f38399cff00146d696e6563726166743a656c656d656e745f39309bff00146d696e6563726166743a656c656d656e745f39319aff00146d696e6563726166743a656c656d656e745f393398ff00146d696e6563726166743a656c656d656e745f393497ff00146d696e6563726166743a656c656d656e745f393596ff00146d696e6563726166743a656c656d656e745f393695ff00146d696e6563726166743a656c656d656e745f393893ff00106d696e6563726166743a636163747573510000146d696e6563726166743a656c656d656e745f393992ff00156d696e6563726166743a656c656d656e745f3130358cff00156d696e6563726166743a656c656d656e745f3130368bff00206d696e6563726166743a6379616e5f676c617a65645f7465727261636f747461e50000156d696e6563726166743a656c656d656e745f3130378aff00156d696e6563726166743a656c656d656e745f31303889ff00156d696e6563726166743a656c656d656e745f31313087ff00156d696e6563726166743a656c656d656e745f31313285ff00176d696e6563726166743a7761727065645f627574746f6efbfe00156d696e6563726166743a656c656d656e745f31313384ff00166d696e6563726166743a62697263685f737461697273870000156d696e6563726166743a656c656d656e745f31313483ff001d6d696e6563726166743a6461726b5f6f616b5f66656e63655f67617465ba0000156d696e6563726166743a656c656d656e745f31313582ff00156d696e6563726166743a656c656d656e745f31313780ff00156d696e6563726166743a656c656d656e745f3131387fff00196d696e6563726166743a6e65746865726974655f626c6f636bf2fe00186d696e6563726166743a7265737061776e5f616e63686f72f0fe00196d696e6563726166743a637279696e675f6f6273696469616edffe000e6d696e6563726166743a626f6174630200186d696e6563726166743a62616e6e65725f7061747465726e650200156d696e6563726166743a656e645f6372797374616c6702000e6d696e6563726166743a736e6f77500000176d696e6563726166743a6465746563746f725f7261696c1c0000176d696e6563726166743a6163616369615f627574746f6e74ff00176d696e6563726166743a71756172747a5f7374616972739c00001b6d696e6563726166743a6163616369615f66656e63655f67617465bb00001e6d696e6563726166743a6163616369615f7374616e64696e675f7369676e42ff00196d696e6563726166743a6163616369615f74726170646f6f726fff00176d696e6563726166743a7075727075725f737461697273cb00001a6d696e6563726166743a6163616369615f77616c6c5f7369676e41ff000f6d696e6563726166743a616c6c6f77d20000196d696e6563726166743a7374616e64696e675f62616e6e6572b00000186d696e6563726166743a62616d626f6f5f7361706c696e675cff00156d696e6563726166743a66726f737465645f696365cf0000116d696e6563726166743a626172726965725fff00106d696e6563726166743a626173616c7416ff00126d696e6563726166743a6974656d2e6265641a0000116d696e6563726166743a626564726f636b070000126d696e6563726166743a6265655f6e65737426ff00116d696e6563726166743a6265656869766525ff00166d696e6563726166743a62697263685f627574746f6e73ff001a6d696e6563726166743a62697263685f66656e63655f67617465b800001e6d696e6563726166743a62697263685f70726573737572655f706c61746569ff00266d696e6563726166743a63686973656c65645f706f6c69736865645f626c61636b73746f6e65e9fe001d6d696e6563726166743a62697263685f7374616e64696e675f7369676e46ff00186d696e6563726166743a62697263685f74726170646f6f726eff00196d696e6563726166743a62697263685f77616c6c5f7369676e45ff00176d696e6563726166743a63686f7275735f666c6f776572c80000146d696e6563726166743a626c61636b73746f6e65effe00106d696e6563726166743a74617267657411ff00206d696e6563726166743a626c61636b73746f6e655f646f75626c655f736c6162e5fe001a6d696e6563726166743a64726965645f6b656c705f626c6f636b75ff001b6d696e6563726166743a626c61636b73746f6e655f737461697273ecfe00196d696e6563726166743a626c61636b73746f6e655f77616c6cebfe00206d696e6563726166743a626c75655f676c617a65645f7465727261636f747461e70000146d696e6563726166743a626f6e655f626c6f636bd80000166d696e6563726166743a626f726465725f626c6f636bd40000136d696e6563726166743a77616c6c5f7369676e440000226d696e6563726166743a6f72616e67655f676c617a65645f7465727261636f747461dd0000166d696e6563726166743a627269636b5f7374616972736c0000216d696e6563726166743a62726f776e5f676c617a65645f7465727261636f747461e80000176d696e6563726166743a627562626c655f636f6c756d6e60ff00156d696e6563726166743a6974656d2e63616d657261f20000176d696e6563726166743a6974656d2e6361756c64726f6e760000146d696e6563726166743a6974656d2e636861696ee2fe00176d696e6563726166743a6368656d6963616c5f68656174c00000146d696e6563726166743a676f6c645f626c6f636b290000166d696e6563726166743a63686f7275735f706c616e74f00000146d696e6563726166743a636f616c5f626c6f636bad00000f6d696e6563726166743a636f636f617f0000146d696e6563726166743a7061636b65645f696365ae0000186d696e6563726166743a636f72616c5f66616e5f68616e6779ff00196d696e6563726166743a636f72616c5f66616e5f68616e673377ff001f6d696e6563726166743a637261636b65645f6e65746865725f627269636b73d1fe002c6d696e6563726166743a637261636b65645f706f6c69736865645f626c61636b73746f6e655f627269636b73e8fe00186d696e6563726166743a6372696d736f6e5f627574746f6efcfe001d6d696e6563726166743a6372696d736f6e5f646f75626c655f736c6162f6fe001c6d696e6563726166743a6372696d736f6e5f66656e63655f67617465fefe00186d696e6563726166743a6372696d736f6e5f687970686165d5fe00156d696e6563726166743a656d6572616c645f6f7265810000186d696e6563726166743a6372696d736f6e5f706c616e6b730eff001b6d696e6563726166743a7370727563655f66656e63655f67617465b70000206d696e6563726166743a6372696d736f6e5f70726573737572655f706c617465fafe001f6d696e6563726166743a6372696d736f6e5f7374616e64696e675f7369676e06ff00166d696e6563726166743a6372696d736f6e5f7374656d1fff001b6d696e6563726166743a6372696d736f6e5f77616c6c5f7369676e04ff001b6d696e6563726166743a6461726b5f6f616b5f74726170646f6f726dff00206d696e6563726166743a6461726b5f707269736d6172696e655f737461697273fdff001f6d696e6563726166743a6461726b6f616b5f7374616e64696e675f7369676e40ff001b6d696e6563726166743a6461726b6f616b5f77616c6c5f7369676e3fff00126d696e6563726166743a6465616462757368200000156d696e6563726166743a6469616d6f6e645f6f7265380000136d696e6563726166743a64697370656e736572170000176d696e6563726166743a6c6176615f6361756c64726f6e2eff00146d696e6563726166743a647261676f6e5f6567677a0000176d696e6563726166743a6a756e676c655f737461697273880000116d696e6563726166743a64726f707065727d0000176d696e6563726166743a656d6572616c645f626c6f636b8500001a6d696e6563726166743a656e6368616e74696e675f7461626c657400001a6d696e6563726166743a656e645f627269636b5f7374616972734eff000e6d696e6563726166743a66697265330000116d696e6563726166743a6675726e6163653d00001b6d696e6563726166743a67696c6465645f626c61636b73746f6e65e7fe000f6d696e6563726166743a676c617373140000146d696e6563726166743a676c6173735f70616e65660000126d696e6563726166743a676f6c645f6f72650e0000156d696e6563726166743a676f6c64656e5f7261696c1b00000f6d696e6563726166743a6772617373020000146d696e6563726166743a67726173735f70617468c60000106d696e6563726166743a67726176656c0d0000206d696e6563726166743a677261795f676c617a65645f7465727261636f747461e30000216d696e6563726166743a677265656e5f676c617a65645f7465727261636f747461e90000146d696e6563726166743a686172645f676c617373fd0000196d696e6563726166743a686172645f676c6173735f70616e65be0000176d696e6563726166743a68617264656e65645f636c6179ac0000276d696e6563726166743a68656176795f77656967687465645f70726573737572655f706c617465940000156d696e6563726166743a696e666f5f757064617465f80000146d696e6563726166743a69726f6e5f626c6f636b2a0000176d696e6563726166743a6a756e676c655f627574746f6e71ff001a6d696e6563726166743a6974656d2e6a756e676c655f646f6f72c300001e6d696e6563726166743a6a756e676c655f7374616e64696e675f7369676e44ff00156d696e6563726166743a6c69745f6675726e6163653e00001a6d696e6563726166743a6a756e676c655f77616c6c5f7369676e43ff00136d696e6563726166743a6974656d2e6b656c7076ff001e6d696e6563726166743a756e6c69745f72656473746f6e655f746f7263684b0000106d696e6563726166743a6c6164646572410000156d696e6563726166743a6c617069735f626c6f636b160000136d696e6563726166743a6c617069735f6f72651500000e6d696e6563726166743a6c6176610b0000116d696e6563726166743a6c65637465726e3eff001b6d696e6563726166743a6d6f7373795f636f62626c6573746f6e653000000f6d696e6563726166743a6c65766572450000206d696e6563726166743a6c696d655f676c617a65645f7465727261636f747461e10000146d696e6563726166743a6c69745f736d6f6b657239ff00146d696e6563726166743a6d656c6f6e5f7374656d6900001d6d696e6563726166743a6974656d2e6e65746865725f7370726f75747312ff00226d696e6563726166743a6d6f7373795f73746f6e655f627269636b5f73746169727351ff00156d696e6563726166743a6d6f76696e67626c6f636bfa0000126d696e6563726166743a6d7963656c69756d6e0000166d696e6563726166743a6e65746865725f627269636b7000001c6d696e6563726166743a6e65746865725f627269636b5f66656e63657100001d6d696e6563726166743a6e65746865725f627269636b5f737461697273720000196d696e6563726166743a6e65746865725f676f6c645f6f7265e0fe001a6d696e6563726166743a6974656d2e6e65746865725f77617274730000146d696e6563726166743a6e65746865727261636b570000176d696e6563726166743a6e657468657272656163746f72f700001d6d696e6563726166743a6e6f726d616c5f73746f6e655f7374616972734cff00136d696e6563726166743a6e6f7465626c6f636b1900001a6d696e6563726166743a7761727065645f77616c6c5f7369676e03ff00146d696e6563726166743a6f616b5f737461697273350000206d696e6563726166743a70696e6b5f676c617a65645f7465727261636f747461e200001c6d696e6563726166743a706973746f6e61726d636f6c6c6973696f6e220000106d696e6563726166743a706f647a6f6cf30000196d696e6563726166743a706f6c69736865645f626173616c7415ff001d6d696e6563726166743a706f6c69736865645f626c61636b73746f6e65ddfe002f6d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f646f75626c655f736c6162e3fe001e6d696e6563726166743a7761727065645f7374616e64696e675f7369676e05ff00286d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f77616c6ceafe002c6d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f70726573737572655f706c617465d9fe00246d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f737461697273dcfe001a6d696e6563726166743a706f77657265645f72657065617465725e00001b6d696e6563726166743a707269736d6172696e655f737461697273feff00166d696e6563726166743a70756d706b696e5f7374656d680000226d696e6563726166743a707572706c655f676c617a65645f7465727261636f747461db00001f6d696e6563726166743a7265645f676c617a65645f7465727261636f747461ea0000216d696e6563726166743a7265645f6e65746865725f627269636b5f73746169727348ff00176d696e6563726166743a72656473746f6e655f6c616d707b0000166d696e6563726166743a72656473746f6e655f6f7265490000176d696e6563726166743a72656473746f6e655f77697265370000216d696e6563726166743a726570656174696e675f636f6d6d616e645f626c6f636bbc00001a6d696e6563726166743a73616e6473746f6e655f737461697273800000156d696e6563726166743a7368726f6f6d6c696768741aff00146d696e6563726166743a6974656d2e736b756c6c900000256d696e6563726166743a736d6f6f74685f7265645f73616e6473746f6e655f73746169727350ff00216d696e6563726166743a736d6f6f74685f73616e6473746f6e655f7374616972734fff001c6d696e6563726166743a6974656d2e736f756c5f63616d7066697265defe00136d696e6563726166743a736f756c5f6669726513ff00166d696e6563726166743a736f756c5f6c616e7465726ef3fe00146d696e6563726166743a736f756c5f746f726368f4fe00146d696e6563726166743a6974656d2e77686561743b00001a6d696e6563726166743a6974656d2e7370727563655f646f6f72c100001f6d696e6563726166743a7370727563655f70726573737572655f706c61746566ff00196d696e6563726166743a7370727563655f74726170646f6f726bff00166d696e6563726166743a73746f6e655f627574746f6e4d0000166d696e6563726166743a73746f6e655f737461697273430000156d696e6563726166743a73746f6e65637574746572f500001c6d696e6563726166743a73747269707065645f62697263685f6c6f67faff00216d696e6563726166743a73747269707065645f6372696d736f6e5f687970686165d4fe001f6d696e6563726166743a73747269707065645f6461726b5f6f616b5f6c6f67f7ff001d6d696e6563726166743a73747269707065645f6a756e676c655f6c6f67f9ff001d6d696e6563726166743a73747269707065645f7370727563655f6c6f67fbff00206d696e6563726166743a73747269707065645f7761727065645f687970686165d3fe001e6d696e6563726166743a73747269707065645f7761727065645f7374656d0fff00196d696e6563726166743a7374727563747572655f626c6f636bfc0000186d696e6563726166743a7374727563747572655f766f6964d900001a6d696e6563726166743a73776565745f62657272795f6275736831ff000f6d696e6563726166743a746f726368320000176d696e6563726166743a74726970776972655f686f6f6b8300001a6d696e6563726166743a756e64657277617465725f746f726368ef00001c6d696e6563726166743a756e706f77657265645f72657065617465725d00001b6d696e6563726166743a7761727065645f776172745f626c6f636b1dff000e6d696e6563726166743a76696e656a0000156d696e6563726166743a77616c6c5f62616e6e6572b100001c6d696e6563726166743a7761727065645f646f75626c655f736c6162f5fe001b6d696e6563726166743a7761727065645f66656e63655f67617465fdfe00176d696e6563726166743a7761727065645f687970686165d6fe00176d696e6563726166743a7761727065645f6e796c69756d17ff00176d696e6563726166743a7761727065645f706c616e6b730dff001f6d696e6563726166743a7761727065645f70726573737572655f706c617465f9fe00176d696e6563726166743a7761727065645f73746169727301ff00156d696e6563726166743a7761727065645f7374656d1eff000f6d696e6563726166743a77617465720900000d6d696e6563726166743a7765621e0000216d696e6563726166743a77686974655f676c617a65645f7465727261636f747461dc00001f6d696e6563726166743a776f6f64656e5f70726573737572655f706c617465480000156d696e6563726166743a7769746865725f726f736528ff001a6d696e6563726166743a6974656d2e776f6f64656e5f646f6f724000002465303438386162302d333234362d346133372d386238332d38626435616239623433366601' + const buf = Buffer.from(s, 'hex') + const des = read(buf) + console.log(des.data.name) + const newBuf = write(des.data.name, des.data.params) + console.log(newBuf) + console.assert(newBuf.toString('hex')==s) + // console.log(serialize(des.data.params, 2)) + } + + async function testAdventureSettings() { + // const buf = Buffer.from('3720009f02010001000000fdffffff') + // const des = read(buf) + // console.log(serialize(des.data.params, 2)) + + const buf = write('adventure_settings', { + flags: { + world_immutable: true, + no_pvp: true + }, + command_permission: 'normal', + action_permissions: { + open_containers: true + }, + permission_level: 'member', + custom_stored_permissions: 0, + user_id: 0 + }) + const des = read(buf) + // fs.writeFileSync('cc.json', serialize(des.data.params, 2)) + console.log('Des', JSON.stringify(des, null, 2)) + } + + async function testInventory() { + const buf = Buffer.from('1e00020000008c0a419e0104060031bb2144723d8342aff19b420000403f0079873e8047513f8833', 'hex') + const des = read(buf) + console.log(JSON.stringify(des)) + } + + async function testInventory() { + const buf = Buffer.from('1e00020000008c0a419e0104060031bb2144723d8342aff19b420000403f0079873e8047513f8833', 'hex') + + } + // creativeTst() // availableCommands() // avaliableCmd() + // creativeTestNew() + // biomeDefinitions() + // startGame() + testInventory() } if (!module.parent) { test() +} + +function serialize(obj = {}, fmt) { + return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) } \ No newline at end of file From 9bd8f4c2bb59e2ab68acfb82b29d62ef5aa50b19 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Feb 2021 13:11:22 -0500 Subject: [PATCH 106/458] server sending generated chunks --- .gitignore | 2 +- data/new/proto.yml | 2 +- data/newproto.json | 2 +- package.json | 1 + src/serverTest.js | 90 +++++++++++++++++++++++----------------------- 5 files changed, 50 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index 4f37984..2f3cd51 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ npm-debug.log __* data/*.js src/**/*.json -src/*.txt +src/**/*.txt dist/ \ No newline at end of file diff --git a/data/new/proto.yml b/data/new/proto.yml index b209d4f..db42f42 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -1003,7 +1003,7 @@ packet_level_chunk: # true. If set to false, the payload is composed of multiple sub-chunks, each of which carry a version # which indicates the way they are serialised, followed by biomes, border blocks and tile entities. If # CacheEnabled is true, the payload consists out of the border blocks and tile entities only. - payload: string + payload: ByteArray packet_set_commands_enabled: !id: 0x3b diff --git a/data/newproto.json b/data/newproto.json index 689ff79..9779bac 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -4506,7 +4506,7 @@ }, { "name": "payload", - "type": "string" + "type": "ByteArray" } ] ], diff --git a/package.json b/package.json index 175c491..18a635e 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@xboxreplay/xboxlive-auth": "^3.3.3", "aes-js": "^3.1.2", "asn1": "^0.2.4", + "bedrock-provider": "github:extremeheat/bedrock-provider", "bn.js": "^4.11.4", "debug": "^4.3.1", "ec-pem": "^0.18.0", diff --git a/src/serverTest.js b/src/serverTest.js index ad54097..6d01f96 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -4,6 +4,7 @@ const CreativeItems = require('../data/creativeitems.json') const NBT = require('prismarine-nbt') const fs = require('fs') + let server = new Server({ }) @@ -38,45 +39,7 @@ server.on('connect', ({ client }) => { }) client.once('resource_pack_client_response', async (packet) => { - // ran = true - // let items = [] - // let ids = 0 - // for (var item of CreativeItems) { - // let creativeitem = { runtime_id: items.length } - // const has_nbt = !!item.nbt_b64 - // if (item.id != 0) { - // creativeitem.item = { - // network_id: item.id, - // auxiliary_value: item.damage || 0, - // has_nbt, - // nbt: { - // version: 1, - // }, - // blocking_tick: 0, - // can_destroy: [], - // can_place_on: [] - // } - // if (has_nbt) { - // let nbtBuf = Buffer.from(item.nbt_b64, 'base64') - // let { parsed } = await NBT.parse(nbtBuf, 'little') - // creativeitem.item.nbt.nbt = parsed - // } - // } - // items.push(creativeitem) - // // console.log(creativeitem) - // } - - // console.log(items, ids) - - // client.write('creative_content', { items }) - // wait a bit just for easier debugging - // setTimeout(() => { - // const biomeDefs = fs.readFileSync('../data/biome_definitions.nbt') - // client.writeRaw('biome_definition_list', biomeDefs) - - // // TODO: send chunks so we can spawn player - // }, 1000) - + }) client.write('network_settings', { @@ -109,10 +72,14 @@ server.on('connect', ({ client }) => { client.queue('game_rules_changed', require('./packets/game_rules_changed.json')) client.queue('respawn', {"x":646.9405517578125,"y":65.62001037597656,"z":77.86255645751953,"state":0,"runtime_entity_id":0}) - for (const file of fs.readdirSync('chunks')) { - const buffer = Buffer.from(fs.readFileSync('./chunks/' + file, 'utf8'), 'hex') - // console.log('Sending chunk', chunk) - client.sendBuffer(buffer) + // for (const file of fs.readdirSync('chunks')) { + // const buffer = Buffer.from(fs.readFileSync('./chunks/' + file, 'utf8'), 'hex') + // // console.log('Sending chunk', chunk) + // client.sendBuffer(buffer) + // } + + for (const chunk of chunks) { + client.queue('level_chunk', chunk) } setInterval(() => { @@ -131,4 +98,39 @@ async function sleep(ms) { return new Promise(res => { setTimeout(() => { res() }, ms) }) -} \ No newline at end of file +} + +// CHUNKS +const { ChunkColumn, Version } = require('bedrock-provider') +const mcData = require('minecraft-data')('1.16') +var chunks = [] +async function buildChunks() { + // "x": 40, + // "z": 4, + + const stone = mcData.blocksByName.stone + + for (var cx = 35; cx < 45; cx++) { + for (var cz = 0; cz < 8; cz++) { + const column = new ChunkColumn(Version.v1_2_0_bis, x, z) + for (var x = 0; x < 16; x++) { + for (var y = 0; y < 60; y++) { + for (var z = 0; z < 16; z++) { + column.setBlock(x,y,z,stone) + } + } + } + + const ser = await column.networkEncodeNoCache() + + chunks.push({ + x:cx, z:cz, sub_chunk_count: column.sectionsLen, cache_enabled: false, + blobs: [], payload: ser + }) + } + } + + // console.log('Chunks',chunks) +} + +buildChunks() \ No newline at end of file From c7823ab71a79242bf92785e6f2f84600c893675c Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Feb 2021 15:21:56 -0500 Subject: [PATCH 107/458] cleanup Update packages, remove junk --- .babelrc | 7 -- .eslintrc | 41 ---------- .gitignore | 1 + dist/createClient.js | 70 ---------------- dist/createServer.js | 147 ---------------------------------- dist/datatypes/minecraft.js | 139 -------------------------------- dist/index.js | 9 --- dist/transforms/serializer.js | 32 -------- package.json | 20 +---- src/ConnWorker.js | 2 +- src/old/createClient.js | 63 --------------- src/old/createServer.js | 138 ------------------------------- 12 files changed, 4 insertions(+), 665 deletions(-) delete mode 100644 .babelrc delete mode 100644 .eslintrc delete mode 100644 dist/createClient.js delete mode 100644 dist/createServer.js delete mode 100644 dist/datatypes/minecraft.js delete mode 100644 dist/index.js delete mode 100644 dist/transforms/serializer.js delete mode 100644 src/old/createClient.js delete mode 100644 src/old/createServer.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index f475336..0000000 --- a/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ - -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript" - ] -} diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index bb70c93..0000000 --- a/.eslintrc +++ /dev/null @@ -1,41 +0,0 @@ -{ - "parser": "babel-eslint", - - "extends": [ - "eslint:recommended" - ], - - "plugins": [ - "@typescript-eslint", - "import" - ], - - "env": { - "es6": true, - "browser": true, - "node": true, - "jasmine": true - }, - - "parserOptions": { - "ecmaFeatures": { - "jsx": true, - "modules": true - } - }, - - "rules": { - "consistent-return": 2, - "no-mixed-operators": 0, - "no-useless-constructor": 0, - "standard/computed-property-even-spacing": 0, - "import/first": 0, - "no-unused-vars": 2, - "no-console": 2, - - "indent": ["error", 4, {"SwitchCase": 1}], - "semi": ["error", "always"], - "brace-style": ["error", "1tbs", { "allowSingleLine": true }], - "radix": ["off"] - } -} diff --git a/.gitignore b/.gitignore index 2f3cd51..f7f9591 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ npm-debug.log +package-lock.json __* data/*.js src/**/*.json diff --git a/dist/createClient.js b/dist/createClient.js deleted file mode 100644 index 13d4cd8..0000000 --- a/dist/createClient.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -var assert = require('assert'); - -var raknet = require('raknet'); - -var fs = require('fs'); - -var path = require('path'); - -var zlib = require('zlib'); - -var ProtoDef = require('protodef').ProtoDef; - -var batchProto = new ProtoDef(); -batchProto.addTypes(require("./datatypes/minecraft")); -batchProto.addType("insideBatch", ["endOfArray", { - "type": ["buffer", { - "countType": "i32" - }] -}]); - -function createClient(options) { - return null; //FIXME - - assert.ok(options, 'options is required'); - var port = options.port || 19132; - var host = options.host || 'localhost'; - assert.ok(options.username, 'username is required'); - options.customPackets = require('../data/protocol'); - options.customTypes = require('./datatypes/minecraft'); - var client = raknet.createClient(options); - client.username = options.username; - client.on('mcpe', function (packet) { - return client.emit(packet.name, packet.params); - }); - - client.writeMCPE = function (name, packet) { - client.writeEncapsulated('mcpe', { - name: name, - params: packet - }); - }; - - client.on('login', function () { - client.writeMCPE('game_login', { - username: client.username, - protocol: 70, - protocol2: 70, - clientId: [-1, -697896776], - clientUuid: '86372ed8-d055-b23a-9171-5e3ac594d766', - serverAddress: client.host + ":" + client.port, - clientSecret: new Buffer('e8 88 db 7b 9f f2 f0 44 a3 51 08 18 4e 8c 7f 9a'.replace(/ /g, ''), 'hex'), - skin: { - skinType: 'Standard_Steve', - texture: fs.readFileSync(path.join(__dirname, 'texture')) - } - }); - }); - client.on('batch', function (packet) { - var buf = zlib.inflateSync(packet.payload); - var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; - packets.forEach(function (packet) { - return client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet])); - }); - }); - return client; -} - -module.exports = createClient; \ No newline at end of file diff --git a/dist/createServer.js b/dist/createServer.js deleted file mode 100644 index e808cc9..0000000 --- a/dist/createServer.js +++ /dev/null @@ -1,147 +0,0 @@ -"use strict"; - -var _raknet = _interopRequireDefault(require("raknet")); - -var _zlib = _interopRequireDefault(require("zlib")); - -var _jwtSimple = _interopRequireDefault(require("jwt-simple")); - -var _protodef = require("protodef"); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } - -var batchProto = new _protodef.ProtoDef(); -var PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; // createServer (object, boolean) -// -// Create & launch a MCPE raknet-based server. -// object: raknet options -// encryption: enable/disable encryption - -function createServer(options, encryption) { - options = options || {}; - var port = options.port || options['server-port'] || 19132; - var host = options.host || '0.0.0.0'; - options.customPackets = (options.protocol ? options.protocol.packets : null) || require('../data/protocol'); - options.customTypes = (options.protocol ? options.protocol.types : null) || require('./datatypes/minecraft'); - batchProto.addTypes(options.customTypes); - batchProto.addType('insideBatch', ['endOfArray', { - 'type': ['buffer', { - 'countType': 'varint' - }] - }]); - - var server = _raknet["default"].createServer(options); - - server.name = options.name || 'Minecraft Server'; - server.motd = options.motd || 'A Minecraft server'; //FIXME - - server.maxPlayers = options['max-players'] || 20; //FIXME - - server.playerCount = 0; //FIXME - - server.on('connection', function (client) { - client.receiveCounter = 0; - client.sendCounter = 0; - client.encryptionEnabled = encryption ? true : false; - var proto = new _protodef.ProtoDef(); - proto.addTypes(options.customTypes); - proto.addTypes(options.customPackets.types); - client.mcpePacketSerializer = new _protodef.Serializer(proto, 'mcpe_packet'); - client.on('mcpe', function (packet) { - client.emit(packet.name, packet.params); - client.emit('debug', packet.name); - }); - client.on('batch', function (packets) { - var buf = _zlib["default"].inflateSync(packets.payload); - - var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; - packets.forEach(function (packet) { - return client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet])); - }); - }); // client.writePacket (string, object) - // Send data to the client - // - // string: packet name - // object: packet data - - client.writeMCPE = function (name, params) { - if (client.encryptionEnabled) { - client.mcpePacketSerializer.write({ - name: name, - params: params - }); - } else { - client.writeEncapsulated('mcpe', { - name: name, - params: params - }); - } - }; - - client.writePacket = client.writeMCPE; // client.writeData (array) - // Send data to the client - // - // array: packets to send - - client.writeBatch = function (packets) { - var payload = _zlib["default"].deflateSync(batchProto.createPacketBuffer('insideBatch', packets.map(function (packet) { - return client.mcpePacketSerializer.createPacketBuffer(packet); - }))); - - client.writePacket('batch', { - payload: payload - }); - }; - - client.writeData = client.writeBatch; // client.writeAll (string, object) - // Send data to the client - // - // string: packet name - // object: packet data - - client.writeAll = function (name, data) { - server._writeAll(name, data); - }; - - client.on('game_login', function (packet) { - try { - var dataProto = new _protodef.ProtoDef(); - dataProto.addType('data_chain', ['container', [{ - 'name': 'chain', - 'type': ['pstring', { - 'countType': 'li32' - }] - }, { - 'name': 'clientData', - 'type': ['pstring', { - 'countType': 'li32' - }] - }]]); //FIXME: Xbox & Non-Xbox support - - console.log(packet); - var body = dataProto.parsePacketBuffer('data_chain', _zlib["default"].inflateSync(packet.body)), - chain = null, - decode = null, - data = null; - body.data.chain = JSON.parse(body.data.chain); - chain = body.data.chain.chain[0]; - decode = _jwtSimple["default"].decode(chain, PUBLIC_KEY, 'ES384'); - data = _jwtSimple["default"].decode(body.data.clientData, decode.identityPublicKey, 'ES384'); - client.emit('mcpe_login', { - protocol: packet.protocol, - uuid: decode.extraData != null ? decode.extraData.identity : null, - id: decode.extraData != null ? decode.extraData.identityPublicKey : null, - username: decode.extraData != null ? decode.extraData.displayName : null, - skinData: data.SkinData, - skinId: data.SkinId - }); - } catch (err) { - console.error(err); - return null; - } - }); - }); - return server; -} - -module.exports = createServer; \ No newline at end of file diff --git a/dist/datatypes/minecraft.js b/dist/datatypes/minecraft.js deleted file mode 100644 index 9a1fcb8..0000000 --- a/dist/datatypes/minecraft.js +++ /dev/null @@ -1,139 +0,0 @@ -'use strict'; - -var nbt = require('prismarine-nbt'); - -var UUID = require('uuid-1345'); - -function readUUID(buffer, offset) { - if (offset + 16 > buffer.length) throw new PartialReadError(); - return { - value: UUID.stringify(buffer.slice(offset, 16 + offset)), - size: 16 - }; -} - -function writeUUID(value, buffer, offset) { - var buf = UUID.parse(value); - buf.copy(buffer, offset); - return offset + 16; -} - -function readNbt(buffer, offset) { - return nbt.protoLE.read(buffer, offset, "nbt"); -} - -function writeNbt(value, buffer, offset) { - return nbt.protoLE.write(value, buffer, offset, "nbt"); -} - -function sizeOfNbt(value) { - return nbt.protoLE.sizeOf(value, "nbt"); -} - -function readEntityMetadata(buffer, offset, _ref) { - var type = _ref.type; - var endVal = _ref.endVal; - var cursor = offset; - var metadata = []; - var item = undefined; - - while (true) { - if (offset + 1 > buffer.length) throw new PartialReadError(); - item = buffer.readUInt8(cursor); - - if (item === endVal) { - return { - value: metadata, - size: cursor + 1 - offset - }; - } - - var results = this.read(buffer, cursor, type, {}); - metadata.push(results.value); - cursor += results.size; - } -} - -function writeEntityMetadata(value, buffer, offset, _ref2) { - var type = _ref2.type; - var endVal = _ref2.endVal; - var self = this; - value.forEach(function (item) { - offset = self.write(item, buffer, offset, type, {}); - }); - buffer.writeUInt8(endVal, offset); - return offset + 1; -} - -function sizeOfEntityMetadata(value, _ref3) { - var type = _ref3.type; - var size = 1; - - for (var i = 0; i < value.length; ++i) { - size += this.sizeOf(value[i], type, {}); - } - - return size; -} - -function readIpAddress(buffer, offset) { - var address = buffer[offset] + '.' + buffer[offset + 1] + '.' + buffer[offset + 2] + '.' + buffer[offset + 3]; - return { - size: 4, - value: address - }; -} - -function writeIpAddress(value, buffer, offset) { - var address = value.split('.'); - address.forEach(function (b) { - buffer[offset] = parseInt(b); - offset++; - }); - return offset; -} - -function readEndOfArray(buffer, offset, typeArgs) { - var type = typeArgs.type; - var cursor = offset; - var elements = []; - - while (cursor < buffer.length) { - var results = this.read(buffer, cursor, type, {}); - elements.push(results.value); - cursor += results.size; - } - - return { - value: elements, - size: cursor - offset - }; -} - -function writeEndOfArray(value, buffer, offset, typeArgs) { - var type = typeArgs.type; - var self = this; - value.forEach(function (item) { - offset = self.write(item, buffer, offset, type, {}); - }); - return offset; -} - -function sizeOfEndOfArray(value, typeArgs) { - var type = typeArgs.type; - var size = 0; - - for (var i = 0; i < value.length; ++i) { - size += this.sizeOf(value[i], type, {}); - } - - return size; -} - -module.exports = { - 'uuid': [readUUID, writeUUID, 16], - 'nbt': [readNbt, writeNbt, sizeOfNbt], - 'entityMetadataLoop': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata], - 'ipAddress': [readIpAddress, writeIpAddress, 4], - 'endOfArray': [readEndOfArray, writeEndOfArray, sizeOfEndOfArray] -}; \ No newline at end of file diff --git a/dist/index.js b/dist/index.js deleted file mode 100644 index 9db82d4..0000000 --- a/dist/index.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -module.exports = { - createSerializer: require("./transforms/serializer").createSerializer, - createDeserializer: require("./transforms/serializer").createDeserializer, - createProtocol: require('./transforms/serializer').createProtocol, - createServer: require("./createServer"), - createClient: require("./createClient") -}; \ No newline at end of file diff --git a/dist/transforms/serializer.js b/dist/transforms/serializer.js deleted file mode 100644 index a1b0965..0000000 --- a/dist/transforms/serializer.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -var ProtoDef = require('protodef').ProtoDef; - -var Serializer = require('protodef').Serializer; - -var Parser = require('protodef').Parser; - -var protocol = require('../../data/protocol.json').types; - -function createProtocol() { - var proto = new ProtoDef(); - proto.addTypes(require('../datatypes/minecraft')); - proto.addTypes(protocol); - return proto; -} - -function createSerializer() { - var proto = createProtocol(); - return new Serializer(proto, 'packet'); -} - -function createDeserializer() { - var proto = createProtocol(); - return new Parser(proto, 'packet'); -} - -module.exports = { - createDeserializer: createDeserializer, - createSerializer: createSerializer, - createProtocol: createProtocol -}; \ No newline at end of file diff --git a/package.json b/package.json index 18a635e..90a49d6 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,6 @@ "description": "Parse and serialize Minecraft Bedrock Edition packets", "main": "index.js", "scripts": { - "build": "babel src --out-dir dist", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ @@ -15,34 +14,22 @@ "license": "MIT", "dependencies": { "@azure/msal-node": "^1.0.0-beta.6", - "@babel/core": "^7.5.4", - "@babel/preset-env": "^7.5.4", - "@babel/preset-typescript": "^7.3.3", - "@babel/register": "^7.4.4", "@jsprismarine/jsbinaryutils": "^2.1.8", - "@jsprismarine/raknet": "github:extremeheat/raknet#client", "@xboxreplay/xboxlive-auth": "^3.3.3", "aes-js": "^3.1.2", "asn1": "^0.2.4", "bedrock-provider": "github:extremeheat/bedrock-provider", - "bn.js": "^4.11.4", "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", "jsp-raknet": "github:extremeheat/raknet#client", - "jwt-simple": "^0.5.6", - "lodash.merge": "^4.4.0", "minecraft-folder-path": "^1.1.0", "prismarine-nbt": "github:extremeheat/prismarine-nbt#le", "protodef": "github:extremeheat/node-protodef#compiler", - "raknet": "git+https://github.com/mhsjlw/node-raknet.git#master", "uuid-1345": "^0.99.7" }, "devDependencies": { - "@babel/cli": "^7.5.0", - "buffer-equal": "^1.0.0", - "mocha": "^2.5.3", - "pre-commit": "^1.2.2" + "mocha": "^2.5.3" }, "repository": { "type": "git", @@ -51,8 +38,5 @@ "bugs": { "url": "https://github.com/mhsjlw/pocket-minecraft-protocol/issues" }, - "homepage": "https://github.com/mhsjlw/pocket-minecraft-protocol#readme", - "pre-commit": [ - "build" - ] + "homepage": "https://github.com/mhsjlw/pocket-minecraft-protocol#readme" } diff --git a/src/ConnWorker.js b/src/ConnWorker.js index 81e7507..996ed56 100644 --- a/src/ConnWorker.js +++ b/src/ConnWorker.js @@ -1,6 +1,6 @@ const RakClient = require('jsp-raknet/client') const { Worker, isMainThread, parentPort } = require('worker_threads') -const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') +const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') function connect(hostname, port) { if (isMainThread) { diff --git a/src/old/createClient.js b/src/old/createClient.js deleted file mode 100644 index 4e87d1c..0000000 --- a/src/old/createClient.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; -const assert = require('assert'); -const raknet = require('raknet'); -const fs = require('fs'); -const path = require('path'); -const zlib = require('zlib'); -const ProtoDef = require('protodef').ProtoDef; -const batchProto = new ProtoDef(); -batchProto.addTypes(require("./datatypes/minecraft")); -batchProto.addType("insideBatch", ["endOfArray", { "type": ["buffer", { "countType": "i32" }] }]); - -function createClient(options) { - return null; //FIXME - - assert.ok(options, 'options is required'); - var port = options.port || 19132; - var host = options.host || 'localhost'; - - assert.ok(options.username, 'username is required'); - - options.customPackets = require('../data/protocol'); - options.customTypes = require('./datatypes/minecraft'); - - var client = raknet.createClient(options); - client.username = options.username; - client.on('mcpe', packet => client.emit(packet.name, packet.params)) - client.writeMCPE = (name, packet) => { - client.writeEncapsulated('mcpe', { - name: name, - params: packet - }); - }; - - client.on('login', function () { - client.writeMCPE('game_login', - { - username: client.username, - protocol: 70, - protocol2: 70, - clientId: [-1, -697896776], - clientUuid: '86372ed8-d055-b23a-9171-5e3ac594d766', - serverAddress: client.host + ":" + client.port, - clientSecret: new Buffer('e8 88 db 7b 9f f2 f0 44 a3 51 08 18 4e 8c 7f 9a'.replace(/ /g, ''), 'hex'), - skin: - { - skinType: 'Standard_Steve', - texture: fs.readFileSync(path.join(__dirname, 'texture')) - } - } - ); - - }); - - client.on('batch', function (packet) { - var buf = zlib.inflateSync(packet.payload); - var packets = batchProto.parsePacketBuffer("insideBatch", buf).data; - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); - }); - - return client; -} - -module.exports = createClient; diff --git a/src/old/createServer.js b/src/old/createServer.js deleted file mode 100644 index cbca2d9..0000000 --- a/src/old/createServer.js +++ /dev/null @@ -1,138 +0,0 @@ -import raknet from 'raknet'; -import zlib from 'zlib'; -import jwt from 'jwt-simple'; -import { ProtoDef, Parser, Serializer } from 'protodef'; - -let batchProto = new ProtoDef(); -const PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V'; - -// createServer (object, boolean) -// -// Create & launch a MCPE raknet-based server. -// object: raknet options -// encryption: enable/disable encryption -function createServer(options, encryption) { - options = options || {}; - - const port = options.port || options['server-port'] || 19132; - const host = options.host || '0.0.0.0'; - - options.customPackets = (options.protocol ? options.protocol.packets : null) || require('../data/protocol'); - options.customTypes = (options.protocol ? options.protocol.types : null) || require('./datatypes/minecraft'); - - batchProto.addTypes(options.customTypes); - batchProto.addType('insideBatch', ['endOfArray', { - 'type': ['buffer', { - 'countType': 'varint', - }] - }]); - - let server = raknet.createServer(options); - server.name = options.name || 'Minecraft Server'; - server.motd = options.motd || 'A Minecraft server'; //FIXME - server.maxPlayers = options['max-players'] || 20; //FIXME - server.playerCount = 0; //FIXME - - server.on('connection', (client) => { - client.receiveCounter = 0; - client.sendCounter = 0; - client.encryptionEnabled = encryption ? true : false; - - let proto = new ProtoDef(); - proto.addTypes(options.customTypes); - proto.addTypes(options.customPackets.types); - client.mcpePacketSerializer = new Serializer(proto, 'mcpe_packet'); - - client.on('mcpe', packet => { - client.emit(packet.name, packet.params); - client.emit('debug', packet.name); - }); - client.on('batch', function (packets) { - var buf = zlib.inflateSync(packets.payload); - var packets = batchProto.parsePacketBuffer('insideBatch', buf).data; - packets.forEach(packet => client.readEncapsulatedPacket(Buffer.concat([new Buffer([0xfe]), packet]))); - }); - - // client.writePacket (string, object) - // Send data to the client - // - // string: packet name - // object: packet data - client.writeMCPE = (name, params) => { - if (client.encryptionEnabled) { - client.mcpePacketSerializer.write({ name, params }); - } else { - client.writeEncapsulated('mcpe', { name, params }); - } - }; - client.writePacket = client.writeMCPE; - - // client.writeData (array) - // Send data to the client - // - // array: packets to send - client.writeBatch = (packets) => { - const payload = zlib.deflateSync(batchProto.createPacketBuffer('insideBatch', - packets.map(packet => client.mcpePacketSerializer.createPacketBuffer(packet)))); - - client.writePacket('batch', { - payload: payload - }); - }; - client.writeData = client.writeBatch; - - // client.writeAll (string, object) - // Send data to the client - // - // string: packet name - // object: packet data - client.writeAll = (name, data) => { - server._writeAll(name, data); - }; - - client.on('game_login', (packet) => { - try { - let dataProto = new ProtoDef(); - dataProto.addType('data_chain', ['container', [{ - 'name': 'chain', - 'type': ['pstring', { - 'countType': 'li32' - }] - }, { - 'name': 'clientData', - 'type': ['pstring', { - 'countType': 'li32' - }] - }]]); - - //FIXME: Xbox & Non-Xbox support - console.log(packet); - let body = dataProto.parsePacketBuffer('data_chain', zlib.inflateSync(packet.body)), - chain = null, - decode = null, - data = null; - - body.data.chain = JSON.parse(body.data.chain); - chain = body.data.chain.chain[0]; - - decode = jwt.decode(chain, PUBLIC_KEY, 'ES384'); - data = jwt.decode(body.data.clientData, decode.identityPublicKey, 'ES384'); - - client.emit('mcpe_login', { - protocol: packet.protocol, - uuid: (decode.extraData != null) ? decode.extraData.identity : null, - id: (decode.extraData != null) ? decode.extraData.identityPublicKey : null, - username: (decode.extraData != null) ? decode.extraData.displayName : null, - skinData: data.SkinData, - skinId: data.SkinId - }) - } catch (err) { - console.error(err); - return null; - } - }); - }); - return server; -} - -module.exports = createServer; From b64a22a8fc99d37a8ce27311086d248ac0cf10bf Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Feb 2021 17:47:14 -0500 Subject: [PATCH 108/458] protocol updates, movement fixes packet_map is now auto-generated --- data/new/compile.js | 40 ++++-- data/new/packet_map.yml | 6 +- data/new/proto.yml | 86 +++++++++++-- data/new/types.yaml | 139 +++++++++++++++++++++ data/newproto.json | 268 +++++++++++++++++++++++++++++++++++++--- package.json | 1 + src/serverTest.js | 33 +++-- 7 files changed, 531 insertions(+), 42 deletions(-) diff --git a/data/new/compile.js b/data/new/compile.js index 7ffca0e..9ba4669 100644 --- a/data/new/compile.js +++ b/data/new/compile.js @@ -1,17 +1,43 @@ +/** + * This is a utility script that converts the YAML here into ProtoDef schema code and (soon) docs/typescript definitions. + * It also pre-compiles JS code from the schema for easier development. + * + * You can run this with `npm run build` + * + */ const fs = require('fs') const { ProtoDefCompiler } = require('protodef').Compiler -let compile -try { - compile = require('protodef-yaml/compiler').compile -} catch (e) { - require('child_process').execSync('npx protodef-yaml proto.yml protocol.json') -} +function genProtoSchema() { + const { parse, compile } = require('protodef-yaml/compiler') + + // Create the packet_map.yml from proto.yml + const parsed = parse('./proto.yml') + const packets = [] + for (const key in parsed) { + if (key.startsWith('%container')) { + const [, name] = key.split(',') + if (name.startsWith('packet_')) { + const children = parsed[key] + const packetName = name.replace('packet_', '') + const packetID = children['!id'] + packets.push([packetID, packetName, name]) + } + } + } + let l1 = l2 = '' + for (const [id,name,fname] of packets) { + l1 += ` 0x${id.toString(16).padStart(2, '0')}: ${name}\n` + l2 += ` if ${name}: ${fname}\n` + } + const t = `!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` + fs.writeFileSync('./packet_map.yml', t) -if (compile) { compile('./proto.yml', 'protocol.json') } +genProtoSchema() + fs.writeFileSync('../newproto.json', JSON.stringify({ types: require('./protocol.json') }, null, 2)) fs.unlinkSync('./protocol.json') //remove temp file diff --git a/data/new/packet_map.yml b/data/new/packet_map.yml index 6f698c9..ff3e7f0 100644 --- a/data/new/packet_map.yml +++ b/data/new/packet_map.yml @@ -1,4 +1,3 @@ - !import: types.yaml mcpe_packet: name: varint => @@ -64,6 +63,7 @@ mcpe_packet: 0x3e: set_player_game_type 0x3f: player_list 0x40: simple_event + 0x41: event 0x42: spawn_experience_orb 0x43: clientbound_map_item_data 0x44: map_info_request @@ -141,6 +141,7 @@ mcpe_packet: 0x9c: packet_violation_warning 0xa2: item_component 0xa3: filter_text_packet + params: name ? if login: packet_login if play_status: packet_play_status @@ -204,6 +205,7 @@ mcpe_packet: if set_player_game_type: packet_set_player_game_type if player_list: packet_player_list if simple_event: packet_simple_event + if event: packet_event if spawn_experience_orb: packet_spawn_experience_orb if clientbound_map_item_data: packet_clientbound_map_item_data if map_info_request: packet_map_info_request @@ -280,4 +282,4 @@ mcpe_packet: if update_player_game_type: packet_update_player_game_type if packet_violation_warning: packet_packet_violation_warning if item_component: packet_item_component - if filter_text_packet: packet_filter_text_packet \ No newline at end of file + if filter_text_packet: packet_filter_text_packet diff --git a/data/new/proto.yml b/data/new/proto.yml index db42f42..526273f 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -453,19 +453,52 @@ packet_move_entity: position: vec3f rotation: Rotation +# MovePlayer is sent by players to send their movement to the server, and by the server to update the +# movement of player entities to other players. packet_move_player: !id: 0x13 !bound: both - runtime_entity_id: varint - x: lf32 - y: lf32 - z: lf32 + # EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and + # entities are generally identified in packets using this runtime ID. + runtime_id: varint + # Position is the position to spawn the player on. If the player is on a distance that the viewer cannot + # see it, the player will still show up if the viewer moves closer. + position: vec3f + # Pitch is the vertical rotation of the player. Facing straight forward yields a pitch of 0. Pitch is + # measured in degrees. pitch: lf32 + # Yaw is the horizontal rotation of the player. Yaw is also measured in degrees yaw: lf32 + # HeadYaw is the same as Yaw, except that it applies specifically to the head of the player. A different + # value for HeadYaw than Yaw means that the player will have its head turned head_yaw: lf32 - mode: u8 + # Mode is the mode of the movement. It specifies the way the player's movement should be shown to other + # players. It is one of the constants below. + mode: u8 => + 0: normal + 1: reset + 2: teleport + 3: rotation + # OnGround specifies if the player is considered on the ground. Note that proxies or hacked clients could + # fake this to always be true, so it should not be taken for granted. on_ground: bool - other_runtime_entity_id: varint + # RiddenEntityRuntimeID is the runtime ID of the entity that the player might currently be riding. If not + # riding, this should be left 0. + ridden_runtime_id: varint + teleport: mode ? + if teleport: + # TeleportCause is written only if Mode is MoveModeTeleport. It specifies the cause of the teleportation, + # which is one of the constants above. + cause: li32 => + 0: unknown + 1: projectile + 2: chorus_fruit + 3: command + 4: behavior + # TeleportSourceEntityType is the entity type that caused the teleportation, for example an ender pearl. + # TODO: is this still a integer and not a string? + source_entity_type: LegacyEntityType + tick: varint64 packet_rider_jump: !id: 0x14 @@ -489,10 +522,20 @@ packet_add_painting: direction: zigzag32 title: string +# TickSync is sent by the client and the server to maintain a synchronized, server-authoritative tick between +# the client and the server. The client sends this packet first, and the server should reply with another one +# of these packets, including the response time. packet_tick_sync: !id: 0x17 !bound: both + # ClientRequestTimestamp is the timestamp on which the client sent this packet to the server. The server + # should fill out that same value when replying. + # The ClientRequestTimestamp is always 0 request_time: li64 + # ServerReceptionTimestamp is the timestamp on which the server received the packet sent by the client. + # When the packet is sent by the client, this value is 0. + # ServerReceptionTimestamp is generally the current tick of the server. It isn't an actual timestamp, as + # the field implies response_time: li64 packet_level_sound_event_old: @@ -1037,6 +1080,33 @@ packet_simple_event: !bound: client event_type: lu16 +# Event is sent by the server to send an event with additional data. It is typically sent to the client for +# telemetry reasons, much like the SimpleEvent packet. +packet_event: + !id: 0x41 + !bound: client + runtime_id: varint64 + event_type: varint => + 0: achievement_awarded + 1: entity_interact + 2: portal_built + 3: portal_used + 4: mob_killed + 5: cauldron_used + 6: player_death + 7: boss_killed + 8: agent_command + 9: agent_created + 10: banner_pattern_removed + 11: commaned_executed + 12: fish_bucketed + 13: mob_born + 14: pet_died + 15: cauldron_block_used + 16: composter_block_used + 17: bell_block_used + use_player_id: u8 + packet_spawn_experience_orb: !id: 0x42 !bound: client @@ -1374,7 +1444,7 @@ packet_update_trade: window_id: u8 # WindowType is an identifier specifying the type of the window opened. In vanilla, it appears this is # always filled out with 15. - window_type: u8 + window_type: WindowType # Size is the amount of trading options that the villager has. size: varint # TradeTier is the tier of the villager that the player is trading with. The tier starts at 0 with a @@ -1412,7 +1482,7 @@ packet_update_equipment: window_id: u8 # WindowType is the type of the window that was opened. Generally, this is the type of a horse inventory, # as the packet is specifically made for that. - window_type: u8 + window_type: WindowType # Size is the size of the horse inventory that should be opened. A bigger size does, in fact, change the # amount of slots displayed. size: u8 diff --git a/data/new/types.yaml b/data/new/types.yaml index 8f6b109..b3418ff 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -673,3 +673,142 @@ CommandOrigin: if dev_console or test: player_entity_id: zigzag64 + +WindowType: u8 => + 0: container + 1: workbench + 2: furnace + 3: enchantment + 4: brewing_stand + 5: anvil + 6: dispenser + 7: dropper + 8: hopper + 9: cauldron + 10: minecart_chest + 11: minecart_hopper + 12: horse + 13: beacon + 14: structure_editor + 15: trading + 16: command_block + 17: jukebox + 18: armor + 19: hand + 20: compound_creator + 21: element_constructor + 22: material_reducer + 23: lab_table + 24: loom + 25: lectern + 26: grindstone + 27: blast_furnace + 28: smoker + 29: stonecutter + 30: cartography + 31: hud + 32: jigsaw_editor + 33: smithing_table + +# TODO: remove? +LegacyEntityType: li32 => + 10: chicken + 11: cow + 12: pig + 13: sheep + 14: wolf + 15: villager + 16: mooshroom + 17: squid + 18: rabbit + 19: bat + 20: iron_golem + 21: snow_golem + 22: ocelot + 23: horse + 24: donkey + 25: mule + 26: skeleton_horse + 27: zombie_horse + 28: polar_bear + 29: llama + 30: parrot + 31: dolphin + 32: zombie + 33: creeper + 34: skeleton + 35: spider + 36: zombie_pigman + 37: slime + 38: enderman + 39: silverfish + 40: cave_spider + 41: ghast + 42: magma_cube + 43: blaze + 44: zombie_villager + 45: witch + 46: stray + 47: husk + 48: wither_skeleton + 49: guardian + 50: elder_guardian + 51: npc + 52: wither + 53: ender_dragon + 54: shulker + 55: endermite + 56: agent # LEARN_TO_CODE_MASCOT + 57: vindicator + 58: phantom + 61: armor_stand + 62: tripod_camera + 63: player + 64: item + 65: tnt + 66: falling_block + 67: moving_block + 68: xp_bottle + 69: xp_orb + 70: eye_of_ender_signal + 71: ender_crystal + 72: fireworks_rocket + 73: thrown_trident + 74: turtle + 75: cat + 76: shulker_bullet + 77: fishing_hook + 78: chalkboard + 79: dragon_fireball + 80: arrow + 81: snowball + 82: egg + 83: painting + 84: minecart + 85: fireball + 86: splash_potion + 87: ender_pearl + 88: leash_knot + 89: wither_skull + 90: boat + 91: wither_skull_dangerous + 93: lightning_bolt + 94: small_fireball + 95: area_effect_cloud + 96: hopper_minecart + 97: tnt_minecart + 98: chest_minecart + 100: command_block_minecart + 101: lingering_potion + 102: llama_spit + 103: evocation_fang + 104: evocation_illager + 105: vex + 106: ice_bomb + 107: balloon + 108: pufferfish + 109: salmon + 110: drowned + 111: tropicalfish + 112: cod + 113: panda \ No newline at end of file diff --git a/data/newproto.json b/data/newproto.json index 9779bac..3a31156 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -2371,6 +2371,156 @@ } ] ], + "WindowType": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "container", + "1": "workbench", + "2": "furnace", + "3": "enchantment", + "4": "brewing_stand", + "5": "anvil", + "6": "dispenser", + "7": "dropper", + "8": "hopper", + "9": "cauldron", + "10": "minecart_chest", + "11": "minecart_hopper", + "12": "horse", + "13": "beacon", + "14": "structure_editor", + "15": "trading", + "16": "command_block", + "17": "jukebox", + "18": "armor", + "19": "hand", + "20": "compound_creator", + "21": "element_constructor", + "22": "material_reducer", + "23": "lab_table", + "24": "loom", + "25": "lectern", + "26": "grindstone", + "27": "blast_furnace", + "28": "smoker", + "29": "stonecutter", + "30": "cartography", + "31": "hud", + "32": "jigsaw_editor", + "33": "smithing_table" + } + } + ], + "LegacyEntityType": [ + "mapper", + { + "type": "li32", + "mappings": { + "10": "chicken", + "11": "cow", + "12": "pig", + "13": "sheep", + "14": "wolf", + "15": "villager", + "16": "mooshroom", + "17": "squid", + "18": "rabbit", + "19": "bat", + "20": "iron_golem", + "21": "snow_golem", + "22": "ocelot", + "23": "horse", + "24": "donkey", + "25": "mule", + "26": "skeleton_horse", + "27": "zombie_horse", + "28": "polar_bear", + "29": "llama", + "30": "parrot", + "31": "dolphin", + "32": "zombie", + "33": "creeper", + "34": "skeleton", + "35": "spider", + "36": "zombie_pigman", + "37": "slime", + "38": "enderman", + "39": "silverfish", + "40": "cave_spider", + "41": "ghast", + "42": "magma_cube", + "43": "blaze", + "44": "zombie_villager", + "45": "witch", + "46": "stray", + "47": "husk", + "48": "wither_skeleton", + "49": "guardian", + "50": "elder_guardian", + "51": "npc", + "52": "wither", + "53": "ender_dragon", + "54": "shulker", + "55": "endermite", + "56": "agent", + "57": "vindicator", + "58": "phantom", + "61": "armor_stand", + "62": "tripod_camera", + "63": "player", + "64": "item", + "65": "tnt", + "66": "falling_block", + "67": "moving_block", + "68": "xp_bottle", + "69": "xp_orb", + "70": "eye_of_ender_signal", + "71": "ender_crystal", + "72": "fireworks_rocket", + "73": "thrown_trident", + "74": "turtle", + "75": "cat", + "76": "shulker_bullet", + "77": "fishing_hook", + "78": "chalkboard", + "79": "dragon_fireball", + "80": "arrow", + "81": "snowball", + "82": "egg", + "83": "painting", + "84": "minecart", + "85": "fireball", + "86": "splash_potion", + "87": "ender_pearl", + "88": "leash_knot", + "89": "wither_skull", + "90": "boat", + "91": "wither_skull_dangerous", + "93": "lightning_bolt", + "94": "small_fireball", + "95": "area_effect_cloud", + "96": "hopper_minecart", + "97": "tnt_minecart", + "98": "chest_minecart", + "100": "command_block_minecart", + "101": "lingering_potion", + "102": "llama_spit", + "103": "evocation_fang", + "104": "evocation_illager", + "105": "vex", + "106": "ice_bomb", + "107": "balloon", + "108": "pufferfish", + "109": "salmon", + "110": "drowned", + "111": "tropicalfish", + "112": "cod", + "113": "panda" + } + } + ], "mcpe_packet": [ "container", [ @@ -2443,6 +2593,7 @@ "62": "set_player_game_type", "63": "player_list", "64": "simple_event", + "65": "event", "66": "spawn_experience_orb", "67": "clientbound_map_item_data", "68": "map_info_request", @@ -2593,6 +2744,7 @@ "set_player_game_type": "packet_set_player_game_type", "player_list": "packet_player_list", "simple_event": "packet_simple_event", + "event": "packet_event", "spawn_experience_orb": "packet_spawn_experience_orb", "clientbound_map_item_data": "packet_clientbound_map_item_data", "map_info_request": "packet_map_info_request", @@ -3534,20 +3686,12 @@ "container", [ { - "name": "runtime_entity_id", + "name": "runtime_id", "type": "varint" }, { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" + "name": "position", + "type": "vec3f" }, { "name": "pitch", @@ -3563,15 +3707,67 @@ }, { "name": "mode", - "type": "u8" + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "normal", + "1": "reset", + "2": "teleport", + "3": "rotation" + } + } + ] }, { "name": "on_ground", "type": "bool" }, { - "name": "other_runtime_entity_id", + "name": "ridden_runtime_id", "type": "varint" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "mode", + "fields": { + "teleport": [ + "container", + [ + { + "name": "teleport_cause", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "unknown", + "1": "projectile", + "2": "chorus_fruit", + "3": "command", + "4": "behavior" + } + } + ] + }, + { + "name": "source_entity_type", + "type": "LegacyEntityType" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" } ] ], @@ -4572,6 +4768,48 @@ } ] ], + "packet_event": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint64" + }, + { + "name": "event_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "achievement_awarded", + "1": "entity_interact", + "2": "portal_built", + "3": "portal_used", + "4": "mob_killed", + "5": "cauldron_used", + "6": "player_death", + "7": "boss_killed", + "8": "agent_command", + "9": "agent_created", + "10": "pattern_removed", + "11": "commaned_executed", + "12": "fish_bucketed", + "13": "mob_born", + "14": "pet_died", + "15": "cauldron_block_used", + "16": "composter_block_used", + "17": "bell_block_used" + } + } + ] + }, + { + "name": "use_player_id", + "type": "u8" + } + ] + ], "packet_spawn_experience_orb": [ "container", [ @@ -5115,7 +5353,7 @@ }, { "name": "window_type", - "type": "u8" + "type": "WindowType" }, { "name": "size", @@ -5160,7 +5398,7 @@ }, { "name": "window_type", - "type": "u8" + "type": "WindowType" }, { "name": "size", diff --git a/package.json b/package.json index 90a49d6..6f9b891 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Parse and serialize Minecraft Bedrock Edition packets", "main": "index.js", "scripts": { + "build": "cd data/new && node compile.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ diff --git a/src/serverTest.js b/src/serverTest.js index 6d01f96..ed6883a 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -54,6 +54,7 @@ server.on('connect', ({ client }) => { client.queue('player_list', require('./packets/player_list.json')) client.queue('start_game', require('./packets/start_game.json')) client.queue('item_component', {"entries":[]}) + client.queue('set_spawn_position', require('./packets/set_spawn_position.json')) client.queue('set_time', { time: 5433771 }) client.queue('set_difficulty', { difficulty: 1 }) client.queue('set_commands_enabled', { enabled: true }) @@ -64,24 +65,28 @@ server.on('connect', ({ client }) => { client.queue('update_attributes', require('./packets/update_attributes.json')) client.queue('creative_content', require('./packets/creative_content.json')) + client.queue('inventory_content', require('./packets/inventory_content.json')) client.queue('player_hotbar', {"selected_slot":3,"window_id":0,"select_slot":true}) client.queue('crafting_data', require('./packets/crafting_data.json')) client.queue('available_commands', require('./packets/available_commands.json')) + client.queue('chunk_radius_update', {"chunk_radius":5}) + + client.queue('set_entity_data', require('./packets/set_entity_data.json')) client.queue('game_rules_changed', require('./packets/game_rules_changed.json')) client.queue('respawn', {"x":646.9405517578125,"y":65.62001037597656,"z":77.86255645751953,"state":0,"runtime_entity_id":0}) - // for (const file of fs.readdirSync('chunks')) { - // const buffer = Buffer.from(fs.readFileSync('./chunks/' + file, 'utf8'), 'hex') - // // console.log('Sending chunk', chunk) - // client.sendBuffer(buffer) - // } - - for (const chunk of chunks) { - client.queue('level_chunk', chunk) + for (const file of fs.readdirSync('chunks')) { + const buffer = Buffer.from(fs.readFileSync('./chunks/' + file, 'utf8'), 'hex') + // console.log('Sending chunk', chunk) + client.sendBuffer(buffer) } + // for (const chunk of chunks) { + // client.queue('level_chunk', chunk) + // } + setInterval(() => { client.write('network_chunk_publisher_update', {"coordinates":{"x":646,"y":130,"z":77},"radius":64}) }, 9500) @@ -90,6 +95,14 @@ server.on('connect', ({ client }) => { setTimeout(() => { client.write('play_status', { status: 'player_spawn' }) }, 8000) + + // Respond to tick synchronization packets + client.on('tick_sync', ({ request_time }) => { + client.queue('tick_sync', { + request_time, + response_time: BigInt(Date.now()) + }) + }) }) }) }) @@ -101,7 +114,7 @@ async function sleep(ms) { } // CHUNKS -const { ChunkColumn, Version } = require('bedrock-provider') +// const { ChunkColumn, Version } = require('bedrock-provider') const mcData = require('minecraft-data')('1.16') var chunks = [] async function buildChunks() { @@ -133,4 +146,4 @@ async function buildChunks() { // console.log('Chunks',chunks) } -buildChunks() \ No newline at end of file +// buildChunks() \ No newline at end of file From 863d51c56adf1508f9ca1df8fa1955ebb283da74 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Feb 2021 22:18:25 -0500 Subject: [PATCH 109/458] Protocol updates, new packets --- data/new/packet_map.yml | 22 ++ data/new/proto.yml | 315 ++++++++++++++++++++++++-- data/new/types.yaml | 10 + data/newproto.json | 474 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 784 insertions(+), 37 deletions(-) diff --git a/data/new/packet_map.yml b/data/new/packet_map.yml index ff3e7f0..45d1f33 100644 --- a/data/new/packet_map.yml +++ b/data/new/packet_map.yml @@ -124,6 +124,8 @@ mcpe_packet: 0x7c: level_event_generic 0x7d: lectern_update 0x7e: video_stream_connect + 0x7f: add_ecs_entity + 0x80: remove_ecs_entity 0x81: client_cache_status 0x82: on_screen_texture_animation 0x83: map_create_locked_copy @@ -132,12 +134,21 @@ mcpe_packet: 0x86: update_block_properties 0x87: client_cache_blob_status 0x88: client_cache_miss_response + 0x89: education_settings + 0x8b: multiplayer_settings + 0x8c: settings_command + 0x8d: anvil_damage + 0x8e: completed_using_item 0x8f: network_settings + 0x90: player_auth_input 0x91: creative_content 0x92: player_enchant_options 0x93: item_stack_request 0x94: item_stack_response + 0x95: player_armor_damage 0x97: update_player_game_type + 0x9a: position_tracking_db_request + 0x99: position_tracking_db_broadcast 0x9c: packet_violation_warning 0xa2: item_component 0xa3: filter_text_packet @@ -266,6 +277,8 @@ mcpe_packet: if level_event_generic: packet_level_event_generic if lectern_update: packet_lectern_update if video_stream_connect: packet_video_stream_connect + if add_ecs_entity: packet_add_ecs_entity + if remove_ecs_entity: packet_remove_ecs_entity if client_cache_status: packet_client_cache_status if on_screen_texture_animation: packet_on_screen_texture_animation if map_create_locked_copy: packet_map_create_locked_copy @@ -274,12 +287,21 @@ mcpe_packet: if update_block_properties: packet_update_block_properties if client_cache_blob_status: packet_client_cache_blob_status if client_cache_miss_response: packet_client_cache_miss_response + if education_settings: packet_education_settings + if multiplayer_settings: packet_multiplayer_settings + if settings_command: packet_settings_command + if anvil_damage: packet_anvil_damage + if completed_using_item: packet_completed_using_item if network_settings: packet_network_settings + if player_auth_input: packet_player_auth_input if creative_content: packet_creative_content if player_enchant_options: packet_player_enchant_options if item_stack_request: packet_item_stack_request if item_stack_response: packet_item_stack_response + if player_armor_damage: packet_player_armor_damage if update_player_game_type: packet_update_player_game_type + if position_tracking_db_request: packet_position_tracking_db_request + if position_tracking_db_broadcast: packet_position_tracking_db_broadcast if packet_violation_warning: packet_packet_violation_warning if item_component: packet_item_component if filter_text_packet: packet_filter_text_packet diff --git a/data/new/proto.yml b/data/new/proto.yml index 526273f..c2c5c1f 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -41,6 +41,7 @@ nbt: native packet_login: !id: 0x01 !bound: server + # Protocol version (Big Endian!) protocol_version: i32 # The combined size of the `chain` and `client_data` payload_size: varint @@ -205,13 +206,7 @@ packet_start_game: # creative spectator. # This field may be set to 5 to make the client fall back to the game mode set in the WorldGameMode # field. - player_gamemode: zigzag32 => - 0: survival - 1: creative - 2: adventure - 3: survival_spectator - 4: creative_spectator - 5: fallback + player_gamemode: GameMode # The spawn position of the player in the world. In servers this is often the same as the # world's spawn position found below. spawn: vec3f @@ -229,9 +224,9 @@ packet_start_game: # 4 being end worlds. A value of 0 will actually make the client stop rendering chunks you # send beyond the world limit. generator: zigzag32 - # The game mode that a player gets when it first spawns in the world. It is shown in the + # The world game mode that a player gets when it first spawns in the world. It is shown in the # settings and is used if the Player Gamemode is set to 5. - gamemode: zigzag32 + world_gamemode: GameMode # Difficulty is the difficulty of the world. It is a value from 0-3, with 0 being peaceful, # 1 being easy, 2 being normal and 3 being hard. difficulty: zigzag32 @@ -1065,10 +1060,14 @@ packet_change_dimension: position: vec3f respawn: bool +# SetPlayerGameType is sent by the server to update the game type (game mode) of the player packet_set_player_game_type: !id: 0x3e !bound: both - gamemode: zigzag32 + # The new gamemode for the player. + # Some of these game types require additional flags to be set in an AdventureSettings packet for + # the game mode to obtain its full functionality. + gamemode: GameMode packet_player_list: !id: 0x3f @@ -1658,10 +1657,15 @@ packet_show_profile: !bound: client xuid: string +# SetDefaultGameType is sent by the client when it toggles the default game type in the settings UI, and is +# sent by the server when it actually changes the default game type, resulting in the toggle being changed +# in the settings UI. packet_set_default_game_type: !id: 0x69 !bound: client - gamemode: varint + # GameType is the new game type that is set. When sent by the client, this is the requested new default + # game type. + gamemode: GameMode packet_remove_objective: !id: 0x6a @@ -1834,6 +1838,27 @@ packet_video_stream_connect: resolution_x: li32 resolution_y: li32 +# This is NOT a Minecraft entity, but an entity in the Entity Component System (ECS) +# for the game engine Minecrat Bedrock uses. Internally, all 'Minecraft entities' are +# known as Actors including in packet names and fields. However, these are irrelevant +# internal details so we don't do the renames in these protocol definitions, for simplicity we just use Entity. +# +# AddEntity is sent by the server to the client. Its function is not entirely clear: It does not add an +# entity in the sense of an in-game entity, but has to do with the ECS that Minecraft uses. +packet_add_ecs_entity: + !id: 0x7f + !bound: client + # EntityNetworkID is the network ID of the entity that should be added. + network_id: varint64 + +# RemoveEntity is sent by the server to the client. Its function is not entirely clear: It does not remove an +# entity in the sense of an in-game entity, but has to do with the ECS that Minecraft uses +packet_remove_ecs_entity: + !id: 0x80 + !bound: client + # EntityNetworkID is the network ID of the entity that should be removed. + network_id: varint64 + packet_client_cache_status: !id: 0x81 !bound: both @@ -1879,6 +1904,88 @@ packet_client_cache_miss_response: !bound: client blobs: Blob[]varint +# EducationSettings is a packet sent by the server to update Minecraft: Education Edition related settings. +# It is unused by the normal base game. +packet_education_settings: + !id: 0x89 + !bound: client + # CodeBuilderDefaultURI is the default URI that the code builder is ran on. Using this, a Code Builder + # program can make code directly affect the server. + CodeBuilderDefaultURI: string + # CodeBuilderTitle is the title of the code builder shown when connected to the CodeBuilderDefaultURI. + CodeBuilderTitle: string + # CanResizeCodeBuilder specifies if clients connected to the world should be able to resize the code + # builder when it is opened. + CanResizeCodeBuilder: bool + HasOverrideURI: bool + OverrideURI: HasOverrideURI? + if true: string + # HasQuiz specifies if the world has a quiz connected to it. + HasQuiz: bool + +# MultiPlayerSettings is sent by the client to update multi-player related settings server-side and sent back +# to online players by the server. +# The MultiPlayerSettings packet is a Minecraft: Education Edition packet. It has no functionality for the +# base game. +packet_multiplayer_settings: + !id: 0x8b + !bound: server + # ActionType is the action that should be done when this packet is sent. It is one of the constants that + # may be found above. + action_type: zigzag32 => + 0: enable_multiplayer + 1: disable_multiplayer + 2: refresh_join_code + +# SettingsCommand is sent by the client when it changes a setting in the settings that results in the issuing +# of a command to the server, such as when Show Coordinates is enabled. +packet_settings_command: + !id: 0x8c + !bound: server + # CommandLine is the full command line that was sent to the server as a result of the setting that the + # client changed. + command_line: string + # SuppressOutput specifies if the client requests the suppressing of the output of the command that was + # executed. Generally this is set to true, as the client won't need a message to confirm the output of + # the change. + suppress_output: bool + +# AnvilDamage is sent by the client to request the dealing damage to an anvil. This packet is completely +# pointless and the server should never listen to it. +packet_anvil_damage: + !id: 0x8d + !bound: server + # Damage is the damage that the client requests to be dealt to the anvil. + damage: u8 + # AnvilPosition is the position in the world that the anvil can be found at. + position: BlockCoordinates + +# CompletedUsingItem is sent by the server to tell the client that it should be done using the item it is +# currently using. +packet_completed_using_item: + !id: 0x8e + !bound: client + # UsedItemID is the item ID of the item that the client completed using. This should typically be the + # ID of the item held in the hand. + used_item_id: li16 + # UseMethod is the method of the using of the item that was completed. It is one of the constants that + # may be found above. + use_method: li32 => + 0: equip_armor + 1: eat + 2: attack + 3: consume + 4: throw + 5: shoot + 6: place + 7: fill_bottle + 8: fill_bucket + 9: pour_bucket + 10: use_tool + 11: interact + 12: retrieved + 13: dyed + 14: traded # NetworkSettings is sent by the server to update a variety of network settings. These settings modify the # way packets are sent over the network stack. @@ -1890,6 +1997,90 @@ packet_network_settings: # When set to 0, all packets will be left uncompressed. compression_threshold: u16 + +# PlayerAuthInput is sent by the client to allow for server authoritative movement. It is used to synchronise +# the player input with the position server-side. +# The client sends this packet when the ServerAuthoritativeMovementMode field in the StartGame packet is set +# to true, instead of the MovePlayer packet. The client will send this packet once every tick. +packet_player_auth_input: + !id: 0x90 + !bound: server + # Pitch that the player reports it has. + pitch: lf32 + # Yaw that player reports it has. + yaw: lf32 + # Position holds the position that the player reports it has. + position: vec3f + # MoveVector is a Vec2 that specifies the direction in which the player moved, as a combination of X/Z + # values which are created using the WASD/controller stick state. + move_vector: vec2f + # HeadYaw is the horizontal rotation of the head that the player reports it has. + head_yaw: lf32 + # InputData is a combination of bit flags that together specify the way the player moved last tick. It + # is a combination of the flags above. + input_data: InputFlag + # InputMode specifies the way that the client inputs data to the screen. It is one of the constants that + # may be found above. + input_mode: varint => + 0: mouse + 1: touch + 2: game_pad + 3: motion_controller + # PlayMode specifies the way that the player is playing. The values it holds, which are rather random, + # may be found above. + play_mode: varint => + 0: normal + 1: teaser + 2: screen + 3: viewer + 4: reality + 5: placement + 6: living_room + 7: exit_level + 8: exit_level_living_room + 9: num_modes + # GazeDirection is the direction in which the player is gazing, when the PlayMode is PlayModeReality: In + # other words, when the player is playing in virtual reality. + gaze_direction: play_mode ? + if reality: vec3f + # Tick is the server tick at which the packet was sent. It is used in relation to + # CorrectPlayerMovePrediction. + tick: varint64 + # Delta was the delta between the old and the new position. There isn't any practical use for this field + # as it can be calculated by the server itself. + delta: vec3f + +InputFlag: [ "bitflags", { + "type": "varint64", + "flags": { + "ascend": 0b1, + "descend": 0b10, + "north_jump": 0b100, + "jump_down": 0b1000, + "sprint_down": 0b10000, + "change_height": 0b100000, + "jumping": 0b1000000, + "auto_jumping_in_water": 0b10000000, + "sneaking": 0b100000000, + "sneak_down": 0b1000000000, + "up": 0b10000000000, + "down": 0b100000000000, + "left": 0b1000000000000, + "right": 0b10000000000000, + "up_left": 0b100000000000000, + "up_right": 0b1000000000000000, + "want_up": 0b10000000000000000, + "want_down": 0b100000000000000000, + "want_down_slow": 0b1000000000000000000, + "want_up_slow": 0b10000000000000000000, + "sprinting": 0b100000000000000000000, + "ascend_scaffolding": 0b1000000000000000000000, + "descend_scaffolding": 0b10000000000000000000000, + "sneak_toggle_down": 0b100000000000000000000000, + "persist_sneak": 0b1000000000000000000000000, + } +}] + packet_creative_content: !id: 0x91 !bound: client @@ -1910,25 +2101,123 @@ packet_item_stack_response: !bound: client responses: ItemStackResponses +# PlayerArmourDamage is sent by the server to damage the armour of a player. It is a very efficient packet, +# but generally it's much easier to just send a slot update for the damaged armour. +packet_player_armor_damage: + !id: 0x95 + !bound: client + # Bitset holds a bitset of 4 bits that indicate which pieces of armour need to have damage dealt to them. + # The first bit, when toggled, is for a helmet, the second for the chestplate, the third for the leggings + # and the fourth for boots. + type: ArmorDamageType + helmet_damage: type.head ? + if true: zigzag32 + chestplate_damage: type.chest ? + if true: zigzag32 + leggings_damage: type.legs ? + if true: zigzag32 + boots_damage: types.feet ? + if true: zigzag32 + +ArmorDamageType: [ "bitflags", + { + "type": "u8", + "flags": { + "head": 0b1, + "chest": 0b10, + "legs": 0b100, + "feet": 0b1000 + } + } +] + +# UpdatePlayerGameType is sent by the server to change the game mode of a player. It is functionally +# identical to the SetPlayerGameType packet. packet_update_player_game_type: !id: 0x97 !bound: server + # GameType is the new game type of the player. It is one of the constants that can be found in + # set_player_game_type.go. Some of these game types require additional flags to be set in an + # AdventureSettings packet for the game mode to obtain its full functionality. + gamemode: GameMode + # PlayerUniqueID is the entity unique ID of the player that should have its game mode updated. If this + # packet is sent to other clients with the player unique ID of another player, nothing happens. + player_unique_id: zigzag64 + +# PositionTrackingDBClientRequest is a packet sent by the client to request the position and dimension of a +# 'tracking ID'. These IDs are tracked in a database by the server. In 1.16, this is used for lodestones. +# The client will send this request to find the position a lodestone compass needs to point to. If found, it +# will point to the lodestone. If not, it will start spinning around. +# A PositionTrackingDBServerBroadcast packet should be sent in response to this packet. +packet_position_tracking_db_request: + !id: 0x9a + !bound: server + # RequestAction is the action that should be performed upon the receiving of the packet. It is one of the + # constants found above. + action: u8 => + 0: query + # TrackingID is a unique ID used to identify the request. The server responds with a + # PositionTrackingDBServerBroadcast packet holding the same ID, so that the client can find out what that + # packet was in response to. + tracking_id: zigzag32 + +# PositionTrackingDBServerBroadcast is sent by the server in response to the +# PositionTrackingDBClientRequest packet. This packet is, as of 1.16, currently only used for lodestones. The +# server maintains a database with tracking IDs and their position and dimension. The client will request +# these tracking IDs, (NBT tag set on the lodestone compass with the tracking ID?) and the server will +# respond with the status of those tracking IDs. +# What is actually done with the data sent depends on what the client chooses to do with it. For the +# lodestone compass, it is used to make the compass point towards lodestones and to make it spin if the +# lodestone at a position is no longer there. +packet_position_tracking_db_broadcast: + !id: 0x99 + !bound: client + # BroadcastAction specifies the status of the position tracking DB response. It is one of the constants + # above, specifying the result of the request with the ID below. + # The Update action is sent for setting the position of a lodestone compass, the Destroy and NotFound to + # indicate that there is not (no longer) a lodestone at that position. + broadcast_action: u8 => + 0: update + 1: destory + 2: not_found + # TrackingID is the ID of the PositionTrackingDBClientRequest packet that this packet was in response to. + # The tracking ID is also present as the 'id' field in the SerialisedData field. + tracking_id: zigzag32 + nbt: nbt + +# PacketViolationWarning is sent by the client when it receives an invalid packet from the server. It holds +# some information on the error that occurred. packet_packet_violation_warning: !id: 0x9c !bound: server - violation_type: zigzag32 - severity: zigzag32 + violation_type: zigzag32 => + 0: malformed + # Severity specifies the severity of the packet violation. The action the client takes after this + # violation depends on the severity sent. + severity: zigzag32 => + 0: warning + 1: final_warning + 2: terminating + # PacketID is the ID of the invalid packet that was received. packet_id: zigzag32 + # ViolationContext holds a description on the violation of the packet. reason: string +# ItemComponent is sent by the server to attach client-side components to a custom item. packet_item_component: !id: 0xa2 !bound: client + # `entries` holds a list of all custom items with their respective components set. entries: ItemComponentList +# FilterText is sent by the both the client and the server. The client sends the packet to the server to +# allow the server to filter the text server-side. The server then responds with the same packet and the +# safer version of the text. packet_filter_text_packet: !id: 0xa3 !bound: client + # Text is either the text from the client or the safer version of the text sent by the server. text: string + # FromServer indicates if the packet was sent by the server or not. from_server: bool diff --git a/data/new/types.yaml b/data/new/types.yaml index b3418ff..9be85ae 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -35,6 +35,14 @@ Experiment: Experiments: Experiment[]li32 +GameMode: zigzag32 => + 0: survival + 1: creative + 2: adventure + 3: survival_spectator + 4: creative_spectator + 5: fallback + GameRule: name: string type: varint => @@ -638,7 +646,9 @@ ItemStackResponses: []varint custom_name: string ItemComponentList: []varint + # Name is the name of the item, which is a name like 'minecraft:stick'. name: string + # Data is a map containing the components and properties of the item. nbt: nbt CommandOrigin: diff --git a/data/newproto.json b/data/newproto.json index 3a31156..38f4bfd 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -141,6 +141,20 @@ "type": "Experiment" } ], + "GameMode": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "survival", + "1": "creative", + "2": "adventure", + "3": "survival_spectator", + "4": "creative_spectator", + "5": "fallback" + } + } + ], "GameRule": [ "container", [ @@ -2654,6 +2668,8 @@ "124": "level_event_generic", "125": "lectern_update", "126": "video_stream_connect", + "127": "add_ecs_entity", + "128": "remove_ecs_entity", "129": "client_cache_status", "130": "on_screen_texture_animation", "131": "map_create_locked_copy", @@ -2662,12 +2678,21 @@ "134": "update_block_properties", "135": "client_cache_blob_status", "136": "client_cache_miss_response", + "137": "education_settings", + "139": "multiplayer_settings", + "140": "settings_command", + "141": "anvil_damage", + "142": "completed_using_item", "143": "network_settings", + "144": "player_auth_input", "145": "creative_content", "146": "player_enchant_options", "147": "item_stack_request", "148": "item_stack_response", + "149": "player_armor_damage", "151": "update_player_game_type", + "153": "position_tracking_db_broadcast", + "154": "position_tracking_db_request", "156": "packet_violation_warning", "162": "item_component", "163": "filter_text_packet" @@ -2805,6 +2830,8 @@ "level_event_generic": "packet_level_event_generic", "lectern_update": "packet_lectern_update", "video_stream_connect": "packet_video_stream_connect", + "add_ecs_entity": "packet_add_ecs_entity", + "remove_ecs_entity": "packet_remove_ecs_entity", "client_cache_status": "packet_client_cache_status", "on_screen_texture_animation": "packet_on_screen_texture_animation", "map_create_locked_copy": "packet_map_create_locked_copy", @@ -2813,12 +2840,21 @@ "update_block_properties": "packet_update_block_properties", "client_cache_blob_status": "packet_client_cache_blob_status", "client_cache_miss_response": "packet_client_cache_miss_response", + "education_settings": "packet_education_settings", + "multiplayer_settings": "packet_multiplayer_settings", + "settings_command": "packet_settings_command", + "anvil_damage": "packet_anvil_damage", + "completed_using_item": "packet_completed_using_item", "network_settings": "packet_network_settings", + "player_auth_input": "packet_player_auth_input", "creative_content": "packet_creative_content", "player_enchant_options": "packet_player_enchant_options", "item_stack_request": "packet_item_stack_request", "item_stack_response": "packet_item_stack_response", + "player_armor_damage": "packet_player_armor_damage", "update_player_game_type": "packet_update_player_game_type", + "position_tracking_db_request": "packet_position_tracking_db_request", + "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", "packet_violation_warning": "packet_packet_violation_warning", "item_component": "packet_item_component", "filter_text_packet": "packet_filter_text_packet" @@ -3177,20 +3213,7 @@ }, { "name": "player_gamemode", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "survival", - "1": "creative", - "2": "adventure", - "3": "survival_spectator", - "4": "creative_spectator", - "5": "fallback" - } - } - ] + "type": "GameMode" }, { "name": "spawn", @@ -3221,8 +3244,8 @@ "type": "zigzag32" }, { - "name": "gamemode", - "type": "zigzag32" + "name": "world_gamemode", + "type": "GameMode" }, { "name": "difficulty", @@ -3729,7 +3752,7 @@ "type": "varint" }, { - "anon": true, + "name": "teleport", "type": [ "switch", { @@ -3739,7 +3762,7 @@ "container", [ { - "name": "teleport_cause", + "name": "cause", "type": [ "mapper", { @@ -4746,7 +4769,7 @@ [ { "name": "gamemode", - "type": "zigzag32" + "type": "GameMode" } ] ], @@ -4792,7 +4815,7 @@ "7": "boss_killed", "8": "agent_command", "9": "agent_created", - "10": "pattern_removed", + "10": "banner_pattern_removed", "11": "commaned_executed", "12": "fish_bucketed", "13": "mob_born", @@ -5835,7 +5858,7 @@ [ { "name": "gamemode", - "type": "varint" + "type": "GameMode" } ] ], @@ -6218,6 +6241,24 @@ } ] ], + "packet_add_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_remove_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], "packet_client_cache_status": [ "container", [ @@ -6292,6 +6333,124 @@ } ] ], + "packet_education_settings": [ + "container", + [ + { + "name": "CodeBuilderDefaultURI", + "type": "string" + }, + { + "name": "CodeBuilderTitle", + "type": "string" + }, + { + "name": "CanResizeCodeBuilder", + "type": "bool" + }, + { + "name": "HasOverrideURI", + "type": "bool" + }, + { + "name": "OverrideURI", + "type": [ + "switch", + { + "compareTo": "HasOverrideURI", + "fields": { + "true": "string" + }, + "default": "void" + } + ] + }, + { + "name": "HasQuiz", + "type": "bool" + } + ] + ], + "packet_multiplayer_settings": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "enable_multiplayer", + "1": "disable_multiplayer", + "2": "refresh_join_code" + } + } + ] + } + ] + ], + "packet_settings_command": [ + "container", + [ + { + "name": "command_line", + "type": "string" + }, + { + "name": "suppress_output", + "type": "bool" + } + ] + ], + "packet_anvil_damage": [ + "container", + [ + { + "name": "damage", + "type": "u8" + }, + { + "name": "position", + "type": "BlockCoordinates" + } + ] + ], + "packet_completed_using_item": [ + "container", + [ + { + "name": "used_item_id", + "type": "li16" + }, + { + "name": "use_method", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "equip_armor", + "1": "eat", + "2": "attack", + "3": "consume", + "4": "throw", + "5": "shoot", + "6": "place", + "7": "fill_bottle", + "8": "fill_bucket", + "9": "pour_bucket", + "10": "use_tool", + "11": "interact", + "12": "retrieved", + "13": "dyed", + "14": "traded" + } + } + ] + } + ] + ], "packet_network_settings": [ "container", [ @@ -6301,6 +6460,92 @@ } ] ], + "packet_player_auth_input": [ + "container", + [ + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "move_vector", + "type": "vec2f" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "input_data", + "type": "InputFlag" + }, + { + "name": "input_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "mouse", + "1": "touch", + "2": "game_pad", + "3": "motion_controller" + } + } + ] + }, + { + "name": "play_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "teaser", + "2": "screen", + "3": "viewer", + "4": "reality", + "5": "placement", + "6": "living_room", + "7": "exit_level", + "8": "exit_level_living_room", + "9": "num_modes" + } + } + ] + }, + { + "name": "gaze_direction", + "type": [ + "switch", + { + "compareTo": "play_mode", + "fields": { + "reality": "vec3f" + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + }, + { + "name": "delta", + "type": "vec3f" + } + ] + ], "packet_creative_content": [ "container", [ @@ -6337,20 +6582,156 @@ } ] ], + "packet_player_armor_damage": [ + "container", + [ + { + "name": "type", + "type": "ArmorDamageType" + }, + { + "name": "helmet_damage", + "type": [ + "switch", + { + "compareTo": "type.head", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "chestplate_damage", + "type": [ + "switch", + { + "compareTo": "type.chest", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "leggings_damage", + "type": [ + "switch", + { + "compareTo": "type.legs", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "boots_damage", + "type": [ + "switch", + { + "compareTo": "types.feet", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + } + ] + ], "packet_update_player_game_type": [ "container", - [] + [ + { + "name": "gamemode", + "type": "GameMode" + }, + { + "name": "player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_position_tracking_db_request": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "query" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + } + ] + ], + "packet_position_tracking_db_broadcast": [ + "container", + [ + { + "name": "broadcast_action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "update", + "1": "destory", + "2": "not_found" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + }, + { + "name": "nbt", + "type": "nbt" + } + ] ], "packet_packet_violation_warning": [ "container", [ { "name": "violation_type", - "type": "zigzag32" + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "malformed" + } + } + ] }, { "name": "severity", - "type": "zigzag32" + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "warning", + "1": "final_warning", + "2": "terminating" + } + } + ] }, { "name": "packet_id", @@ -6469,6 +6850,51 @@ "force_move": 256 } } + ], + "InputFlag": [ + "bitflags", + { + "type": "varint64", + "flags": { + "ascend": 1, + "descend": 2, + "north_jump": 4, + "jump_down": 8, + "sprint_down": 16, + "change_height": 32, + "jumping": 64, + "auto_jumping_in_water": 128, + "sneaking": 256, + "sneak_down": 512, + "up": 1024, + "down": 2048, + "left": 4096, + "right": 8192, + "up_left": 16384, + "up_right": 32768, + "want_up": 65536, + "want_down": 131072, + "want_down_slow": 262144, + "want_up_slow": 524288, + "sprinting": 1048576, + "ascend_scaffolding": 2097152, + "descend_scaffolding": 4194304, + "sneak_toggle_down": 8388608, + "persist_sneak": 16777216 + } + } + ], + "ArmorDamageType": [ + "bitflags", + { + "type": "u8", + "flags": { + "head": 1, + "chest": 2, + "legs": 4, + "feet": 8 + } + } ] } } \ No newline at end of file From f00357eca60fcd4ad26a3f04bf7a6d35c0474164 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 5 Mar 2021 02:13:40 -0500 Subject: [PATCH 110/458] Logging updates --- src/ConnWorker.js | 3 ++- src/auth/encryption.js | 1 + src/client.js | 26 ++++++++++++++++++-------- src/clientTest.js | 4 ++-- src/connection.js | 28 ++++++++++++++++++---------- src/server.js | 10 +++++++--- src/serverPlayer.js | 11 ++++++++--- src/serverTest.js | 2 +- 8 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/ConnWorker.js b/src/ConnWorker.js index 996ed56..e43aea5 100644 --- a/src/ConnWorker.js +++ b/src/ConnWorker.js @@ -1,6 +1,7 @@ const RakClient = require('jsp-raknet/client') const { Worker, isMainThread, parentPort } = require('worker_threads') const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') +const Reliability = require('jsp-raknet/protocol/reliability') function connect(hostname, port) { if (isMainThread) { @@ -49,7 +50,7 @@ function main() { console.log('SEND' , globalThis.raknetConnection, evt.packet) const sendPacket = new EncapsulatedPacket() - sendPacket.reliability = 0 + sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = evt.packet globalThis.raknetConnection?.addEncapsulatedToQueue(sendPacket) diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 375fc27..d758f41 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -80,6 +80,7 @@ function Encrypt(client, server, options) { // It works! First encrypted packet :) client.write('client_to_server_handshake', {}) + this.emit('join') } client.on('server.client_handshake', startClientboundEncryption) diff --git a/src/client.js b/src/client.js index 6ceca76..6ed2816 100644 --- a/src/client.js +++ b/src/client.js @@ -8,13 +8,16 @@ const Options = require('./options') const debug = require('debug')('minecraft-protocol') const fs = require('fs') -const log = console.log const useWorkers = true class Client extends Connection { + /** + * + * @param {{ version: number, hostname: string, port: number }} options + */ constructor(options) { super() - this.options = { ...Options.defaultOptions, options } + this.options = { ...Options.defaultOptions, ...options } this.serializer = createSerializer() this.deserializer = createDeserializer() this.validateOptions() @@ -29,10 +32,14 @@ class Client extends Connection { this.on('session', this.connect) this.startQueue() + this.inLog = (...args) => console.info('C ->', ...args) + this.outLog = (...args) => console.info('C <-', ...args) // this.on('decrypted', this.onDecryptedPacket) } validateOptions() { + // console.log('Options', this.options) + if (!this.options.hostname || this.options.port == null) throw Error('Invalid hostname/port') if (this.options.version < Options.MIN_VERSION) { throw new Error(`Unsupported protocol version < ${Options.MIN_VERSION} : ${this.options.version}`) } @@ -45,8 +52,10 @@ class Client extends Connection { } connect = async (sessionData) => { + const hostname = this.options.hostname || '127.0.0.1' + const port = this.options.port || 19132 if (useWorkers) { - this.worker = ConnWorker.connect('127.0.0.1', 19132) + this.worker = ConnWorker.connect(hostname, port) this.worker.on('message', (evt) => { switch (evt.type) { case 'connected': @@ -103,6 +112,7 @@ class Client extends Connection { chain: encodedChain, client_data: this.clientUserChain }) + this.emit('loggingIn') } onDisconnectRequest(packet) { @@ -112,11 +122,11 @@ class Client extends Connection { process.exit(1) } + close() { + console.warn('Close not implemented!!') + } + tryRencode(name, params, actual) { - if (name == 'level_chunk') { - console.log("Skipping chunk validation, it's broken right now") - return - } const packet = this.serializer.createPacketBuffer({ name, params }) console.assert(packet.toString('hex') == actual.toString('hex')) @@ -138,7 +148,7 @@ class Client extends Connection { // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } - console.log('->', pakData.name, serialize(pakData.params).slice(0, 100)) + this.inLog('-> C', pakData.name, serialize(pakData.params).slice(0, 100)) // No idea what this exotic 0xA0 packet is, it's not implemented anywhere // and seems empty. Possible gibberish from the raknet impl diff --git a/src/clientTest.js b/src/clientTest.js index 75a621d..4e0e620 100644 --- a/src/clientTest.js +++ b/src/clientTest.js @@ -1,4 +1,4 @@ -// process.env.DEBUG = 'minecraft-protocol raknet' +process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('./client') const fs = require('fs') // console.log = () => @@ -6,7 +6,7 @@ const fs = require('fs') async function test() { const client = new Client({ hostname: '127.0.0.1', - port: 19132 + port: 19130 }) client.once('resource_packs_info', (packet) => { diff --git a/src/connection.js b/src/connection.js index 44f3891..3795b0e 100644 --- a/src/connection.js +++ b/src/connection.js @@ -3,19 +3,24 @@ const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') +const Reliability = require('jsp-raknet/protocol/reliability') + const debug = require('debug')('minecraft-protocol') class Connection extends EventEmitter { startEncryption(iv) { this.encryptionEnabled = true - console.log('Started encryption', this.sharedSecret, iv) + this.inLog('Started encryption', this.sharedSecret, iv) this.decrypt = cipher.createDecryptor(this, iv) this.encrypt = cipher.createEncryptor(this, iv) + this.q2 = [] } write(name, params) { // TODO: Batch - console.log('Need to encode', name, params) - // console.log('<-', name) + // console.log('Need to encode', name, params) + var s = this.connect ? 'C' : 'S' + if (this.downQ) s += 'P' + this.outLog('<- ' + s, name) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) // console.log('Sending buf', packet.toString('hex').) @@ -29,9 +34,10 @@ class Connection extends EventEmitter { } queue(name, params) { - console.log('<- ', name) + this.outLog('Q <- ', name) const packet = this.serializer.createPacketBuffer({ name, params }) this.q.push(packet) + this.q2.push(name) } startQueue() { @@ -40,9 +46,10 @@ class Connection extends EventEmitter { if (this.q.length) { //TODO: can we just build Batch before the queue loop? const batch = new BatchPacket() + this.outLog('<- BATCH', this.q2) // For now, we're over conservative so send max 3 packets // per batch and hold the rest for the next tick - for (let i = 0; i < 3 && i < this.q.length; i++) { + for (let i = 0; /*i < 10 &&*/ i < this.q.length; i++) { const packet = this.q.shift() batch.addEncodedPacket(packet) } @@ -51,6 +58,7 @@ class Connection extends EventEmitter { } else { this.sendDecryptedBatch(batch) } + this.q2 = [] } }, 100) } @@ -105,11 +113,11 @@ class Connection extends EventEmitter { // TODO: Rename this to sendEncapsulated sendMCPE(buffer, immediate) { if (this.worker) { - console.log('-> buf', buffer) + this.outLog('-> buf', buffer) this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) } else { const sendPacket = new EncapsulatedPacket() - sendPacket.reliability = 0 + sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = buffer this.connection.addEncapsulatedToQueue(sendPacket) if (immediate) this.connection.sendQueue() @@ -118,10 +126,10 @@ class Connection extends EventEmitter { // These are callbacks called from encryption.js onEncryptedPacket = (buf) => { - console.log('ENC BUF', buf) + this.outLog('ENC BUF', buf) const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header - console.log('Sending wrapped encrypted batch', packet) + this.outLog('Sending wrapped encrypted batch', packet) this.sendMCPE(packet) } @@ -145,7 +153,7 @@ class Connection extends EventEmitter { const batch = new BatchPacket(stream) batch.decode() const packets = batch.getPackets() - console.log('Reading ', packets.length, 'packets') + this.inLog('Reading ', packets.length, 'packets') for (var packet of packets) { this.readPacket(packet) } diff --git a/src/server.js b/src/server.js index f94b573..0ad023a 100644 --- a/src/server.js +++ b/src/server.js @@ -9,11 +9,14 @@ const debug = require('debug')('minecraft-protocol') class Server extends EventEmitter { constructor(options) { super() - this.options = { ...Options.defaultOptions, options } + this.options = { ...Options.defaultOptions, ...options } this.serializer = createSerializer() this.deserializer = createDeserializer() this.clients = {} + this.clientCount = 0 this.validateOptions() + this.inLog = (...args) => console.debug('S', ...args) + this.outLog = (...args) => console.debug('S', ...args) } validateOptions() { @@ -26,13 +29,14 @@ class Server extends EventEmitter { debug('new connection', conn) const player = new Player(this, conn) this.clients[hash(conn.address)] = player - + this.clientCount++ this.emit('connect', { client: player }) } onCloseConnection = (inetAddr, reason) => { debug('close connection', inetAddr, reason) delete this.clients[hash(inetAddr)] + this.clientCount-- } onEncapsulated = (encapsulated, inetAddr) => { @@ -45,7 +49,7 @@ class Server extends EventEmitter { client.handle(buffer) } - async create(serverIp, port) { + async create(serverIp = this.options.hostname, port = this.options.port) { this.listener = new Listener(this) this.raknet = await this.listener.listen(serverIp, port) console.debug('Listening on', serverIp, port) diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 86d10bc..20c66ee 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -11,15 +11,20 @@ const ClientStatus = { } class Player extends Connection { - constructor(server, connection, options) { + constructor(server, connection) { super() this.server = server this.serializer = server.serializer + this.deserializer = server.deserializer + // console.log('serializer/des',this.serializer,this.deserializer) this.connection = connection - Encrypt(this, server, options) + this.options = server.options + Encrypt(this, server, this.options) this.startQueue() this.status = ClientStatus.Authenticating + this.inLog = (...args) => console.info('S ->', ...args) + this.outLog = (...args) => console.info('S <-', ...args) } getData() { @@ -103,7 +108,7 @@ class Player extends Connection { throw e } - console.log('->', des) + console.log('-> S', des) switch (des.data.name) { case 'login': console.log(des) diff --git a/src/serverTest.js b/src/serverTest.js index ed6883a..975e00e 100644 --- a/src/serverTest.js +++ b/src/serverTest.js @@ -1,4 +1,4 @@ -// process.env.DEBUG = 'minecraft-protocol raknet' +process.env.DEBUG = 'minecraft-protocol raknet' const { Server } = require('./server') const CreativeItems = require('../data/creativeitems.json') const NBT = require('prismarine-nbt') From 86dcbc1f493acdb67e9316215a4445bbb130532f Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 8 Mar 2021 02:36:25 -0500 Subject: [PATCH 111/458] use raknet-native with js fallback --- package.json | 1 + {src => samples}/clientTest.js | 4 +- {src => samples}/serverTest.js | 34 +++--- src/client.js | 54 ++------- src/connection.js | 22 ++-- src/datatypes/promises.js | 12 ++ src/index.js | 7 -- src/rak.js | 179 ++++++++++++++++++++++++++++ src/{ConnWorker.js => rakWorker.js} | 1 - src/server.js | 37 +++--- src/texture | Bin 16384 -> 0 bytes src/transforms/encryption.js | 49 +++----- 12 files changed, 262 insertions(+), 138 deletions(-) rename {src => samples}/clientTest.js (95%) rename {src => samples}/serverTest.js (71%) create mode 100644 src/datatypes/promises.js delete mode 100644 src/index.js create mode 100644 src/rak.js rename src/{ConnWorker.js => rakWorker.js} (98%) delete mode 100644 src/texture diff --git a/package.json b/package.json index 6f9b891..b5647f9 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "minecraft-folder-path": "^1.1.0", "prismarine-nbt": "github:extremeheat/prismarine-nbt#le", "protodef": "github:extremeheat/node-protodef#compiler", + "raknet-native": "^0.0.4", "uuid-1345": "^0.99.7" }, "devDependencies": { diff --git a/src/clientTest.js b/samples/clientTest.js similarity index 95% rename from src/clientTest.js rename to samples/clientTest.js index 4e0e620..11b9b3a 100644 --- a/src/clientTest.js +++ b/samples/clientTest.js @@ -1,12 +1,12 @@ process.env.DEBUG = 'minecraft-protocol raknet' -const { Client } = require('./client') +const { Client } = require('../src/client') const fs = require('fs') // console.log = () => async function test() { const client = new Client({ hostname: '127.0.0.1', - port: 19130 + port: 19132 }) client.once('resource_packs_info', (packet) => { diff --git a/src/serverTest.js b/samples/serverTest.js similarity index 71% rename from src/serverTest.js rename to samples/serverTest.js index 975e00e..ac50b53 100644 --- a/src/serverTest.js +++ b/samples/serverTest.js @@ -1,5 +1,5 @@ process.env.DEBUG = 'minecraft-protocol raknet' -const { Server } = require('./server') +const { Server } = require('../src/server') const CreativeItems = require('../data/creativeitems.json') const NBT = require('prismarine-nbt') const fs = require('fs') @@ -50,35 +50,35 @@ server.on('connect', ({ client }) => { client.queue('inventory_slot', {"inventory_id":120,"slot":i,"uniqueid":0,"item":{"network_id":0}}) } - client.queue('inventory_transaction', require('./packets/inventory_transaction.json')) - client.queue('player_list', require('./packets/player_list.json')) - client.queue('start_game', require('./packets/start_game.json')) + client.queue('inventory_transaction', require('../src/packets/inventory_transaction.json')) + client.queue('player_list', require('../src/packets/player_list.json')) + client.queue('start_game', require('../src/packets/start_game.json')) client.queue('item_component', {"entries":[]}) - client.queue('set_spawn_position', require('./packets/set_spawn_position.json')) + client.queue('set_spawn_position', require('../src/packets/set_spawn_position.json')) client.queue('set_time', { time: 5433771 }) client.queue('set_difficulty', { difficulty: 1 }) client.queue('set_commands_enabled', { enabled: true }) - client.queue('adventure_settings', require('./packets/adventure_settings.json')) + client.queue('adventure_settings', require('../src/packets/adventure_settings.json')) - client.queue('biome_definition_list', require('./packets/biome_definition_list.json')) - client.queue('available_entity_identifiers', require('./packets/available_entity_identifiers.json')) + client.queue('biome_definition_list', require('../src/packets/biome_definition_list.json')) + client.queue('available_entity_identifiers', require('../src/packets/available_entity_identifiers.json')) - client.queue('update_attributes', require('./packets/update_attributes.json')) - client.queue('creative_content', require('./packets/creative_content.json')) - client.queue('inventory_content', require('./packets/inventory_content.json')) + client.queue('update_attributes', require('../src/packets/update_attributes.json')) + client.queue('creative_content', require('../src/packets/creative_content.json')) + client.queue('inventory_content', require('../src/packets/inventory_content.json')) client.queue('player_hotbar', {"selected_slot":3,"window_id":0,"select_slot":true}) - client.queue('crafting_data', require('./packets/crafting_data.json')) - client.queue('available_commands', require('./packets/available_commands.json')) + client.queue('crafting_data', require('../src/packets/crafting_data.json')) + client.queue('available_commands', require('../src/packets/available_commands.json')) client.queue('chunk_radius_update', {"chunk_radius":5}) - client.queue('set_entity_data', require('./packets/set_entity_data.json')) + client.queue('set_entity_data', require('../src/packets/set_entity_data.json')) - client.queue('game_rules_changed', require('./packets/game_rules_changed.json')) + client.queue('game_rules_changed', require('../src/packets/game_rules_changed.json')) client.queue('respawn', {"x":646.9405517578125,"y":65.62001037597656,"z":77.86255645751953,"state":0,"runtime_entity_id":0}) - for (const file of fs.readdirSync('chunks')) { - const buffer = Buffer.from(fs.readFileSync('./chunks/' + file, 'utf8'), 'hex') + for (const file of fs.readdirSync('../src/chunks')) { + const buffer = Buffer.from(fs.readFileSync('../src/chunks/' + file, 'utf8'), 'hex') // console.log('Sending chunk', chunk) client.sendBuffer(buffer) } diff --git a/src/client.js b/src/client.js index 6ed2816..24d0b96 100644 --- a/src/client.js +++ b/src/client.js @@ -1,20 +1,14 @@ -const RakClient = require('jsp-raknet/client') +const fs = require('fs') +const debug = require('debug')('minecraft-protocol') const { Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') -const ConnWorker = require('./ConnWorker') const { Encrypt } = require('./auth/encryption') const auth = require('./client/auth') const Options = require('./options') -const debug = require('debug')('minecraft-protocol') -const fs = require('fs') - -const useWorkers = true +const { RakClient } = require('./Rak') class Client extends Connection { - /** - * - * @param {{ version: number, hostname: string, port: number }} options - */ + /** @param {{ version: number, hostname: string, port: number }} options */ constructor(options) { super() this.options = { ...Options.defaultOptions, ...options } @@ -54,41 +48,11 @@ class Client extends Connection { connect = async (sessionData) => { const hostname = this.options.hostname || '127.0.0.1' const port = this.options.port || 19132 - if (useWorkers) { - this.worker = ConnWorker.connect(hostname, port) - this.worker.on('message', (evt) => { - switch (evt.type) { - case 'connected': - this.sendLogin() - break - case 'encapsulated': - this.onEncapsulated(...evt.args) - break - } - }) - - } else { - if (this.raknet) return - - this.raknet = new RakClient('127.0.0.1', 19132) - await this.raknet.connect() - - this.raknet.on('connecting', () => { - // console.log(`[client] connecting to ${hostname}/${port}`) - }) - this.raknet.on('connected', (connection) => { - console.log(`[client] connected!`) - this.connection = connection - this.sendLogin() - }) - - this.raknet.on('encapsulated', this.onEncapsulated) - - this.raknet.on('raw', (buffer, inetAddr) => { - console.log('Raw packet', buffer, inetAddr) - }) - } + this.connection = new RakClient({ useWorkers: true, hostname, port }) + this.connection.onConnected = () => this.sendLogin() + this.connection.onEncapsulated = this.onEncapsulated + this.connection.connect() } sendLogin() { @@ -100,7 +64,7 @@ class Client extends Connection { ] const encodedChain = JSON.stringify({ chain }) - const skinChain = JSON.stringify({}) + // const skinChain = JSON.stringify({}) const bodyLength = this.clientUserChain.length + encodedChain.length + 8 diff --git a/src/connection.js b/src/connection.js index 3795b0e..8cd8dad 100644 --- a/src/connection.js +++ b/src/connection.js @@ -2,7 +2,6 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') -const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') const Reliability = require('jsp-raknet/protocol/reliability') const debug = require('debug')('minecraft-protocol') @@ -112,16 +111,17 @@ class Connection extends EventEmitter { // TODO: Rename this to sendEncapsulated sendMCPE(buffer, immediate) { - if (this.worker) { - this.outLog('-> buf', buffer) - this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) - } else { - const sendPacket = new EncapsulatedPacket() - sendPacket.reliability = Reliability.ReliableOrdered - sendPacket.buffer = buffer - this.connection.addEncapsulatedToQueue(sendPacket) - if (immediate) this.connection.sendQueue() - } + this.connection.sendReliable(buffer, immediate) + // if (this.worker) { + // this.outLog('-> buf', buffer) + // this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) + // } else { + // const sendPacket = new EncapsulatedPacket() + // sendPacket.reliability = Reliability.ReliableOrdered + // sendPacket.buffer = buffer + // this.connection.addEncapsulatedToQueue(sendPacket) + // if (immediate) this.connection.sendQueue() + // } } // These are callbacks called from encryption.js diff --git a/src/datatypes/promises.js b/src/datatypes/promises.js new file mode 100644 index 0000000..c3763e1 --- /dev/null +++ b/src/datatypes/promises.js @@ -0,0 +1,12 @@ +module.exports = { + sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + }, + + waitFor(cb, withTimeout) { + return Promise.race([ + new Promise((res, rej) => cb(res)), + sleep(withTimeout) + ]) + } +} \ No newline at end of file diff --git a/src/index.js b/src/index.js deleted file mode 100644 index b02489a..0000000 --- a/src/index.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - createSerializer: require("./transforms/serializer").createSerializer, - createDeserializer: require("./transforms/serializer").createDeserializer, - createProtocol: require('./transforms/serializer').createProtocol, - createServer: require("./createServer"), - createClient: require("./createClient") -}; diff --git a/src/rak.js b/src/rak.js new file mode 100644 index 0000000..c9a60a6 --- /dev/null +++ b/src/rak.js @@ -0,0 +1,179 @@ +const { EventEmitter } = require('events') +const Listener = require('jsp-raknet/listener') +const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') +const RakClient = require('jsp-raknet/client') +const ConnWorker = require('./rakWorker') +try { + var { Client, Server, PacketPriority, PacketReliability, McPingMessage } = require('raknet-native') +} catch (e) { + console.debug('[raknet] native not found, using js', e) +} + +class RakNativeClient extends EventEmitter { + constructor(options) { + super() + this.onConnected = () => {} + this.onCloseConnection = () => {} + this.onEncapsulated = () => {} + + this.raknet = new Client(options.hostname, options.port, 'minecraft') + this.raknet.on('encapsulated', thingy => { + console.log('Encap',thingy) + const { buffer, address, guid }=thingy + this.onEncapsulated(buffer, address) + }) + this.raknet.on('connected', () => { + this.onConnected() + }) + } + + async ping() { + this.raknet.ping() + return waitFor((done) => { + this.raknet.on('pong', (ret) => { + if (ret.extra) { + done(ret.extra.toString()) + } + }) + }, 1000) + } + + connect() { + this.raknet.connect() + } + + sendReliable(buffer, immediate) { + const priority = immediate ? PacketPriority.IMMEDIATE_PRIORITY : PacketPriority.MEDIUM_PRIORITY + return this.raknet.send(buffer, priority, PacketReliability.RELIABLE_ORDERED, 0) + } +} + +class RakNativeServer extends EventEmitter { + constructor(options = {}) { + super() + console.log('opts',options) + this.onOpenConnection = () => {} + this.onCloseConnection = () => {} + this.onEncapsulated = () => {} + this.raknet = new Server(options.hostname, options.port, { + maxConnections: options.maxConnections || 3, + minecraft: { message: new McPingMessage().toString() } + }) + + this.raknet.on('openConnection', (client) => { + client.sendReliable = function(buffer, immediate) { + const priority = immediate ? PacketPriority.IMMEDIATE_PRIORITY : PacketPriority.MEDIUM_PRIORITY + return this.send(buffer, priority, PacketReliability.RELIABLE_ORDERED, 0) + } + this.onOpenConnection(client) + }) + + this.raknet.on('closeConnection', (client) => { + console.log('!!! Client CLOSED CONNECTION!') + this.onCloseConnection(client) + }) + + this.raknet.on('encapsulated', (thingy) => { + const { buffer, address, guid }=thingy + console.log('ENCAP',thingy) + this.onEncapsulated(buffer, address) + }) + } + + listen() { + this.raknet.listen() + } +} + +class RakJsClient extends EventEmitter { + constructor(options = {}) { + super() + this.onConnected = () => {} + this.onEncapsulated = () => {} + if (options.useWorkers) { + this.connect = this.workerConnect + this.sendReliable = this.workerSendReliable + } else { + this.connect = this.plainConnect + this.sendReliable = this.plainSendReliable + } + } + + workerConnect(hostname = this.options.hostname, port = this.options.port) { + this.worker = ConnWorker.connect(hostname, port) + + this.worker.on('message', (evt) => { + switch (evt.type) { + case 'connected': + this.onConnected() + break + case 'encapsulated': + const [ecapsulated, address] = evt.args + this.onEncapsulated(ecapsulated.buffer, address.hash) + break + } + }) + } + + async plainConnect(hostname = this.options.hostname, port = this.options.port) { + this.raknet = new RakClient(hostname, port) + await this.raknet.connect() + + this.raknet.on('connecting', () => { + console.log(`[client] connecting to ${hostname}/${port}`) + }) + + this.raknet.on('connected', this.onConnected) + this.raknet.on('encapsulated', (encapsulated, addr) => this.onEncapsulated(encapsulated.buffer, addr.hash)) + } + + workerSendReliable(buffer, immediate) { + this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) + } + + plainSendReliable(buffer, immediate) { + const sendPacket = new EncapsulatedPacket() + sendPacket.reliability = Reliability.ReliableOrdered + sendPacket.buffer = buffer + this.connection.addEncapsulatedToQueue(sendPacket) + if (immediate) this.connection.sendQueue() + } +} + +class RakJsServer extends EventEmitter { + constructor(options = {}) { + super() + this.options = options + this.onOpenConnection = () => {} + this.onCloseConnection = () => {} + this.onEncapsulated = () => {} + + if (options.useWorkers) { + throw Error('nyi') + } else { + this.listen = this.plainListen + } + } + + async plainListen() { + this.raknet = new Listener() + await this.raknet.listen(this.options.hostname, this.options.port) + this.raknet.on('openConnection', (conn) => { + conn.sendReliable = function(buffer, immediate) { + const sendPacket = new EncapsulatedPacket() + sendPacket.reliability = Reliability.ReliableOrdered + sendPacket.buffer = buffer + this.connection.addEncapsulatedToQueue(sendPacket) + if (immediate) this.raknet.sendQueue() + } + this.onOpenConnection(conn) + }) + this.raknet.on('closeConnection', this.onCloseConnection) + this.raknet.on('encapsulated', this.onEncapsulated) + } +} + +module.exports = { + RakClient: Client ? RakNativeClient : RakJsClient, + RakServer: Server ? RakNativeServer : RakJsServer +} \ No newline at end of file diff --git a/src/ConnWorker.js b/src/rakWorker.js similarity index 98% rename from src/ConnWorker.js rename to src/rakWorker.js index e43aea5..3dc837a 100644 --- a/src/ConnWorker.js +++ b/src/rakWorker.js @@ -16,7 +16,6 @@ var raknet function main() { parentPort.on('message', (evt) => { if (evt.type == 'connect') { - console.warn('-------- ', evt) const { hostname, port } =evt raknet = new RakClient(hostname, port) diff --git a/src/server.js b/src/server.js index 0ad023a..2e3a924 100644 --- a/src/server.js +++ b/src/server.js @@ -1,8 +1,7 @@ -const Listener = require('jsp-raknet/listener') const { EventEmitter } = require('events') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { Player } = require('./serverPlayer') - +const { RakServer } = require('./rak') const Options = require('./options') const debug = require('debug')('minecraft-protocol') @@ -26,41 +25,35 @@ class Server extends EventEmitter { } onOpenConnection = (conn) => { - debug('new connection', conn) + this.inLog('new connection', conn) const player = new Player(this, conn) - this.clients[hash(conn.address)] = player + this.clients[conn.address] = player this.clientCount++ this.emit('connect', { client: player }) } onCloseConnection = (inetAddr, reason) => { debug('close connection', inetAddr, reason) - delete this.clients[hash(inetAddr)] + delete this.clients[inetAddr] this.clientCount-- } - onEncapsulated = (encapsulated, inetAddr) => { - debug(inetAddr.address, 'Encapsulated', encapsulated) - const buffer = encapsulated.buffer - const client = this.clients[hash(inetAddr)] + onEncapsulated = (buffer, address) => { + debug(address, 'Encapsulated', buffer) + const client = this.clients[address] if (!client) { - throw new Error(`packet from unknown inet addr: ${inetAddr.address}/${inetAddr.port}`) + throw new Error(`packet from unknown inet addr: ${address}`) } client.handle(buffer) } - async create(serverIp = this.options.hostname, port = this.options.port) { - this.listener = new Listener(this) - this.raknet = await this.listener.listen(serverIp, port) - console.debug('Listening on', serverIp, port) - - this.raknet.on('openConnection', this.onOpenConnection) - this.raknet.on('closeConnection', this.onCloseConnection) - this.raknet.on('encapsulated', this.onEncapsulated) - - this.raknet.on('raw', (buffer, inetAddr) => { - debug('Raw packet', buffer, inetAddr) - }) + async create(hostname = this.options.hostname, port = this.options.port) { + this.raknet = new RakServer({ hostname, port }) + await this.raknet.listen() + console.debug('Listening on', hostname, port) + this.raknet.onOpenConnection = this.onOpenConnection + this.raknet.onCloseConnection = this.onCloseConnection + this.raknet.onEncapsulated = this.onEncapsulated } } diff --git a/src/texture b/src/texture deleted file mode 100644 index 83c6355c885f2aee7dc4b597942800afa91a8e45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeI2-)~e!6vy{bTR=)QHvA}POI-_Qso(=8TBP#J7>y8(QiBAHAf+K`P!ov(l?c^D zeIkKWOiWCO(eR+?gTY6i`ad1#Gu`j?FzoJK=&rkIZR$VBf2E-{p1u2{;;n3a#4ugMkHLR>_cr_T@Q%#WmM+~-*m#BT zihX!(PhI}O!9nweCTP%j_U?~TV_$dlkS2K5-?P(RD*T?6`eWJ;%Y`4#lwEtGUi}Z1 zhnK|u7dyO9uU`>$;JKgjv)@x&3im(!;?^F((~rT}$h!RrS6y50>4z9Lm zHZ53X(@NViu<#jBUf&x(^T?$Se&sO+otT5T=9Nx7M}3=X_ED$x(K=Z(wsl}tzU9#XTN-O#CB|66LZLA3}dr_sqLD)`W0;FJbCtuKT&wot z#!C}?r|YkMiXUFP!Ui9I*e<^{W^*U@+F1F~$Zp~1(DSo)`~1nsPMaUJA%|SXFqS#| zoSs$phW0~O@rQa1$35F;mky2E)puXCD@S$)wte>7`Q!HI=QG*o+uv8t*pH|8+r{ub zpB!=-vvr^^&Y{|)1B_V8u4h4~>(72=o$T4;6BYaZ^lNtg#7pt-89vv(J30~gcH75$ zp1aGwJ^F%uc6ev}?Bnkp#xRyS;{FeFGPl^_)w98Wf9NznYuEbmb0-hPdVclxE<1Oi zVrTbmwdskG$O`W#uWq+5-q;n5HaX<}aOz+jd;Pta7kpJi=0r!;U!Fcc#J3@xPxnvOe~M*2}s)4{g8Jw9UAb&(B4E8c*kFH$Qt`Otk&)7r*bTmyb^5!ROm4 zA9HHH|Ed0d4{*lSzhcUDdU&>!A02A($Ns8D&D0-8nP;P&%b(t#ti2Jx&li8HRUQ6x zf2aJ?$M1nw@Jkzfs!zk`udlxtJwI(}RmZFT@}5onxQ~;>)RcM4 z_+i0RJJ0U-b;|Gar4fC!!#K~D)*metmydnby^lV5^%s}CXQQot`819`dN$%y{kY~? znLQ5zKY1FXc+AmrAn{Y$QQW0UTMB^G{*Bw2XV)}A2blR z;`hs+w?B$_p+KQPp+KQPp+KQPp+KQPp+KQPp+KQPp+KQPp+Ks@qR&rx2c+}u&|d8M zX1cz1UoV

{Y+)_q}c)@~V55m)swD>uYyhT=FTO`sLHO=Tm+CJ>cU}gC)qX+Qxkz_{1NdbGk3&Tg?A2 DCE}OY diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 670d8a9..36f7c18 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -72,43 +72,24 @@ function createEncryptor(client, iv) { // A packet is encrypted via AES256(plaintext + SHA256(send_counter + plaintext + secret_key)[0:8]). // The send counter is represented as a little-endian 64-bit long and incremented after each packet. - const addChecksum = new Transform({ // append checksum - transform(chunk, enc, cb) { - // console.log('Encryptor: checking checksum', chunk) - // Here we concat the payload + checksum before the encryption - const packet = Buffer.concat([chunk, computeCheckSum(chunk, client.sendCounter, client.secretKeyBytes)]) - client.sendCounter++ - this.push(packet) - cb() - } - }) + function process(chunk) { + const buffer = Zlib.deflateRawSync(chunk, { level: 7 }) + // client.outLog('🟡 Compressed', buffer, client.sendCounter) + const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) + client.sendCounter++ + // client.outLog('writing to cipher...', packet, client.secretKeyBytes, iv) + client.cipher.write(packet) + } - // https://stackoverflow.com/q/25971715/11173996 - // TODO: Fix deflate stream - for some reason using .pipe() doesn't work using zlib.createDeflateRaw() - // so we define our own compressor transform - // const compressor = Zlib.createDeflateRaw({ level: 7, chunkSize: 1024 * 1024 * 2, flush: Zlib.Z_SYNC_FLUSH }) - const compressor = new Transform({ - transform(chunk, enc, cb) { - Zlib.deflateRaw(chunk, { level: 7 }, (err, res) => { - if (err) { - console.error(err) - throw new Error(`Failed to deflate stream`) - } - this.push(res) - cb() - }) - } - }) + // const stream = new PassThrough() + client.cipher.on('data', client.onEncryptedPacket) - const stream = new PassThrough() - - stream - .pipe(compressor) - .pipe(addChecksum).pipe(client.cipher).on('data', client.onEncryptedPacket) return (blob) => { - stream.write(blob) + client.outLog(client.options ? 'C':'S', '🟡 Encrypting', blob) + // stream.write(blob) + process(blob) } } @@ -119,7 +100,7 @@ function createDecryptor(client, iv) { function verify(chunk) { // console.log('Decryptor: checking checksum', client.receiveCounter, chunk) - + // client.outLog('🔵 Inflating', chunk) // First try to zlib decompress, then see how much bytes get read const { buffer, engine } = Zlib.inflateRawSync(chunk, { chunkSize: 1024 * 1024 * 2, @@ -158,6 +139,8 @@ function createDecryptor(client, iv) { client.decipher.on('data', verify) return (blob) => { + // client.inLog(client.options ? 'C':'S', ' 🔵 Decrypting', client.receiveCounter, blob) + // client.inLog('Using shared key', client.secretKeyBytes, iv) client.decipher.write(blob) } } From 9e1500ec775501f824098cc4ec46dd19c8dfaee2 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 9 Mar 2021 02:13:47 -0500 Subject: [PATCH 112/458] add new packets and working proxy --- data/new/packet_map.yml | 10 ++ data/new/proto.yml | 82 ++++++++++++++ data/newproto.json | 115 ++++++++++++++++++++ src/client.js | 4 +- src/connection.js | 20 +++- src/rak.js | 3 +- src/relay.js | 202 +++++++++++++++++++++++++++++++++++ src/serverPlayer.js | 1 + src/transforms/encryption.js | 2 +- 9 files changed, 430 insertions(+), 9 deletions(-) create mode 100644 src/relay.js diff --git a/data/new/packet_map.yml b/data/new/packet_map.yml index 45d1f33..3734525 100644 --- a/data/new/packet_map.yml +++ b/data/new/packet_map.yml @@ -150,6 +150,11 @@ mcpe_packet: 0x9a: position_tracking_db_request 0x99: position_tracking_db_broadcast 0x9c: packet_violation_warning + 0x9d: motion_prediction_hints + 0x9e: animate_entity + 0x9f: camera_shake + 0xa0: player_fog + 0xa1: correct_player_move_prediction 0xa2: item_component 0xa3: filter_text_packet @@ -303,5 +308,10 @@ mcpe_packet: if position_tracking_db_request: packet_position_tracking_db_request if position_tracking_db_broadcast: packet_position_tracking_db_broadcast if packet_violation_warning: packet_packet_violation_warning + if motion_prediction_hints: packet_motion_prediction_hints + if animate_entity: packet_animate_entity + if camera_shake: packet_camera_shake + if player_fog: packet_player_fog + if correct_player_move_prediction: packet_correct_player_move_prediction if item_component: packet_item_component if filter_text_packet: packet_filter_text_packet diff --git a/data/new/proto.yml b/data/new/proto.yml index c2c5c1f..0965d3d 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -2204,6 +2204,87 @@ packet_packet_violation_warning: # ViolationContext holds a description on the violation of the packet. reason: string + +# MotionPredictionHints is sent by the server to the client. There is a predictive movement component for +# entities. This packet fills the "history" of that component and entity movement is computed based on the +# points. Vanilla sends this packet instead of the SetActorMotion packet when 'spatial optimisations' are +# enabled. +packet_motion_prediction_hints: + !id: 0x9d + !bound: client + # EntityRuntimeID is the runtime ID of the entity whose velocity is sent to the client. + entity_runtime_id: varint64 + # Velocity is the server-calculated velocity of the entity at the point of sending the packet. + velocity: vec3f + # OnGround specifies if the server currently thinks the entity is on the ground. + on_ground: bool + + +# AnimateEntity is sent by the server to animate an entity client-side. It may be used to play a single +# animation, or to activate a controller which can start a sequence of animations based on different +# conditions specified in an animation controller. +# Much of the documentation of this packet can be found at +# https://minecraft.gamepedia.com/Bedrock_Edition_beta_animation_documentation. +packet_animate_entity: + !id: 0x9e + !bound: client + # Animation is the name of a single animation to start playing. + animation: string + # NextState is the first state to start with. These states are declared in animation controllers (which, + # in themselves, are animations too). These states in turn may have animations and transitions to move to + # a next state. + next_state: string + # StopCondition is a MoLang expression that specifies when the animation should be stopped. + stop_condition: string + # Controller is the animation controller that is used to manage animations. These controllers decide when + # to play which animation. + controller: string + # BlendOutTime does not currently seem to be used. + blend_out_time: lf32 + # EntityRuntimeIDs is list of runtime IDs of entities that the animation should be applied to. + runtime_entity_ids: varint64[]varint + +# CameraShake is sent by the server to make the camera shake client-side. This feature was added for map- +# making partners. +packet_camera_shake: + !id: 0x9f + !bound: client + # Intensity is the intensity of the shaking. The client limits this value to 4, so anything higher may + # not work. + intensity: lf32 + # Duration is the number of seconds the camera will shake for. + duration: lf32 + # Type is the type of shake, and is one of the constants listed above. The different type affects how + # the shake looks in game. + type: u8 + +# PlayerFog is sent by the server to render the different fogs in the Stack. The types of fog are controlled +# by resource packs to change how they are rendered, and the ability to create custom fog. +packet_player_fog: + !id: 0xa0 + !bound: client + # Stack is a list of fog identifiers to be sent to the client. Examples of fog identifiers are + # "minecraft:fog_ocean" and "minecraft:fog_hell". + stack: string[]varint + + +# CorrectPlayerMovePrediction is sent by the server if and only if StartGame.ServerAuthoritativeMovementMode +# is set to AuthoritativeMovementModeServerWithRewind. The packet is used to correct movement at a specific +# point in time. +packet_correct_player_move_prediction: + !id: 0xa1 + !bound: client + # Position is the position that the player is supposed to be at at the tick written in the field below. + # The client will change its current position based on movement after that tick starting from the + # Position. + position: vec3f + # Delta is the change in position compared to what the client sent as its position at that specific tick. + delta: vec3f + # OnGround specifies if the player was on the ground at the time of the tick below. + on_ground: bool + # Tick is the tick of the movement which was corrected by this packet. + tick: varint64 + # ItemComponent is sent by the server to attach client-side components to a custom item. packet_item_component: !id: 0xa2 @@ -2221,3 +2302,4 @@ packet_filter_text_packet: text: string # FromServer indicates if the packet was sent by the server or not. from_server: bool + diff --git a/data/newproto.json b/data/newproto.json index 38f4bfd..bbce33d 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -2694,6 +2694,11 @@ "153": "position_tracking_db_broadcast", "154": "position_tracking_db_request", "156": "packet_violation_warning", + "157": "motion_prediction_hints", + "158": "animate_entity", + "159": "camera_shake", + "160": "player_fog", + "161": "correct_player_move_prediction", "162": "item_component", "163": "filter_text_packet" } @@ -2856,6 +2861,11 @@ "position_tracking_db_request": "packet_position_tracking_db_request", "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", "packet_violation_warning": "packet_packet_violation_warning", + "motion_prediction_hints": "packet_motion_prediction_hints", + "animate_entity": "packet_animate_entity", + "camera_shake": "packet_camera_shake", + "player_fog": "packet_player_fog", + "correct_player_move_prediction": "packet_correct_player_move_prediction", "item_component": "packet_item_component", "filter_text_packet": "packet_filter_text_packet" }, @@ -6743,6 +6753,111 @@ } ] ], + "packet_motion_prediction_hints": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + } + ] + ], + "packet_animate_entity": [ + "container", + [ + { + "name": "animation", + "type": "string" + }, + { + "name": "next_state", + "type": "string" + }, + { + "name": "stop_condition", + "type": "string" + }, + { + "name": "controller", + "type": "string" + }, + { + "name": "blend_out_time", + "type": "lf32" + }, + { + "name": "runtime_entity_ids", + "type": [ + "array", + { + "countType": "varint", + "type": "varint64" + } + ] + } + ] + ], + "packet_camera_shake": [ + "container", + [ + { + "name": "intensity", + "type": "lf32" + }, + { + "name": "duration", + "type": "lf32" + }, + { + "name": "type", + "type": "u8" + } + ] + ], + "packet_player_fog": [ + "container", + [ + { + "name": "stack", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "packet_correct_player_move_prediction": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], "packet_item_component": [ "container", [ diff --git a/src/client.js b/src/client.js index 24d0b96..9419202 100644 --- a/src/client.js +++ b/src/client.js @@ -112,7 +112,7 @@ class Client extends Connection { // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } - this.inLog('-> C', pakData.name, serialize(pakData.params).slice(0, 100)) + this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100)*/) // No idea what this exotic 0xA0 packet is, it's not implemented anywhere // and seems empty. Possible gibberish from the raknet impl @@ -149,7 +149,7 @@ class Client extends Connection { fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) break case 'level_chunk': - fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) + // fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) break default: // console.log('Sending to listeners') diff --git a/src/connection.js b/src/connection.js index 8cd8dad..e621446 100644 --- a/src/connection.js +++ b/src/connection.js @@ -19,7 +19,7 @@ class Connection extends EventEmitter { // console.log('Need to encode', name, params) var s = this.connect ? 'C' : 'S' if (this.downQ) s += 'P' - this.outLog('<- ' + s, name) + this.outLog('NB <- ' + s, name,params) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) // console.log('Sending buf', packet.toString('hex').) @@ -33,8 +33,13 @@ class Connection extends EventEmitter { } queue(name, params) { - this.outLog('Q <- ', name) + this.outLog('Q <- ', name, params) const packet = this.serializer.createPacketBuffer({ name, params }) + if (name == 'level_chunk') { + // Skip queue + this.sendMCPE(packet) + return + } this.q.push(packet) this.q2.push(name) } @@ -48,16 +53,19 @@ class Connection extends EventEmitter { this.outLog('<- BATCH', this.q2) // For now, we're over conservative so send max 3 packets // per batch and hold the rest for the next tick - for (let i = 0; /*i < 10 &&*/ i < this.q.length; i++) { + const sending = [] + for (let i = 0; i < 3 && i < this.q.length; i++) { const packet = this.q.shift() + sending.push(this.q2.shift()) batch.addEncodedPacket(packet) } + // console.warn('~~ Sending', sending) if (this.encryptionEnabled) { this.sendEncryptedBatch(batch) } else { this.sendDecryptedBatch(batch) } - this.q2 = [] + // this.q2 = [] } }, 100) } @@ -162,5 +170,7 @@ class Connection extends EventEmitter { // console.log('[client] handled incoming ', buffer) } } - +function serialize(obj = {}, fmt) { + return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) +} module.exports = { Connection } \ No newline at end of file diff --git a/src/rak.js b/src/rak.js index c9a60a6..5a16182 100644 --- a/src/rak.js +++ b/src/rak.js @@ -57,7 +57,8 @@ class RakNativeServer extends EventEmitter { this.onEncapsulated = () => {} this.raknet = new Server(options.hostname, options.port, { maxConnections: options.maxConnections || 3, - minecraft: { message: new McPingMessage().toString() } + minecraft: { }, + message: new McPingMessage().toBuffer() }) this.raknet.on('openConnection', (client) => { diff --git a/src/relay.js b/src/relay.js new file mode 100644 index 0000000..6fdc890 --- /dev/null +++ b/src/relay.js @@ -0,0 +1,202 @@ +process.env.DEBUG = 'minecraft-protocol raknet' +const { Client } = require("./client") +const { Server } = require("./server") +const { Player } = require("./serverPlayer") +const debug = require('debug')('minecraft-protocol relay') + +/** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ + +class RelayPlayer extends Player { + constructor(server, conn) { + super(server, conn) + this.server = server + this.conn = conn + + this.startRelaying = false + this.once('join', () => { + this.write('client_cache_status', {enabled:false}) // disable this asap on join + + this.flushDownQueue() + this.startRelaying = true + }) + this.downQ = [] + this.upQ = [] + this.upInLog = (...msg) => console.info('** Backend -> Proxy', ...msg) + this.upOutLog = (...msg) => console.info('** Proxy -> Backend', ...msg) + this.downInLog = (...msg) => console.info('** Client -> Proxy', ...msg) + this.downOutLog = (...msg) => console.info('** Proxy -> Client', ...msg) + + this.outLog = this.downOutLog + this.inLog = this.downInLog + } + + // Called when we get a packet from backend server (Backend -> PROXY -> Client) + readUpstream(packet) { + if (!this.startRelaying) { + console.warn('The downstream client is not ready yet !!') + this.downQ.push(packet) + return + } + this.upInLog('Recv packet', packet) + const des = this.server.deserializer.parsePacketBuffer(packet) + const name = des.data.name + const params = des.data.params + this.upInLog('~~ Bounce B->C', name, serialize(params).slice(0, 100)) + this.upInLog('~~ ', des.buffer) + if (name == 'play_status' && params.status == 'login_success') return + + if (name == 'level_chunk') { //send chunk directly + this.upInLog('Would send chunk', params) + this.sendBuffer(packet) + return + } else this.upInLog('?',name) + + // if (name == 'network_chunk_publisher_update') return + // if (name == 'crafting_data' || name == 'level_chunk') return // Alex breaks + this.queue(name, params) + // this.sendBuffer(packet) + } + + flushDownQueue() { + for (const packet of this.downQ) { + const des = this.server.deserializer.parsePacketBuffer(packet) + this.write(des.data.name, des.data.params) + } + this.downQ = [] + } + + flushUpQueue() { + for (var e of this.upQ) { // Send the queue + const des = this.server.deserializer.parsePacketBuffer(e) + if (des.data.name == 'client_cache_status') { // already disabled on join + // this.upstream.write('client_cache_status', {enabled:false}) + } else { + this.upstream.write(des.data.name, des.data.params) + } + } + this.upQ = [] + } + + // Called when the server gets a packet from the downstream player (Client -> PROXY -> Backend) + readPacket(packet) { + if (this.startRelaying) { // The DS client conn is established & we got a packet to send to US server + if (!this.upstream) { // Upstream is still connecting/handshaking + debug('Got downstream connected packet but upstream is not connected yet, added to q', this.queue.length) + this.upQ.push(packet) // Put into a queue + return + } + this.flushUpQueue() // Send queued packets + this.downInLog('Recv packet', packet) + const des = this.server.deserializer.parsePacketBuffer(packet) + switch (des.data.name) { + case 'client_cache_status': + this.upstream.queue('client_cache_status', {enabled:false}) + break + // case 'request_chunk_radius': + // this.upstream.queue('request_chunk_radius', {chunk_radius: 1}) + // break + default: + // Emit the packet as-is back to the upstream server + this.upstream.queue(des.data.name, des.data.params) + } + } else { + super.readPacket(packet) + } + } +} + +class Relay extends Server { + /** + * Creates a new non-transparent proxy connection to a destination server + * @param {Options} options + */ + constructor(options) { + super(options) + this.RelayPlayer = options.relayPlayer || RelayPlayer + this.forceSingle = true + this.upstreams = new Map() + } + + openUpstreamConnection(ds, clientAddr) { + const client = new Client({ + hostname: this.options.destination.hostname, + port: this.options.destination.port, + encrypt: this.options.encrypt + }) + client.outLog = ds.upOutLog + client.inLog = ds.upInLog + // console.log('Set upstream logs', client.outLog, client.inLog) + client.once('join', () => { // Intercept once handshaking done + ds.upstream = client + ds.flushUpQueue() + console.log('UPSTREAM HAS JOINED') + client.readPacket = (packet) => ds.readUpstream(packet) + }) + this.upstreams.set(clientAddr.hash, client) + } + + closeUpstreamConnection(clientAddr) { + const up = this.upstreams.get(clientAddr.hash) + if (!up) throw Error(`unable to close non-existant connection ${clientAddr.hash}`) + up.close() + this.upstreams.delete(clientAddr.hash) + debug('relay closed connection', clientAddr) + } + + onOpenConnection = (conn) => { + debug('new connection', conn) + if (this.forceSingle && this.clientCount > 0) { + debug('dropping connection as single client relay', conn) + conn.close() + } else { + const player = new this.RelayPlayer(this, conn) + console.log('NEW CONNECTION', conn.address) + this.clients[conn.address] = player + this.emit('connect', { client: player }) + this.openUpstreamConnection(player, conn.address) + } + } +} +console.log = () => {} + + +function serialize(obj = {}, fmt) { + return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) +} + +function createRelay() { + console.log('Creating relay') + /** + * Example to create a non-transparent proxy (or 'Relay') connection to destination server + * In Relay we de-code and re-encode packets + */ + const relay = new Relay({ + /* Hostname and port for clients to listen to */ + hostname: '0.0.0.0', + port: 19130, + /** + * Who does the authentication + * If set to `client`, all connecting clients will be sent a message with a link to authenticate + * If set to `server`, the server will authenticate and only one client will be able to join + * (Default) If set to `none`, no authentication will be done + */ + auth: 'server', + + /** + * Sets if packets will automatically be forwarded. If set to false, you must listen for on('packet') + * events and + */ + auto: true, + + /* Where to send upstream packets to */ + destination: { + hostname: '127.0.0.1', + port: 19132, + encryption: true + } + }) + + relay.create() +} + +createRelay() \ No newline at end of file diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 20c66ee..8d05c6a 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -90,6 +90,7 @@ class Player extends Connection { // After sending Server to Client Handshake, this handles the client's // Client to Server handshake response. This indicates successful encryption onHandshake() { + // this.outLog('Sending login success!', this.status) // https://wiki.vg/Bedrock_Protocol#Play_Status this.write('play_status', { status: 'login_success' }) this.status = ClientStatus.Initializing diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 36f7c18..dee6469 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -87,7 +87,7 @@ function createEncryptor(client, iv) { return (blob) => { - client.outLog(client.options ? 'C':'S', '🟡 Encrypting', blob) + // client.outLog(client.options ? 'C':'S', '🟡 Encrypting', client.sendCounter, blob) // stream.write(blob) process(blob) } From 667030370e38ff42cfeb8af160ad60c3b7a33207 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 11 Mar 2021 06:05:04 -0500 Subject: [PATCH 113/458] varint64 impl, inventory and other packet fixes --- data/new/proto.yml | 120 +++++++++++-- data/new/types.yaml | 157 +++++++++++++---- data/newproto.json | 250 ++++++++++++++++++++++------ package.json | 4 +- src/connection.js | 13 +- src/datatypes/compiler-minecraft.js | 66 ++++++-- src/datatypes/varlong.js | 63 +++++++ src/rak.js | 4 +- src/relay.js | 84 ++++++---- test/serialization.js | 39 ++++- 10 files changed, 645 insertions(+), 155 deletions(-) create mode 100644 src/datatypes/varlong.js diff --git a/data/new/proto.yml b/data/new/proto.yml index 0965d3d..0a3bd85 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -1,9 +1,9 @@ # Created from MiNET docs string: ["pstring",{"countType":"varint"}] ByteArray: ["buffer",{"countType":"varint"}] +SignedByteArray: ["buffer",{"countType":"zigzag32"}] LittleString: ["pstring",{"countType":"li32"}] varint32: varint -varint64: varint bool: native zigzag32: native zigzag64: native @@ -166,6 +166,7 @@ packet_text: _: type? if chat or whisper or announcement: source_name: string + message: string if raw or tip or system or json_whisper or json: message: string if translation or popup or jukebox_popup: @@ -718,7 +719,7 @@ packet_mob_equipment: item: Item slot: u8 selected_slot: u8 - windows_id: u8 + windows_id: WindowID packet_mob_armor_equipment: !id: 0x20 @@ -865,46 +866,94 @@ packet_respawn: state: u8 runtime_entity_id: varint +# ContainerOpen is sent by the server to open a container client-side. This container must be physically +# present in the world, for the packet to have any effect. Unlike Java Edition, Bedrock Edition requires that +# chests for example must be present and in range to open its inventory. packet_container_open: !id: 0x2e !bound: client + # WindowID is the ID representing the window that is being opened. It may be used later to close the + # container using a ContainerClose packet. window_id: u8 - type: u8 + # ContainerType is the type ID of the container that is being opened when opening the container at the + # position of the packet. It depends on the block/entity, and could, for example, be the window type of + # a chest or a hopper, but also a horse inventory. + window_type: WindowType + # ContainerPosition is the position of the container opened. The position must point to a block entity + # that actually has a container. If that is not the case, the window will not be opened and the packet + # will be ignored, if a valid ContainerEntityUniqueID has not also been provided. coordinates: BlockCoordinates + # ContainerEntityUniqueID is the unique ID of the entity container that was opened. It is only used if + # the ContainerType is one that points to an entity, for example a horse. runtime_entity_id: zigzag64 +# ContainerClose is sent by the server to close a container the player currently has opened, which was opened +# using the ContainerOpen packet, or by the client to tell the server it closed a particular container, such +# as the crafting grid. packet_container_close: !id: 0x2f !bound: both + # WindowID is the ID representing the window of the container that should be closed. It must be equal to + # the one sent in the ContainerOpen packet to close the designated window. window_id: u8 + # ServerSide determines whether or not the container was force-closed by the server. If this value is + # not set correctly, the client may ignore the packet and respond with a PacketViolationWarning. server: bool +# PlayerHotBar is sent by the server to the client. It used to be used to link hot bar slots of the player to +# actual slots in the inventory, but as of 1.2, this was changed and hot bar slots are no longer a free +# floating part of the inventory. +# Since 1.2, the packet has been re-purposed, but its new functionality is not clear. packet_player_hotbar: !id: 0x30 !bound: both selected_slot: varint - window_id: u8 + window_id: WindowID select_slot: bool +# InventoryContent is sent by the server to update the full content of a particular inventory. It is usually +# sent for the main inventory of the player, but also works for other inventories that are currently opened +# by the player. packet_inventory_content: !id: 0x31 !bound: both + # WindowID is the ID that identifies one of the windows that the client currently has opened, or one of + # the consistent windows such as the main inventory. inventory_id: varint + # Content is the new content of the inventory. The length of this slice must be equal to the full size of + # the inventory window updated. input: ItemStacks +# InventorySlot is sent by the server to update a single slot in one of the inventory windows that the client +# currently has opened. Usually this is the main inventory, but it may also be the off hand or, for example, +# a chest inventory. packet_inventory_slot: !id: 0x32 !bound: both - inventory_id: varint + # WindowID is the ID of the window that the packet modifies. It must point to one of the windows that the + # client currently has opened. + window_id: varint + # Slot is the index of the slot that the packet modifies. The new item will be set to the slot at this + # index. slot: varint + # NewItem is the item to be put in the slot at Slot. It will overwrite any item that may currently + # be present in that slot. uniqueid: zigzag32 item: Item +# ContainerSetData is sent by the server to update specific data of a single container, meaning a block such +# as a furnace or a brewing stand. This data is usually used by the client to display certain features +# client-side. packet_container_set_data: !id: 0x33 !bound: client - window_id: u8 + # WindowID is the ID of the window that should have its data set. The player must have a window open with + # the window ID passed, or nothing will happen. + window_id: WindowID + # Key is the key of the property. It is one of the constants that can be found above. Multiple properties + # share the same key, but the functionality depends on the type of the container that the data is set to. property: zigzag32 + # Value is the value of the property. Its use differs per property. value: zigzag32 packet_crafting_data: @@ -915,20 +964,33 @@ packet_crafting_data: potion_container_recipes: PotionContainerChangeRecipes is_clean: bool +# CraftingEvent is sent by the client when it crafts a particular item. Note that this packet may be fully +# ignored, as the InventoryTransaction packet provides all the information required. packet_crafting_event: !id: 0x35 !bound: both - window_id: u8 - recipe_type: zigzag32 + # WindowID is the ID representing the window that the player crafted in. + window_id: WindowID + # CraftingType is a type that indicates the way the crafting was done, for example if a crafting table + # was used. + recipe_type: zigzag32 => + 0: inventory + 1: crafting + 2: workbench + # RecipeUUID is the UUID of the recipe that was crafted. It points to the UUID of the recipe that was + # sent earlier in the CraftingData packet. recipe_id: uuid - input: ItemStacks - result: ItemStacks + # Input is a list of items that the player put into the recipe so that it could create the Output items. + # These items are consumed in the process. + input: Item[]varint + # Output is a list of items that were obtained as a result of crafting the recipe. + result: Item[]varint + packet_gui_data_pick_item: !id: 0x36 !bound: client - # AdventureSettings is sent by the server to update game-play related features, in particular permissions to # access these features for the client. It includes allowing the player to fly, build and mine, and attack # entities. Most of these flags should be checked server-side instead of using this packet only. @@ -1085,7 +1147,7 @@ packet_event: !id: 0x41 !bound: client runtime_id: varint64 - event_type: varint => + event_type: zigzag32 => 0: achievement_awarded 1: entity_interact 2: portal_built @@ -1105,6 +1167,7 @@ packet_event: 16: composter_block_used 17: bell_block_used use_player_id: u8 + event_data: restBuffer # Unknown data, TODO: add packet_spawn_experience_orb: !id: 0x42 @@ -1821,13 +1884,36 @@ packet_level_sound_event: is_baby_mob: bool is_global: bool +# LevelEventGeneric is sent by the server to send a 'generic' level event to the client. This packet sends an +# NBT serialised object and may for that reason be used for any event holding additional data. packet_level_event_generic: !id: 0x7c !bound: client + # EventID is a unique identifier that identifies the event called. The data that follows has fields in + # the NBT depending on what event it is. + event_id: varint + # SerialisedEventData is a network little endian serialised object of event data, with fields that vary + # depending on EventID. + # Unlike many other NBT structures, this data is not actually in a compound but just loosely floating + # NBT tags. To decode using the nbt package, you would need to append 0x0a00 at the start (compound id + # and name length) and add 0x00 at the end, to manually wrap it in a compound. Likewise, you would have + # to remove these bytes when encoding. + nbt: nbtLoop +# LecternUpdate is sent by the client to update the server on which page was opened in a book on a lectern, +# or if the book should be removed from it. packet_lectern_update: !id: 0x7d !bound: client + # Page is the page number in the book that was opened by the player on the lectern. + page: u8 + # PageCount is the number of pages that the book opened in the lectern has. + page_count: u8 + # Position is the position of the lectern that was updated. If no lectern is at the block position, + # the packet should be ignored. + position: vec3i + # DropBook specifies if the book currently set on display in the lectern should be dropped server-side. + drop_book: bool packet_video_stream_connect: !id: 0x7e @@ -1890,11 +1976,15 @@ packet_update_block_properties: packet_client_cache_blob_status: !id: 0x87 !bound: client + # The number of MISSes in this packet + misses: varint + # The number of HITs in this packet + haves: varint # A list of blob hashes that the client does not have a blob available for. The server # should send the blobs matching these hashes as soon as possible. - missing: lu64[]varint + missing: lu64[]$misses # A list of hashes that the client does have a cached blob for. Server doesn't need to send. - have: lu64[]varint + have: lu64[]$haves # ClientCacheMissResponse is part of the blob cache protocol. It is sent by the server in response to a # ClientCacheBlobStatus packet and contains the blob data of all blobs that the client acknowledged not to @@ -2051,7 +2141,7 @@ packet_player_auth_input: delta: vec3f InputFlag: [ "bitflags", { - "type": "varint64", + "type": "varint", "flags": { "ascend": 0b1, "descend": 0b10, diff --git a/data/new/types.yaml b/data/new/types.yaml index 9be85ae..adf7b3b 100644 --- a/data/new/types.yaml +++ b/data/new/types.yaml @@ -64,7 +64,7 @@ Blob: hash: lu64 # Payload is the data of the blob. When sent, the client will associate the Hash of the blob with the # Payload in it. - payload: string + payload: ByteArray BlockPalette: []varint name: string @@ -586,52 +586,121 @@ StackRequestSlotInfo: # ItemStackRequests: []varint + # RequestID is a unique ID for the request. This ID is used by the server to send a response for this + # specific request in the ItemStackResponse packet. request_id: zigzag32 actions: []varint type_id: u8 => - '0': 'TAKE' - '1': 'PLACE' - '2': 'SWAP' - '3': 'DROP' - '4': 'DESTROY' - '5': 'CRAFTING_CONSUME_INPUT' - '6': 'create' - '7': 'LAB_TABLE_COMBINE' - '8': 'BEACON_PAYMENT' - '9': 'CRAFTING_RECIPE' - '10': 'CRAFTING_RECIPE_AUTO' #recipe book? - '11': 'CREATIVE_CREATE' - '12': 'CRAFTING_NON_IMPLEMENTED_DEPRECATED' #anvils aren't fully implemented yet - '13': 'CRAFTING_RESULTS_DEPRECATED' #no idea what this is for + # TakeStackRequestAction is sent by the client to the server to take x amount of items from one slot in a + # container to the cursor. + 0: take + # PlaceStackRequestAction is sent by the client to the server to place x amount of items from one slot into + # another slot, such as when shift clicking an item in the inventory to move it around or when moving an item + # in the cursor into a slot. + 1: place + # SwapStackRequestAction is sent by the client to swap the item in its cursor with an item present in another + # container. The two item stacks swap places. + 2: swap + # DropStackRequestAction is sent by the client when it drops an item out of the inventory when it has its + # inventory opened. This action is not sent when a player drops an item out of the hotbar using the Q button + # (or the equivalent on mobile). The InventoryTransaction packet is still used for that action, regardless of + # whether the item stack network IDs are used or not. + 3: drop + # DestroyStackRequestAction is sent by the client when it destroys an item in creative mode by moving it + # back into the creative inventory. + 4: destroy + # ConsumeStackRequestAction is sent by the client when it uses an item to craft another item. The original + # item is 'consumed'. + 5: consume + # CreateStackRequestAction is sent by the client when an item is created through being used as part of a + # recipe. For example, when milk is used to craft a cake, the buckets are leftover. The buckets are moved to + # the slot sent by the client here. + # Note that before this is sent, an action for consuming all items in the crafting table/grid is sent. Items + # that are not fully consumed when used for a recipe should not be destroyed there, but instead, should be + # turned into their respective resulting items. + 6: create + # LabTableCombineStackRequestAction is sent by the client when it uses a lab table to combine item stacks. + 7: lab_table_combine + # BeaconPaymentStackRequestAction is sent by the client when it submits an item to enable effects from a + # beacon. These items will have been moved into the beacon item slot in advance. + 8: beacon_payment + # CraftRecipeStackRequestAction is sent by the client the moment it begins crafting an item. This is the + # first action sent, before the Consume and Create item stack request actions. + # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as + # crafting, where the old item is consumed. + 9: craft_recipe + # AutoCraftRecipeStackRequestAction is sent by the client similarly to the CraftRecipeStackRequestAction. The + # only difference is that the recipe is automatically created and crafted by shift clicking the recipe book. + 10: craft_recipe_auto #recipe book? + # CraftCreativeStackRequestAction is sent by the client when it takes an item out fo the creative inventory. + # The item is thus not really crafted, but instantly created. + 11: craft_creative + # CraftRecipeOptionalStackRequestAction is sent when using an anvil. When this action is sent, the + # CustomNames field in the respective stack request is non-empty and contains the name of the item created + # using the anvil. + 12: optional + # CraftNonImplementedStackRequestAction is an action sent for inventory actions that aren't yet implemented + # in the new system. These include, for example, anvils. + 13: non_implemented #anvils aren't fully implemented yet + # CraftResultsDeprecatedStackRequestAction is an additional, deprecated packet sent by the client after + # crafting. It holds the final results and the amount of times the recipe was crafted. It shouldn't be used. + # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as + # crafting, where the old item is consumed. + 14: results_deprecated _: type_id ? - if TAKE or PLACE: + if take or place: count: u8 source: StackRequestSlotInfo destination: StackRequestSlotInfo - if SWAP: + if swap: + # Source and Destination point to the source slot from which Count of the item stack were taken and the + # destination slot to which this item was moved. source: StackRequestSlotInfo destination: StackRequestSlotInfo - if DROP: + if drop: + # Count is the count of the item in the source slot that was taken towards the destination slot. count: u8 + # Source is the source slot from which items were dropped to the ground. source: StackRequestSlotInfo + # Randomly seems to be set to false in most cases. I'm not entirely sure what this does, but this is what + # vanilla calls this field. randomly: bool - if DESTROY or CRAFTING_CONSUME_INPUT: + if destroy or consume: + # Count is the count of the item in the source slot that was destroyed. count: u8 + # Source is the source slot from which items came that were destroyed by moving them into the creative + # inventory. source: StackRequestSlotInfo if create: + # ResultsSlot is the slot in the inventory in which the results of the crafting ingredients are to be + # placed. result_slot_id: u8 - if BEACON_PAYMENT: - primary_effect: varint - secondary_effect: varint - if CRAFTING_RECIPE or CRAFTING_RECIPE_AUTO: - recipe_network_id: varint32 - if CREATIVE_CREATE: + if beacon_payment: + # PrimaryEffect and SecondaryEffect are the effects that were selected from the beacon. + primary_effect: zigzag32 + secondary_effect: zigzag32 + if craft_recipe or craft_recipe_auto: + # RecipeNetworkID is the network ID of the recipe that is about to be crafted. This network ID matches + # one of the recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as + # of 1.16. + recipe_network_id: varint + if craft_creative: + # CreativeItemNetworkID is the network ID of the creative item that is being created. This is one of the + # creative item network IDs sent in the CreativeContent packet. creative_item_network_id: varint32 - if CRAFTING_NON_IMPLEMENTED_DEPRECATED: void - if CRAFTING_RESULTS_DEPRECATED: - result_items: ItemStacks + if optional: + # For the cartography table, if a certain MULTI recipe is being called, this points to the network ID that was assigned. + recipe_network_id: varint + # Most likely the index in the request's filter strings that this action is using + filtered_string_index: li32 + if non_implemented: void + if results_deprecated: + result_items: Item[]varint times_crafted: u8 - + # CustomNames is a list of custom names involved in the request. This is typically filled with one string + # when an anvil is used. + # * Used for the server to determine which strings should be filtered. Used in anvils to verify a renamed item. + custom_names: string[]varint ItemStackResponses: []varint result: u8 @@ -683,6 +752,36 @@ CommandOrigin: if dev_console or test: player_entity_id: zigzag64 +# Some arbitrary definitions from CBMC, Window IDs are normally +# unique + sequential +WindowID: i8 => + -100: drop_contents + -24: beacon + -23: trading_output + -22: trading_use_inputs + -21: trading_input_2 + -20: trading_input_1 + -17: enchant_output + -16: enchant_material + -15: enchant_input + -13: anvil_output + -12: anvil_result + -11: anvil_material + -10: container_input + -5: crafting_use_ingredient + -4: crafting_result + -3: crafting_remove_ingredient + -2: crafting_add_ingredient + -1: none + 0: inventory + 1: first + 100: last + 119: offhand + 120: armor + 121: creative + 122: hotbar + 123: fixed_inventory + 124: ui WindowType: u8 => 0: container diff --git a/data/newproto.json b/data/newproto.json index bbce33d..4c90341 100644 --- a/data/newproto.json +++ b/data/newproto.json @@ -1,7 +1,6 @@ { "types": { "varint32": "varint", - "varint64": "varint", "bool": "native", "zigzag32": "native", "zigzag64": "native", @@ -209,7 +208,7 @@ }, { "name": "payload", - "type": "string" + "type": "ByteArray" } ] ], @@ -2037,20 +2036,21 @@ { "type": "u8", "mappings": { - "0": "TAKE", - "1": "PLACE", - "2": "SWAP", - "3": "DROP", - "4": "DESTROY", - "5": "CRAFTING_CONSUME_INPUT", + "0": "take", + "1": "place", + "2": "swap", + "3": "drop", + "4": "destroy", + "5": "consume", "6": "create", - "7": "LAB_TABLE_COMBINE", - "8": "BEACON_PAYMENT", - "9": "CRAFTING_RECIPE", - "10": "CRAFTING_RECIPE_AUTO", - "11": "CREATIVE_CREATE", - "12": "CRAFTING_NON_IMPLEMENTED_DEPRECATED", - "13": "CRAFTING_RESULTS_DEPRECATED" + "7": "lab_table_combine", + "8": "beacon_payment", + "9": "craft_recipe", + "10": "craft_recipe_auto", + "11": "craft_creative", + "12": "optional", + "13": "non_implemented", + "14": "results_deprecated" } } ] @@ -2062,7 +2062,7 @@ { "compareTo": "type_id", "fields": { - "TAKE": [ + "take": [ "container", [ { @@ -2079,7 +2079,7 @@ } ] ], - "PLACE": [ + "place": [ "container", [ { @@ -2096,7 +2096,7 @@ } ] ], - "SWAP": [ + "swap": [ "container", [ { @@ -2109,7 +2109,7 @@ } ] ], - "DROP": [ + "drop": [ "container", [ { @@ -2126,7 +2126,7 @@ } ] ], - "DESTROY": [ + "destroy": [ "container", [ { @@ -2139,7 +2139,7 @@ } ] ], - "CRAFTING_CONSUME_INPUT": [ + "consume": [ "container", [ { @@ -2161,38 +2161,38 @@ } ] ], - "BEACON_PAYMENT": [ + "beacon_payment": [ "container", [ { "name": "primary_effect", - "type": "varint" + "type": "zigzag32" }, { "name": "secondary_effect", + "type": "zigzag32" + } + ] + ], + "craft_recipe": [ + "container", + [ + { + "name": "recipe_network_id", "type": "varint" } ] ], - "CRAFTING_RECIPE": [ + "craft_recipe_auto": [ "container", [ { "name": "recipe_network_id", - "type": "varint32" + "type": "varint" } ] ], - "CRAFTING_RECIPE_AUTO": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint32" - } - ] - ], - "CREATIVE_CREATE": [ + "craft_creative": [ "container", [ { @@ -2201,13 +2201,32 @@ } ] ], - "CRAFTING_NON_IMPLEMENTED_DEPRECATED": "void", - "CRAFTING_RESULTS_DEPRECATED": [ + "optional": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + }, + { + "name": "filtered_string_index", + "type": "li32" + } + ] + ], + "non_implemented": "void", + "results_deprecated": [ "container", [ { "name": "result_items", - "type": "ItemStacks" + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] }, { "name": "times_crafted", @@ -2224,6 +2243,16 @@ ] } ] + }, + { + "name": "custom_names", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] } ] ] @@ -2385,6 +2414,41 @@ } ] ], + "WindowID": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], "WindowType": [ "mapper", { @@ -3063,6 +3127,10 @@ { "name": "source_name", "type": "string" + }, + { + "name": "message", + "type": "string" } ] ], @@ -3072,6 +3140,10 @@ { "name": "source_name", "type": "string" + }, + { + "name": "message", + "type": "string" } ] ], @@ -3081,6 +3153,10 @@ { "name": "source_name", "type": "string" + }, + { + "name": "message", + "type": "string" } ] ], @@ -4166,7 +4242,7 @@ }, { "name": "windows_id", - "type": "u8" + "type": "WindowID" } ] ], @@ -4457,8 +4533,8 @@ "type": "u8" }, { - "name": "type", - "type": "u8" + "name": "window_type", + "type": "WindowType" }, { "name": "coordinates", @@ -4492,7 +4568,7 @@ }, { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "select_slot", @@ -4517,7 +4593,7 @@ "container", [ { - "name": "inventory_id", + "name": "window_id", "type": "varint" }, { @@ -4539,7 +4615,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "property", @@ -4577,11 +4653,21 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "recipe_type", - "type": "zigzag32" + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "inventory", + "1": "crafting", + "2": "workbench" + } + } + ] }, { "name": "recipe_id", @@ -4589,11 +4675,23 @@ }, { "name": "input", - "type": "ItemStacks" + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] }, { "name": "result", - "type": "ItemStacks" + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] } ] ], @@ -4813,7 +4911,7 @@ "type": [ "mapper", { - "type": "varint", + "type": "zigzag32", "mappings": { "0": "achievement_awarded", "1": "entity_interact", @@ -4840,6 +4938,10 @@ { "name": "use_player_id", "type": "u8" + }, + { + "name": "event_data", + "type": "restBuffer" } ] ], @@ -6220,11 +6322,37 @@ ], "packet_level_event_generic": [ "container", - [] + [ + { + "name": "event_id", + "type": "varint" + }, + { + "name": "nbt", + "type": "nbtLoop" + } + ] ], "packet_lectern_update": [ "container", - [] + [ + { + "name": "page", + "type": "u8" + }, + { + "name": "page_count", + "type": "u8" + }, + { + "name": "position", + "type": "vec3i" + }, + { + "name": "drop_book", + "type": "bool" + } + ] ], "packet_video_stream_connect": [ "container", @@ -6306,12 +6434,20 @@ "packet_client_cache_blob_status": [ "container", [ + { + "name": "misses", + "type": "varint" + }, + { + "name": "haves", + "type": "varint" + }, { "name": "missing", "type": [ "array", { - "countType": "varint", + "count": "misses", "type": "lu64" } ] @@ -6321,7 +6457,7 @@ "type": [ "array", { - "countType": "varint", + "count": "haves", "type": "lu64" } ] @@ -6892,6 +7028,12 @@ "countType": "varint" } ], + "SignedByteArray": [ + "buffer", + { + "countType": "zigzag32" + } + ], "LittleString": [ "pstring", { @@ -6969,7 +7111,7 @@ "InputFlag": [ "bitflags", { - "type": "varint64", + "type": "varint", "flags": { "ascend": 1, "descend": 2, diff --git a/package.json b/package.json index b5647f9..043dc14 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,9 @@ "jsonwebtoken": "^8.5.1", "jsp-raknet": "github:extremeheat/raknet#client", "minecraft-folder-path": "^1.1.0", - "prismarine-nbt": "github:extremeheat/prismarine-nbt#le", + "prismarine-nbt": "^1.5.0", "protodef": "github:extremeheat/node-protodef#compiler", - "raknet-native": "^0.0.4", + "raknet-native": "^0.1.0", "uuid-1345": "^0.99.7" }, "devDependencies": { diff --git a/src/connection.js b/src/connection.js index e621446..367896c 100644 --- a/src/connection.js +++ b/src/connection.js @@ -35,9 +35,9 @@ class Connection extends EventEmitter { queue(name, params) { this.outLog('Q <- ', name, params) const packet = this.serializer.createPacketBuffer({ name, params }) - if (name == 'level_chunk') { - // Skip queue - this.sendMCPE(packet) + if (name == 'level_chunk' || name=='client_cache_blob_status' || name == 'client_cache_miss_response') { + // Skip queue, send ASAP + this.sendBuffer(packet) return } this.q.push(packet) @@ -54,12 +54,12 @@ class Connection extends EventEmitter { // For now, we're over conservative so send max 3 packets // per batch and hold the rest for the next tick const sending = [] - for (let i = 0; i < 3 && i < this.q.length; i++) { + for (let i = 0; i < this.q.length; i++) { const packet = this.q.shift() sending.push(this.q2.shift()) batch.addEncodedPacket(packet) } - // console.warn('~~ Sending', sending) + // this.outLog('~~ Sending', sending) if (this.encryptionEnabled) { this.sendEncryptedBatch(batch) } else { @@ -67,7 +67,7 @@ class Connection extends EventEmitter { } // this.q2 = [] } - }, 100) + }, 20) } writeRaw(name, buffer) { // skip protodef serializaion @@ -102,6 +102,7 @@ class Connection extends EventEmitter { } } else { this.q.push(buffer) + this.q2.push('rawBuffer') } } diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index 8d1e10f..a4ab558 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -1,9 +1,6 @@ const UUID = require('uuid-1345') const minecraft = require('./minecraft') - -const Read = {} -const Write = {} -const SizeOf = {} +const { Read, Write, SizeOf } = require('./varlong') /** * UUIDs @@ -38,6 +35,39 @@ SizeOf.restBuffer = ['native', (value) => { return value.length }] +/** + * Read NBT until end of buffer or \0 + */ +Read.nbtLoop = ['context', (buffer, offset) => { + const values = [] + while (buffer[offset] != 0) { + // console.log('offs',offset, buffer.length,buffer.slice(offset)) + const n = ctx.nbt(buffer, offset) + // console.log('read',n) + values.push(n.value) + offset += n.size + } + // console.log('Ext',offset, buffer.length,buffer.slice(offset)) + return { value: values, size: buffer.length - offset } +}] +Write.nbtLoop = ['context', (value, buffer, offset) => { + for (const val of value) { + // console.log('val',val,offset) + offset = ctx.nbt(val, buffer, offset) + } + // offset += 1 + // console.log('writing 0', offset) + buffer.writeUint8(0, offset) + return offset + 1 +}] +SizeOf.nbtLoop = ['context', (value, buffer, offset) => { + let size = 1 + for (const val of value) { + size += ctx.nbt(val, buffer, offset) + } + return size +}] + /** * NBT */ @@ -50,19 +80,19 @@ SizeOf.nbt = ['native', minecraft.nbt[2]] */ // nvm, // Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { - // return compiler.wrapCode(` - // const { value, size } = ${compiler.callType('buffer, offset', type)} - // const val = {} - // for (let i = 0; i < size; i++) { - // const hi = (value >> i) & 1 - // if () - // const v = value & - // if (flags[i]) - // } - // ` +// return compiler.wrapCode(` +// const { value, size } = ${compiler.callType('buffer, offset', type)} +// const val = {} +// for (let i = 0; i < size; i++) { +// const hi = (value >> i) & 1 +// if () +// const v = value & +// if (flags[i]) +// } +// ` // }] -Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { +Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { return compiler.wrapCode(` const { value: _value, size } = ${compiler.callType(type, 'offset')} const value = { _value } @@ -75,7 +105,7 @@ Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { }] -Write.bitflags = ['parametrizable', (compiler, { type, flags }) => { +Write.bitflags = ['parametrizable', (compiler, { type, flags }) => { return compiler.wrapCode(` const flags = ${JSON.stringify(flags)} let val = value._value @@ -86,7 +116,7 @@ Write.bitflags = ['parametrizable', (compiler, { type, flags }) => { `.trim()) }] -SizeOf.bitflags = ['parametrizable', (compiler, { type, flags }) => { +SizeOf.bitflags = ['parametrizable', (compiler, { type, flags }) => { return compiler.wrapCode(` const flags = ${JSON.stringify(flags)} let val = value._value @@ -117,7 +147,7 @@ Write.enum_size_based_on_values_len = ['parametrizable', (compiler) => { }) }] SizeOf.enum_size_based_on_values_len = ['parametrizable', (compiler) => { - return str(() => { + return str(() => { if (value.values_len <= 0xff) _enum_type = 'byte' else if (value.values_len <= 0xffff) _enum_type = 'short' else if (value.values_len <= 0xffffff) _enum_type = 'int' diff --git a/src/datatypes/varlong.js b/src/datatypes/varlong.js new file mode 100644 index 0000000..fa1059f --- /dev/null +++ b/src/datatypes/varlong.js @@ -0,0 +1,63 @@ +function sizeOfVarLong(value) { + if (typeof value.valueOf() === 'object') { + value = (BigInt(value[0]) << 32n) | BigInt(value[1]) + } else if (typeof value !== 'bigint') value = BigInt(value) + + let cursor = 0 + while (value > 127n) { + value >>= 7n + cursor++ + } + return cursor + 1 +} + +/** + * Reads a 64-bit VarInt as a BigInt + */ +function readVarLong(buffer, offset) { + let result = BigInt(0) + let shift = 0n + let cursor = offset + let size = 0 + + while (true) { + if (cursor + 1 > buffer.length) { throw new Error('unexpected buffer end') } + const b = buffer.readUInt8(cursor) + result |= (BigInt(b) & 0x7fn) << shift // Add the bits to our number, except MSB + cursor++ + if (!(b & 0x80)) { // If the MSB is not set, we return the number + size = cursor - offset + break + } + shift += 7n // we only have 7 bits, MSB being the return-trigger + if (shift > 63n) throw new Error(`varint is too big: ${shift}`) + } + + return { value: result, size } +} + +/** + * Writes a zigzag encoded 64-bit VarInt as a BigInt + */ +function writeVarLong(value, buffer, offset) { + // if an array, turn it into a BigInt + if (typeof value.valueOf() === 'object') { + value = BigInt.asIntN(64, (BigInt(value[0]) << 32n)) | BigInt(value[1]) + } else if (typeof value !== 'bigint') value = BigInt(value) + + let cursor = 0 + while (value > 127n) { // keep writing in 7 bit slices + const num = Number(value & 0xFFn) + buffer.writeUInt8(num | 0x80, offset + cursor) + cursor++ + value >>= 7n + } + buffer.writeUInt8(Number(value), offset + cursor) + return offset + cursor + 1 +} + +module.exports = { + Read: { varint64: ['native', readVarLong] }, + Write: { varint64: ['native', writeVarLong] }, + SizeOf: { varint64: ['native', sizeOfVarLong] } +} \ No newline at end of file diff --git a/src/rak.js b/src/rak.js index 5a16182..ad216a0 100644 --- a/src/rak.js +++ b/src/rak.js @@ -18,7 +18,7 @@ class RakNativeClient extends EventEmitter { this.raknet = new Client(options.hostname, options.port, 'minecraft') this.raknet.on('encapsulated', thingy => { - console.log('Encap',thingy) + // console.log('Encap',thingy) const { buffer, address, guid }=thingy this.onEncapsulated(buffer, address) }) @@ -76,7 +76,7 @@ class RakNativeServer extends EventEmitter { this.raknet.on('encapsulated', (thingy) => { const { buffer, address, guid }=thingy - console.log('ENCAP',thingy) + // console.log('ENCAP',thingy) this.onEncapsulated(buffer, address) }) } diff --git a/src/relay.js b/src/relay.js index 6fdc890..0fee6af 100644 --- a/src/relay.js +++ b/src/relay.js @@ -1,4 +1,5 @@ -process.env.DEBUG = 'minecraft-protocol raknet' +// process.env.DEBUG = 'minecraft-protocol raknet' +const fs = require('fs') const { Client } = require("./client") const { Server } = require("./server") const { Player } = require("./serverPlayer") @@ -6,6 +7,8 @@ const debug = require('debug')('minecraft-protocol relay') /** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ +const debugging = true // Do re-encoding tests + class RelayPlayer extends Player { constructor(server, conn) { super(server, conn) @@ -13,10 +16,8 @@ class RelayPlayer extends Player { this.conn = conn this.startRelaying = false - this.once('join', () => { - this.write('client_cache_status', {enabled:false}) // disable this asap on join - - this.flushDownQueue() + this.once('join', () => { // The client has joined our proxy + this.flushDownQueue() // Send queued packets from the upstream backend this.startRelaying = true }) this.downQ = [] @@ -26,6 +27,20 @@ class RelayPlayer extends Player { this.downInLog = (...msg) => console.info('** Client -> Proxy', ...msg) this.downOutLog = (...msg) => console.info('** Proxy -> Client', ...msg) + if (!server.options.logging) { + this.upInLog = () => { } + this.upOutLog = () => { } + this.downInLog = () => { } + this.downOutLog = () => { } + } + + // this.upOutLog = (...msg) => { + // if (msg.includes('player_auth_input')) { + // // stream.write(msg) + // console.info('INPUT', msg) + // } + // } + this.outLog = this.downOutLog this.inLog = this.downInLog } @@ -41,22 +56,26 @@ class RelayPlayer extends Player { const des = this.server.deserializer.parsePacketBuffer(packet) const name = des.data.name const params = des.data.params - this.upInLog('~~ Bounce B->C', name, serialize(params).slice(0, 100)) - this.upInLog('~~ ', des.buffer) - if (name == 'play_status' && params.status == 'login_success') return + this.upInLog('~ Bounce B->C', name, serialize(params).slice(0, 100)) + // this.upInLog('~ ', des.buffer) + if (name == 'play_status' && params.status == 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect - if (name == 'level_chunk') { //send chunk directly - this.upInLog('Would send chunk', params) - this.sendBuffer(packet) - return - } else this.upInLog('?',name) + if (debugging) { // some packet encode/decode testing stuff + const rpacket = this.server.serializer.createPacketBuffer({ name, params }) + if (rpacket.toString('hex') !== packet.toString('hex')) { + console.warn('New', rpacket.toString('hex')) + console.warn('Old', packet.toString('hex')) + console.log('Failed to re-encode', name, params) + process.exit(1) + throw Error('re-encoding fail for' + name + ' - ' + JSON.stringify(params)) + } + } - // if (name == 'network_chunk_publisher_update') return - // if (name == 'crafting_data' || name == 'level_chunk') return // Alex breaks this.queue(name, params) // this.sendBuffer(packet) } + // Send queued packets to the connected client flushDownQueue() { for (const packet of this.downQ) { const des = this.server.deserializer.parsePacketBuffer(packet) @@ -65,11 +84,12 @@ class RelayPlayer extends Player { this.downQ = [] } + // Send queued packets to the backend upstream server from the client flushUpQueue() { for (var e of this.upQ) { // Send the queue const des = this.server.deserializer.parsePacketBuffer(e) - if (des.data.name == 'client_cache_status') { // already disabled on join - // this.upstream.write('client_cache_status', {enabled:false}) + if (des.data.name == 'client_cache_status') { // Currently broken, force off the chunk cache + this.upstream.write('client_cache_status', { enabled: false }) } else { this.upstream.write(des.data.name, des.data.params) } @@ -79,25 +99,35 @@ class RelayPlayer extends Player { // Called when the server gets a packet from the downstream player (Client -> PROXY -> Backend) readPacket(packet) { - if (this.startRelaying) { // The DS client conn is established & we got a packet to send to US server + if (this.startRelaying) { // The downstream client conn is established & we got a packet to send to upstream server if (!this.upstream) { // Upstream is still connecting/handshaking - debug('Got downstream connected packet but upstream is not connected yet, added to q', this.queue.length) + this.downInLog('Got downstream connected packet but upstream is not connected yet, added to q', this.upQ.length) this.upQ.push(packet) // Put into a queue return } this.flushUpQueue() // Send queued packets this.downInLog('Recv packet', packet) const des = this.server.deserializer.parsePacketBuffer(packet) + + if (debugging) { // some packet encode/decode testing stuff + const rpacket = this.server.serializer.createPacketBuffer(des.data) + if (rpacket.toString('hex') !== packet.toString('hex')) { + console.warn('New', rpacket.toString('hex')) + console.warn('Old', packet.toString('hex')) + console.log('Failed to re-encode', des.data) + process.exit(1) + } + } + switch (des.data.name) { case 'client_cache_status': - this.upstream.queue('client_cache_status', {enabled:false}) + this.upstream.queue('client_cache_status', { enabled: false }) break - // case 'request_chunk_radius': - // this.upstream.queue('request_chunk_radius', {chunk_radius: 1}) - // break default: // Emit the packet as-is back to the upstream server - this.upstream.queue(des.data.name, des.data.params) + // this.upstream.queue(des.data.name, des.data.params) + this.downInLog('Relaying', des.data) + this.upstream.sendBuffer(packet) } } else { super.readPacket(packet) @@ -150,15 +180,13 @@ class Relay extends Server { conn.close() } else { const player = new this.RelayPlayer(this, conn) - console.log('NEW CONNECTION', conn.address) + console.debug('New connection from', conn.address) this.clients[conn.address] = player this.emit('connect', { client: player }) this.openUpstreamConnection(player, conn.address) } } } -console.log = () => {} - function serialize(obj = {}, fmt) { return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) @@ -192,7 +220,7 @@ function createRelay() { destination: { hostname: '127.0.0.1', port: 19132, - encryption: true + // encryption: true } }) diff --git a/test/serialization.js b/test/serialization.js index 6c1cbe5..bde8b37 100644 --- a/test/serialization.js +++ b/test/serialization.js @@ -241,13 +241,50 @@ function test() { } + function testLevelEventGeneric() { + const s = '7cce1f0305436f756e74800205084469725363616c65cdcc4c3e0504456e647800a01c440504456e647900001a420504456e647a00008942050653746172747899ef1944050653746172747900002042050653746172747a4583a042050a566172696174696f6e789a99193f050a566172696174696f6e799a99394000' + const buf = Buffer.from(s, 'hex') + const des = read(buf) + console.log(JSON.stringify(des)) + + console.log(des.data.name) + const newBuf = write(des.data.name, des.data.params) + console.log(newBuf.toString('hex'), s) + console.assert(newBuf.toString('hex')==s) + } + + function testEvent() { + const s = '41fdffffff5f2801001203e1417678933fdf294642a034a03e57b65b40' + const buf = Buffer.from(s, 'hex') + const des = read(buf) + console.log(serialize(des)) + + console.log(des.data.name) + const newBuf = write(des.data.name, des.data.params) + console.log(newBuf.toString('hex'), s) + console.assert(newBuf.toString('hex')==s) + } + + function testItemStackReq() { + const s = '93010105030b9d050e01920502000000000100013b32053a000000' + const buf = Buffer.from(s, 'hex') + const des = read(buf) + console.log(serialize(des)) + + console.log(des.data.name) + const newBuf = write(des.data.name, des.data.params) + console.log(newBuf.toString('hex'), 'OLD:', s) + console.assert(newBuf.toString('hex')==s) + } + // creativeTst() // availableCommands() // avaliableCmd() // creativeTestNew() // biomeDefinitions() // startGame() - testInventory() + // testLevelEventGeneric() + testItemStackReq() } if (!module.parent) { From 2905d39dd4acdec3748571e5bc7a5b05c1c0ac44 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Thu, 11 Mar 2021 12:11:42 +0000 Subject: [PATCH 114/458] remove yarn file --- yarn.lock | 2680 ----------------------------------------------------- 1 file changed, 2680 deletions(-) delete mode 100644 yarn.lock diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index a2e8df3..0000000 --- a/yarn.lock +++ /dev/null @@ -1,2680 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/cli@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.5.0.tgz#f403c930692e28ecfa3bf02a9e7562b474f38271" - integrity sha512-qNH55fWbKrEsCwID+Qc/3JDPnsSGpIIiMDbppnR8Z6PxLAqMQCFNqBctkIkBrMH49Nx+qqVTrHRWUR+ho2k+qQ== - dependencies: - commander "^2.8.1" - convert-source-map "^1.1.0" - fs-readdir-recursive "^1.1.0" - glob "^7.0.0" - lodash "^4.17.11" - mkdirp "^0.5.1" - output-file-sync "^2.0.0" - slash "^2.0.0" - source-map "^0.5.0" - optionalDependencies: - chokidar "^2.0.4" - -"@babel/code-frame@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" - integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== - dependencies: - "@babel/highlight" "^7.0.0" - -"@babel/core@^7.5.4": - version "7.5.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.4.tgz#4c32df7ad5a58e9ea27ad025c11276324e0b4ddd" - integrity sha512-+DaeBEpYq6b2+ZmHx3tHspC+ZRflrvLqwfv8E3hNr5LVQoyBnL8RPKSBCg+rK2W2My9PWlujBiqd0ZPsR9Q6zQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.5.0" - "@babel/helpers" "^7.5.4" - "@babel/parser" "^7.5.0" - "@babel/template" "^7.4.4" - "@babel/traverse" "^7.5.0" - "@babel/types" "^7.5.0" - convert-source-map "^1.1.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.11" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a" - integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA== - dependencies: - "@babel/types" "^7.5.0" - jsesc "^2.5.1" - lodash "^4.17.11" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" - integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" - integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-call-delegate@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" - integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== - dependencies: - "@babel/helper-hoist-variables" "^7.4.4" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" - -"@babel/helper-create-class-features-plugin@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.5.0.tgz#02edb97f512d44ba23b3227f1bf2ed43454edac5" - integrity sha512-EAoMc3hE5vE5LNhMqDOwB1usHvmRjCDAnH8CD4PVkX9/Yr3W/tcz8xE8QvdZxfsFBDICwZnF2UTHIqslRpvxmA== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-member-expression-to-functions" "^7.0.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.4.4" - "@babel/helper-split-export-declaration" "^7.4.4" - -"@babel/helper-define-map@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a" - integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/types" "^7.4.4" - lodash "^4.17.11" - -"@babel/helper-explode-assignable-expression@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" - integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== - dependencies: - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== - dependencies: - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-get-function-arity@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-hoist-variables@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" - integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== - dependencies: - "@babel/types" "^7.4.4" - -"@babel/helper-member-expression-to-functions@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" - integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-module-imports@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" - integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8" - integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/template" "^7.4.4" - "@babel/types" "^7.4.4" - lodash "^4.17.11" - -"@babel/helper-optimise-call-expression@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" - integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-plugin-utils@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== - -"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" - integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q== - dependencies: - lodash "^4.17.11" - -"@babel/helper-remap-async-to-generator@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" - integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-wrap-function" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27" - integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.0.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" - -"@babel/helper-simple-access@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" - integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== - dependencies: - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-split-export-declaration@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" - integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== - dependencies: - "@babel/types" "^7.4.4" - -"@babel/helper-wrap-function@^7.1.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" - integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.2.0" - -"@babel/helpers@^7.5.4": - version "7.5.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.4.tgz#2f00608aa10d460bde0ccf665d6dcf8477357cf0" - integrity sha512-6LJ6xwUEJP51w0sIgKyfvFMJvIb9mWAfohJp0+m6eHJigkFdcH8duZ1sfhn0ltJRzwUIT/yqqhdSfRpCpL7oow== - dependencies: - "@babel/template" "^7.4.4" - "@babel/traverse" "^7.5.0" - "@babel/types" "^7.5.0" - -"@babel/highlight@^7.0.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" - integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.4.4", "@babel/parser@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7" - integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA== - -"@babel/plugin-proposal-async-generator-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" - integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - "@babel/plugin-syntax-async-generators" "^7.2.0" - -"@babel/plugin-proposal-dynamic-import@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506" - integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" - -"@babel/plugin-proposal-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" - integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" - -"@babel/plugin-proposal-object-rest-spread@^7.5.4": - version "7.5.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331" - integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - -"@babel/plugin-proposal-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" - integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" - -"@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78" - integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" - -"@babel/plugin-syntax-async-generators@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" - integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-dynamic-import@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" - integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" - integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-object-rest-spread@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" - integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" - integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-typescript@^7.2.0": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" - integrity sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-arrow-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" - integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-async-to-generator@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" - integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - -"@babel/plugin-transform-block-scoped-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" - integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-block-scoping@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d" - integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.11" - -"@babel/plugin-transform-classes@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6" - integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-define-map" "^7.4.4" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.4.4" - "@babel/helper-split-export-declaration" "^7.4.4" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" - integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-destructuring@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a" - integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3" - integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" - -"@babel/plugin-transform-duplicate-keys@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" - integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-exponentiation-operator@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" - integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-for-of@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" - integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-function-name@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" - integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" - integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-member-expression-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d" - integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-modules-amd@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" - integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== - dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-commonjs@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74" - integrity sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ== - dependencies: - "@babel/helper-module-transforms" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-systemjs@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249" - integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg== - dependencies: - "@babel/helper-hoist-variables" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-umd@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" - integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw== - dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.4.5": - version "7.4.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz#9d269fd28a370258199b4294736813a60bbdd106" - integrity sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg== - dependencies: - regexp-tree "^0.1.6" - -"@babel/plugin-transform-new-target@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" - integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-object-super@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598" - integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" - -"@babel/plugin-transform-parameters@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" - integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== - dependencies: - "@babel/helper-call-delegate" "^7.4.4" - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-property-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905" - integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-regenerator@^7.4.5": - version "7.4.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f" - integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA== - dependencies: - regenerator-transform "^0.14.0" - -"@babel/plugin-transform-reserved-words@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" - integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-shorthand-properties@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" - integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-spread@^7.2.0": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" - integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-sticky-regex@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" - integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" - -"@babel/plugin-transform-template-literals@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" - integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-typeof-symbol@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" - integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-typescript@^7.3.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.5.2.tgz#ea7da440d29b8ccdb1bd02e18f6cfdc7ce6c16f5" - integrity sha512-r4zJOMbKY5puETm8+cIpaa0RQZG/sSASW1u0pj8qYklcERgVIbxVbP2wyJA7zI1//h7lEagQmXi9IL9iI5rfsA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.5.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript" "^7.2.0" - -"@babel/plugin-transform-unicode-regex@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f" - integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.5.4" - -"@babel/preset-env@^7.5.4": - version "7.5.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.4.tgz#64bc15041a3cbb0798930319917e70fcca57713d" - integrity sha512-hFnFnouyRNiH1rL8YkX1ANCNAUVC8Djwdqfev8i1415tnAG+7hlA5zhZ0Q/3Q5gkop4HioIPbCEWAalqcbxRoQ== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.2.0" - "@babel/plugin-proposal-dynamic-import" "^7.5.0" - "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.5.4" - "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-syntax-async-generators" "^7.2.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" - "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.5.0" - "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.4.4" - "@babel/plugin-transform-classes" "^7.4.4" - "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.5.0" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/plugin-transform-duplicate-keys" "^7.5.0" - "@babel/plugin-transform-exponentiation-operator" "^7.2.0" - "@babel/plugin-transform-for-of" "^7.4.4" - "@babel/plugin-transform-function-name" "^7.4.4" - "@babel/plugin-transform-literals" "^7.2.0" - "@babel/plugin-transform-member-expression-literals" "^7.2.0" - "@babel/plugin-transform-modules-amd" "^7.5.0" - "@babel/plugin-transform-modules-commonjs" "^7.5.0" - "@babel/plugin-transform-modules-systemjs" "^7.5.0" - "@babel/plugin-transform-modules-umd" "^7.2.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5" - "@babel/plugin-transform-new-target" "^7.4.4" - "@babel/plugin-transform-object-super" "^7.2.0" - "@babel/plugin-transform-parameters" "^7.4.4" - "@babel/plugin-transform-property-literals" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.4.5" - "@babel/plugin-transform-reserved-words" "^7.2.0" - "@babel/plugin-transform-shorthand-properties" "^7.2.0" - "@babel/plugin-transform-spread" "^7.2.0" - "@babel/plugin-transform-sticky-regex" "^7.2.0" - "@babel/plugin-transform-template-literals" "^7.4.4" - "@babel/plugin-transform-typeof-symbol" "^7.2.0" - "@babel/plugin-transform-unicode-regex" "^7.4.4" - "@babel/types" "^7.5.0" - browserslist "^4.6.0" - core-js-compat "^3.1.1" - invariant "^2.2.2" - js-levenshtein "^1.1.3" - semver "^5.5.0" - -"@babel/preset-typescript@^7.3.3": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz#88669911053fa16b2b276ea2ede2ca603b3f307a" - integrity sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.3.2" - -"@babel/register@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.4.4.tgz#370a68ba36f08f015a8b35d4864176c6b65d7a23" - integrity sha512-sn51H88GRa00+ZoMqCVgOphmswG4b7mhf9VOB0LUBAieykq2GnRFerlN+JQkO/ntT7wz4jaHNSRPg9IdMPEUkA== - dependencies: - core-js "^3.0.0" - find-cache-dir "^2.0.0" - lodash "^4.17.11" - mkdirp "^0.5.1" - pirates "^4.0.0" - source-map-support "^0.5.9" - -"@babel/template@^7.1.0", "@babel/template@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" - integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.4.4" - "@babel/types" "^7.4.4" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485" - integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.5.0" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.5.0" - "@babel/types" "^7.5.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.11" - -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab" - integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ== - dependencies: - esutils "^2.0.2" - lodash "^4.17.11" - to-fast-properties "^2.0.0" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -ajv@^6.5.4: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -asn1@^0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -babel-plugin-dynamic-import-node@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" - integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== - dependencies: - object.assign "^4.1.0" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -bn.js@^4.11.4: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -browserslist@^4.6.0, browserslist@^4.6.2: - version "4.6.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453" - integrity sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA== - dependencies: - caniuse-lite "^1.0.30000984" - electron-to-chromium "^1.3.191" - node-releases "^1.1.25" - -buffer-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" - integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -caniuse-lite@^1.0.30000984: - version "1.0.30000984" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000984.tgz#dc96c3c469e9bcfc6ad5bdd24c77ec918ea76fe0" - integrity sha512-n5tKOjMaZ1fksIpQbjERuqCyfgec/m9pferkFQbLmWtqLUdmt12hNhjSwsmPdqeiG2NkITOQhr1VYIwWSAceiA== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chokidar@^2.0.4: - version "2.1.6" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" - integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -chownr@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" - integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -commander@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" - integrity sha1-+mihT2qUXVTbvlDYzbMyDp47GgY= - -commander@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" - integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM= - -commander@^2.8.1: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.4.7: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - -convert-source-map@^1.1.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== - dependencies: - safe-buffer "~5.1.1" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-js-compat@^3.1.1: - version "3.1.4" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.1.4.tgz#e4d0c40fbd01e65b1d457980fe4112d4358a7408" - integrity sha512-Z5zbO9f1d0YrJdoaQhphVAnKPimX92D6z8lCGphH89MNRxlL1prI9ExJPqVwP0/kgkQCv8c4GJGT8X16yUncOg== - dependencies: - browserslist "^4.6.2" - core-js-pure "3.1.4" - semver "^6.1.1" - -core-js-pure@3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.4.tgz#5fa17dc77002a169a3566cc48dc774d2e13e3769" - integrity sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA== - -core-js@^3.0.0: - version "3.1.4" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07" - integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ== - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -debug@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - integrity sha1-+HBX6ZWxofauaklgZkE3vFbwOdo= - dependencies: - ms "0.7.1" - -debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.1.0, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -define-properties@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - -diff@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" - integrity sha1-fyjS657nsVqX79ic5j3P2qPMur8= - -electron-to-chromium@^1.3.191: - version "1.3.191" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.191.tgz#c451b422cd8b2eab84dedabab5abcae1eaefb6f0" - integrity sha512-jasjtY5RUy/TOyiUYM2fb4BDaPZfm6CXRFeJDMfFsXYADGxUN49RBqtgB7EL2RmJXeIRUk9lM1U6A5yk2YJMPQ== - -escape-string-regexp@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" - integrity sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE= - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -find-cache-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fs-minipass@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" - integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== - dependencies: - minipass "^2.2.1" - -fs-readdir-recursive@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" - integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== - dependencies: - nan "^2.12.1" - node-pre-gyp "^0.12.0" - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob@3.2.11: - version "3.2.11" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" - integrity sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0= - dependencies: - inherits "2" - minimatch "0.3" - -glob@^7.0.0, glob@^7.1.3: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -graceful-fs@^4.1.11: - version "4.2.0" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" - integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== - -growl@1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" - integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== - dependencies: - minimatch "^3.0.4" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -jade@0.26.3: - version "0.26.3" - resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" - integrity sha1-jxDXl32NefL2/4YqgbBRPMslaGw= - dependencies: - commander "0.6.1" - mkdirp "0.3.0" - -js-levenshtein@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" - integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== - dependencies: - minimist "^1.2.0" - -jwt-simple@^0.5.0: - version "0.5.6" - resolved "https://registry.yarnpkg.com/jwt-simple/-/jwt-simple-0.5.6.tgz#3357adec55b26547114157be66748995b75b333a" - integrity sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg== - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= - -lodash.merge@^4.4.0, lodash.merge@^4.6.1: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.reduce@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" - integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= - -lodash@^4.17.11: - version "4.17.14" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" - integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= - -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -macaddress@^0.2.9: - version "0.2.9" - resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.9.tgz#3579b8b9acd5b96b4553abf0f394185a86813cb3" - integrity sha512-k4F1JUof6cQXxNFzx3thLby4oJzXTXQueAOOts944Vqizn+Rjc2QNFenT9FJSLU1CH3PmrHRSyZs2E+Cqw+P2w== - -make-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -minimatch@0.3: - version "0.3.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" - integrity sha1-J12O2qxPG7MyZHIInnlJyDlGmd0= - dependencies: - lru-cache "2" - sigmund "~1.0.0" - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -minipass@^2.2.1, minipass@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" - integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" - integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== - dependencies: - minipass "^2.2.1" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" - integrity sha1-G79asbqCevI1dRQ0kEJkVfSB/h4= - -mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -mocha@^2.5.3: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" - integrity sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg= - dependencies: - commander "2.3.0" - debug "2.2.0" - diff "1.4.0" - escape-string-regexp "1.0.2" - glob "3.2.11" - growl "1.9.2" - jade "0.26.3" - mkdirp "0.5.1" - supports-color "1.2.0" - to-iso-string "0.0.2" - -ms@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - integrity sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg= - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -needle@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= - -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -node-releases@^1.1.25: - version "1.1.25" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3" - integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ== - dependencies: - semver "^5.3.0" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== - -npm-packlist@^1.1.6: - version "1.4.4" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" - integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-keys@^1.0.11, object-keys@^1.0.12: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - -os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc= - -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -output-file-sync@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-2.0.1.tgz#f53118282f5f553c2799541792b723a4c71430c0" - integrity sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ== - dependencies: - graceful-fs "^4.1.11" - is-plain-obj "^1.1.0" - mkdirp "^0.5.1" - -p-limit@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" - integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== - dependencies: - p-try "^2.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pirates@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -pre-commit@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" - integrity sha1-287g7p3nI15X95xW186UZBpp7sY= - dependencies: - cross-spawn "^5.0.1" - spawn-sync "^1.0.15" - which "1.2.x" - -prismarine-nbt@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prismarine-nbt/-/prismarine-nbt-1.2.1.tgz#4b0e50e538a4676ee259ae0588120360ab39110d" - integrity sha512-E2bBd2XzmcynT67zrkucgrC2MIgjmUtUathJ9sfjTswT+ou+7kbHbbLHO3nHLb6TKGiWFH79OfUmBTHJFULpbw== - dependencies: - protodef "^1.2.1" - -private@^0.1.6: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -protodef-validator@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/protodef-validator/-/protodef-validator-1.2.2.tgz#68fae789170e60c5a0a72686f56daee8f791f659" - integrity sha512-EnfcF1v/FGPtkwQr6SAbCM+9IoMCXlhtUVQKgeavUXoJ4FLNk3dZ0jIg/KDnTmaVgvDdHXhg1foH/qTae9vfhw== - dependencies: - ajv "^6.5.4" - -protodef@^1.2.1, protodef@^1.2.3, protodef@^1.6.6: - version "1.6.9" - resolved "https://registry.yarnpkg.com/protodef/-/protodef-1.6.9.tgz#3e913264757e1cf8489589552ec04263a44401f2" - integrity sha512-evAmLjdHgQ3B+wYyCgEijQxSBW049psaXCQlvg6PeJGhgTGEcMrn3M7idHbYvpGNKVIqwnIx8dpFpz1CJNm1wQ== - dependencies: - lodash.get "^4.4.2" - lodash.reduce "^4.6.0" - protodef-validator "^1.2.2" - readable-stream "^3.0.3" - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -"raknet@git+https://github.com/mhsjlw/node-raknet.git#master": - version "1.8.0" - resolved "git+https://github.com/mhsjlw/node-raknet.git#c017e4625e87a25e5fef1bb2fbb01e3fc5f91b00" - dependencies: - debug "^3.1.0" - lodash.merge "^4.6.1" - protodef "^1.6.6" - split-buffer "^1.0.0" - -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.3: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" - integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -regenerate-unicode-properties@^8.0.2: - version "8.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" - integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - -regenerator-transform@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf" - integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w== - dependencies: - private "^0.1.6" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexp-tree@^0.1.6: - version "0.1.11" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.11.tgz#c9c7f00fcf722e0a56c7390983a7a63dd6c272f3" - integrity sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg== - -regexpu-core@^4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae" - integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.0.2" - regjsgen "^0.5.0" - regjsparser "^0.6.0" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.1.0" - -regjsgen@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" - integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA== - -regjsparser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" - integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== - dependencies: - jsesc "~0.5.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.3.2: - version "1.11.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" - integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== - dependencies: - path-parse "^1.0.6" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -rimraf@^2.6.1: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -safe-buffer@^5.1.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== - -semver@^6.1.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" - integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== - -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@^0.5.9: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY= - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" - -split-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/split-buffer/-/split-buffer-1.0.0.tgz#b7e8e0ab51345158b72c1f6dbef2406d51f1d027" - integrity sha1-t+jgq1E0UVi3LB9tvvJAbVHx0Cc= - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" - integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== - dependencies: - safe-buffer "~5.1.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - integrity sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -tar@^4: - version "4.4.10" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" - integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.3.5" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-iso-string@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" - integrity sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" - integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" - integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" - integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -uuid-1345@^0.99.6: - version "0.99.7" - resolved "https://registry.yarnpkg.com/uuid-1345/-/uuid-1345-0.99.7.tgz#e52845074352feaae72ce7b31ae1f53b486ceea1" - integrity sha512-A70cwvqH95zULri1/t00/r6Bd97hKpNvS9SoSLP9Bupn95sX/01JkOuH9YjJrmNul7ZAjyX3Y3ZMlDrCjuoNPQ== - dependencies: - macaddress "^0.2.9" - -which@1.2.x: - version "1.2.14" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" - integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU= - dependencies: - isexe "^2.0.0" - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yallist@^3.0.0, yallist@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" - integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== From 3ffcf841eaba0cd4a93a13375fc8e1d39185ad7b Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Thu, 11 Mar 2021 13:30:44 +0100 Subject: [PATCH 115/458] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 037985b..3c7e063 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/PrismarineJS/pocket-minecraft-protocol](https://badges.gitter.im/PrismarineJS/pocket-minecraft-protocol.svg)](https://gitter.im/PrismarineJS/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ========================= -> Note: **THIS IS NOT USABLE SOFTWARE!** If you're looking for experimental encryption or current support, please see the [1.1](https://github.com/PrismarineJS/pocket-minecraft-protocol/tree/1.1)+ branch +Not ready for prime time yet, check https://github.com/PrismarineJS/bedrock-protocol/projects/1 for progress Parse and serialize Minecraft: Pocket Edition packets From df8612e35519bbeaeb21fd51eba4c6d963510039 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 12 Mar 2021 14:20:25 -0500 Subject: [PATCH 116/458] Start work on multi-version support, test cleanup (#43) * some cleanup * start work on multi-version support * undelete some old examples, can update them later * move old examples --- .gitignore | 10 +- data/{ => 1.16.201}/biome_definitions.nbt | Bin data/{ => 1.16.201}/creativeitems.json | 0 .../{newproto.json => 1.16.201/protocol.json} | 0 data/1.16.201/skin_geom.txt | 1 + data/new/compile.js | 37 +- data/new/packet_map.yml | 317 --- data/new/proto.yml | 9 +- data/protocol.json | 2517 ----------------- data/provider.js | 45 + {samples => examples}/clientTest.js | 0 examples/createRelay.js | 38 + examples/{ => old}/chunk | Bin examples/{ => old}/client.js | 0 examples/{ => old}/deserialize.js | 0 examples/{ => old}/server.js | 0 examples/{ => old}/server_simple.js | 0 {samples => examples}/serverTest.js | 43 +- src/auth/chains.js | 32 +- src/auth/encryption.js | 7 +- src/auth/tests/encrypt.js | 232 -- src/auth/tests/encryptTest.js | 88 - src/auth/tests/jwtTest.js | 49 - src/client.js | 98 +- src/client/auth.js | 49 +- src/connection.js | 66 +- src/datatypes/promises.js | 12 - src/datatypes/util.js | 37 + src/options.js | 12 +- src/rak.js | 47 +- src/relay.js | 48 +- src/server.js | 23 +- src/serverPlayer.js | 17 +- src/transforms/encryption.js | 26 +- src/transforms/serializer.js | 27 +- 35 files changed, 369 insertions(+), 3518 deletions(-) rename data/{ => 1.16.201}/biome_definitions.nbt (100%) rename data/{ => 1.16.201}/creativeitems.json (100%) rename data/{newproto.json => 1.16.201/protocol.json} (100%) create mode 100644 data/1.16.201/skin_geom.txt delete mode 100644 data/new/packet_map.yml delete mode 100644 data/protocol.json create mode 100644 data/provider.js rename {samples => examples}/clientTest.js (100%) create mode 100644 examples/createRelay.js rename examples/{ => old}/chunk (100%) rename examples/{ => old}/client.js (100%) rename examples/{ => old}/deserialize.js (100%) rename examples/{ => old}/server.js (100%) rename examples/{ => old}/server_simple.js (100%) rename {samples => examples}/serverTest.js (69%) delete mode 100644 src/auth/tests/encrypt.js delete mode 100644 src/auth/tests/encryptTest.js delete mode 100644 src/auth/tests/jwtTest.js delete mode 100644 src/datatypes/promises.js create mode 100644 src/datatypes/util.js diff --git a/.gitignore b/.gitignore index f7f9591..2f39796 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,11 @@ node_modules/ npm-debug.log package-lock.json __* -data/*.js src/**/*.json -src/**/*.txt -dist/ \ No newline at end of file +# Runtime generated data +data/*/sample +data/**/read.js +data/**/write.js +data/**/size.js +samples/*.txt +samples/*.json \ No newline at end of file diff --git a/data/biome_definitions.nbt b/data/1.16.201/biome_definitions.nbt similarity index 100% rename from data/biome_definitions.nbt rename to data/1.16.201/biome_definitions.nbt diff --git a/data/creativeitems.json b/data/1.16.201/creativeitems.json similarity index 100% rename from data/creativeitems.json rename to data/1.16.201/creativeitems.json diff --git a/data/newproto.json b/data/1.16.201/protocol.json similarity index 100% rename from data/newproto.json rename to data/1.16.201/protocol.json diff --git a/data/1.16.201/skin_geom.txt b/data/1.16.201/skin_geom.txt new file mode 100644 index 0000000..0c3cd70 --- /dev/null +++ b/data/1.16.201/skin_geom.txt @@ -0,0 +1 @@ +ewogICAiZm9ybWF0X3ZlcnNpb24iIDogIjEuMTQuMCIsCiAgICJtaW5lY3JhZnQ6Z2VvbWV0cnkiIDogWwogICAgICB7CiAgICAgICAgICJib25lcyIgOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImJlbHQiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJsb2NhdG9ycyIgOiB7CiAgICAgICAgICAgICAgICAgICJhcm1vcl9vZmZzZXQuZGVmYXVsdF9uZWNrIiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAibmFtZSIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJib2R5YXJtb3IiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJoZWFkIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVsbWV0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyA1LjAsIDIyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm1pcnJvciIgOiB0cnVlLAogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0Ym9vdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNi4wLCAxNS4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRsZWdnaW5nIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGJvb3QiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibG9jYXRvcnMiIDogewogICAgICAgICAgICAgICAgICAibGVhZF9ob2xkIiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0aXRlbSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyb290IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGxlZ2dpbmciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJvb3QiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfQogICAgICAgICBdLAogICAgICAgICAiZGVzY3JpcHRpb24iIDogewogICAgICAgICAgICAiaWRlbnRpZmllciIgOiAiZ2VvbWV0cnkucGVyc29uYV9lMTk5NjcyYThjMWE4N2UwLTAiLAogICAgICAgICAgICAidGV4dHVyZV9oZWlnaHQiIDogMS4wLAogICAgICAgICAgICAidGV4dHVyZV93aWR0aCIgOiAxLjAKICAgICAgICAgfQogICAgICB9LAogICAgICB7CiAgICAgICAgICJib25lcyIgOiBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImJlbHQiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJsb2NhdG9ycyIgOiB7CiAgICAgICAgICAgICAgICAgICJhcm1vcl9vZmZzZXQuZGVmYXVsdF9uZWNrIiA6IFsgMC4wLCAyNC4wLCAwLjAgXQogICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAibmFtZSIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgMC4wLCAyNC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk5ODA0Njg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiYm9keWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiYm9keSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImhlbG1ldCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImhlYWQiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImphY2tldCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjI1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjI1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjI1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjI1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMjUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4yNTAsIDI0LjI1MCwgMi4yNTAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xNTYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC45OTAyMzQzNzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRhcm0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNS4wLCAyMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAyNC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMCwgMjQuMCwgMi4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTgwNDY4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm1pcnJvciIgOiB0cnVlLAogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0Ym9vdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNi4wLCAxNS4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuOTAwMDAwMDk1MzY3NDMyLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjEwMDAwMDAwMTQ5MDExNjEsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuOTAwMDAwMDk1MzY3NDMyLCAwLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4xMDAwMDAwMDE0OTAxMTYxLCAwLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4xMDAwMDAwMDE0OTAxMTYxLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMTAwMDAwMDAxNDkwMTE2MSwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4xMDAwMDAwMDE0OTAxMTYxLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjkwMDAwMDA5NTM2NzQzMiwgMTIuMCwgMi4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yODEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjgxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yODEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjMxMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI4MTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk4MjQyMTg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnZ2luZyIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdHBhbnRzIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMzQ5OTk5OTk0MDM5NTM1NSwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgLTAuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIDEyLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMzQ5OTk5OTk0MDM5NTM1NSwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0wLjM0OTk5OTk5NDAzOTUzNTUsIDEyLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMC4zNDk5OTk5OTQwMzk1MzU1LCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTAuMzQ5OTk5OTk0MDM5NTM1NSwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMTUwMDAwMDk1MzY3NDMyLCAxMi4yNTAsIDIuMjUwIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQ2ODc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Njg3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDY4NzUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Njg3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40Mzc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQ2ODc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQ2ODc1MCwgMC45ODI0MjE4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRzbGVldmUiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNS4wLCAyMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMy43NTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjI1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgOC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA4LjI1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDMuNzUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMy43NTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAzLjc1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDguMjUwLCAyNC4yNTAsIDIuMjUwIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQzNzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zMTI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjQwNjI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNzUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0Mzc1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC40MDYyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDM3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNDA2MjUwLCAwLjk5MDIzNDM3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0c29jayIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTUuMCwgMjIuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICJwb2x5X21lc2giIDogewogICAgICAgICAgICAgICAgICAibm9ybWFsaXplZF91dnMiIDogdHJ1ZSwKICAgICAgICAgICAgICAgICAgIm5vcm1hbHMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIC0xLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0xLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAtMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIDEuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb2x5cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAwLCAwLCAwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMSwgMCwgMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIsIDAsIDIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAzLCAwLCAzIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDQsIDEsIDQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA1LCAxLCA1IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNiwgMSwgNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDcsIDEsIDcgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOCwgMiwgOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDksIDIsIDkgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMCwgMiwgMTAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMSwgMiwgMTEgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTIsIDMsIDEyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTMsIDMsIDEzIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTQsIDMsIDE0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTUsIDMsIDE1IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDE2LCA0LCAxNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE3LCA0LCAxNyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE4LCA0LCAxOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE5LCA0LCAxOSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMCwgNSwgMjAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMSwgNSwgMjEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMiwgNSwgMjIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMywgNSwgMjMgXQogICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb3NpdGlvbnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDI0LjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMjQuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4wLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMCwgMjQuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjAsIDI0LjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIDIuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJ1dnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5ODA0Njg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTgwNDY4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTk4MDQ2ODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5ODA0Njg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRhcm1hcm1vciIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRib290IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgImxvY2F0b3JzIiA6IHsKICAgICAgICAgICAgICAgICAgImxlYWRfaG9sZCIgOiBbIC02LjAsIDE1LjAsIDAuMCBdCiAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC02LjAsIDE1LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICJwb2x5X21lc2giIDogewogICAgICAgICAgICAgICAgICAibm9ybWFsaXplZF91dnMiIDogdHJ1ZSwKICAgICAgICAgICAgICAgICAgIm5vcm1hbHMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIC0xLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0xLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAtMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIDEuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb2x5cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAwLCAwLCAwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMSwgMCwgMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIsIDAsIDIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAzLCAwLCAzIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDQsIDEsIDQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA1LCAxLCA1IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNiwgMSwgNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDcsIDEsIDcgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOCwgMiwgOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDksIDIsIDkgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMCwgMiwgMTAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMSwgMiwgMTEgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTIsIDMsIDEyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTMsIDMsIDEzIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTQsIDMsIDE0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTUsIDMsIDE1IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDE2LCA0LCAxNiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE3LCA0LCAxNyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE4LCA0LCAxOCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE5LCA0LCAxOSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMCwgNSwgMjAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMSwgNSwgMjEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMiwgNSwgMjIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyMywgNSwgMjMgXQogICAgICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJwb3NpdGlvbnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMTIuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuOTAwMDAwMDk1MzY3NDMyLCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuOTAwMDAwMDk1MzY3NDMyLCAxMi4wLCAtMi4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuOTAwMDAwMDk1MzY3NDMyLCAxMi4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDAuMCwgLTIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIC0yLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5OTk5OTg5NzE4MTk4Nzc2LCAwLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjkwMDAwMDA5NTM2NzQzMiwgMC4wLCAyLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy45MDAwMDAwOTUzNjc0MzIsIDEyLjAsIDIuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDk5OTk5ODk3MTgxOTg3NzYsIDEyLjAsIDIuMCBdCiAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICJ1dnMiIDogWwogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTU2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTg3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE4NzUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjE1NjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yMTg3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC45NzY1NjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjIxODc1MCwgMC45ODI0MjE4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0bGVnZ2luZyIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0bGVnIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodHBhbnRzIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQ5OTk5OTA0NjMyNTY4NCwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgLTAuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQ5OTk5OTA0NjMyNTY4NCwgLTAuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMzQ5OTk5OTA0NjMyNTY4NCwgLTAuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMTUwMDAwMDk1MzY3NDMyLCAtMC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIC0wLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAtMC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgLTAuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIC0wLjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4zNDk5OTk5MDQ2MzI1Njg0LCAxMi4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjE1MDAwMDA5NTM2NzQzMiwgMTIuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIC0wLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4xNTAwMDAwOTUzNjc0MzIsIDEyLjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjM0OTk5OTkwNDYzMjU2ODQsIDEyLjI1MCwgMi4yNTAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTc2NTYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45ODI0MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTgyNDIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk3NjU2MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk4MjQyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODI0MjE4NzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0c2xlZXZlIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXSwKICAgICAgICAgICAgICAgInBvbHlfbWVzaCIgOiB7CiAgICAgICAgICAgICAgICAgICJub3JtYWxpemVkX3V2cyIgOiB0cnVlLAogICAgICAgICAgICAgICAgICAibm9ybWFscyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAxLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgLTEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjAsIC0xLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgMS4wIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvbHlzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDAsIDAsIDAgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxLCAwLCAxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMiwgMCwgMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDMsIDAsIDMgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNCwgMSwgNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDUsIDEsIDUgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA2LCAxLCA2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNywgMSwgNyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA4LCAyLCA4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgOSwgMiwgOSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEwLCAyLCAxMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDExLCAyLCAxMSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMiwgMywgMTIgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxMywgMywgMTMgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNCwgMywgMTQgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNSwgMywgMTUgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTYsIDQsIDE2IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTcsIDQsIDE3IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTgsIDQsIDE4IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTksIDQsIDE5IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDIwLCA1LCAyMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIxLCA1LCAyMSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIyLCA1LCAyMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDIzLCA1LCAyMyBdCiAgICAgICAgICAgICAgICAgICAgIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInBvc2l0aW9ucyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAyNC4yNTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy43NTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDI0LjI1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy43NTAsIDExLjc1MCwgMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMy43NTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjI1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC04LjI1MCwgMTEuNzUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMTEuNzUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAyLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDExLjc1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAxMS43NTAsIC0yLjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC0zLjc1MCwgMjQuMjUwLCAtMi4yNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtOC4yNTAsIDI0LjI1MCwgLTIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAxMS43NTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTguMjUwLCAyNC4yNTAsIDIuMjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTMuNzUwLCAyNC4yNTAsIDIuMjUwIF0KICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgInV2cyIgOiBbCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wMzEyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkyMTg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5MjE4NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wNjI1MCwgMC45OTIxODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDkzNzUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDYyNTAsIDAuOTkwMjM0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMDMxMjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk4NDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA2MjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAzMTI1MCwgMC45OTAyMzQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wOTM3NTAsIDAuOTg0Mzc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMTI1MCwgMC45ODQzNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4xMjUwLCAwLjk5MDIzNDM3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjA5Mzc1MCwgMC45OTAyMzQzNzUwIF0KICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0c29jayIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0bGVnIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyb290IgogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJ3YWlzdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJvb3QiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0KICAgICAgICAgXSwKICAgICAgICAgImRlc2NyaXB0aW9uIiA6IHsKICAgICAgICAgICAgImlkZW50aWZpZXIiIDogImdlb21ldHJ5LmFuaW1hdGVkXzEyOHgxMjhfcGVyc29uYS1lMTk5NjcyYThjMWE4N2UwLTAiLAogICAgICAgICAgICAidGV4dHVyZV9oZWlnaHQiIDogMjA0OC4wLAogICAgICAgICAgICAidGV4dHVyZV93aWR0aCIgOiAxMjguMAogICAgICAgICB9CiAgICAgIH0sCiAgICAgIHsKICAgICAgICAgImJvbmVzIiA6IFsKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiYmVsdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgImxvY2F0b3JzIiA6IHsKICAgICAgICAgICAgICAgICAgImFybW9yX29mZnNldC5kZWZhdWx0X25lY2siIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJib2R5IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAid2Fpc3QiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImJvZHlhcm1vciIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogImhhdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImhlYWQiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMzIuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMzIuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjUwLCAyMy41MCwgNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjUwLCAyMy41MCwgLTQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDMyLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjUwLCAzMi41MCwgNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIDQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjUwLCAzMi41MCwgLTQuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC41MCwgMjMuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMjMuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIC00LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDMyLjUwLCAtNC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuNTAsIDIzLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDIzLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuNTAsIDMyLjUwLCA0LjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC41MCwgMzIuNTAsIDQuNTAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC42MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC42MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjc1MCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuNjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjc1MCwgMC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC41MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjYyNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC42MjUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC43NTAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuNTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuNjI1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjYyNTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAwLjAsIDI0LjAsIDAuMCBdLAogICAgICAgICAgICAgICAicG9seV9tZXNoIiA6IHsKICAgICAgICAgICAgICAgICAgIm5vcm1hbGl6ZWRfdXZzIiA6IHRydWUsCiAgICAgICAgICAgICAgICAgICJub3JtYWxzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDEuMCwgMC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAtMS4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtMS4wLCAwLjAsIDAuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC4wLCAwLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuMCwgLTEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMCwgMC4wLCAxLjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9seXMiIDogWwogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMCwgMCwgMCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEsIDAsIDEgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAyLCAwLCAyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMywgMCwgMyBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyA0LCAxLCA0IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgNSwgMSwgNSBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDYsIDEsIDYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA3LCAxLCA3IF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDgsIDIsIDggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyA5LCAyLCA5IF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTAsIDIsIDEwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMTEsIDIsIDExIF0KICAgICAgICAgICAgICAgICAgICAgXSwKICAgICAgICAgICAgICAgICAgICAgWwogICAgICAgICAgICAgICAgICAgICAgICBbIDEyLCAzLCAxMiBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDEzLCAzLCAxMyBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE0LCAzLCAxNCBdLAogICAgICAgICAgICAgICAgICAgICAgICBbIDE1LCAzLCAxNSBdCiAgICAgICAgICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgICAgICAgIFsKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNiwgNCwgMTYgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxNywgNCwgMTcgXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOCwgNCwgMTggXSwKICAgICAgICAgICAgICAgICAgICAgICAgWyAxOSwgNCwgMTkgXQogICAgICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAgICBbCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjAsIDUsIDIwIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjEsIDUsIDIxIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjIsIDUsIDIyIF0sCiAgICAgICAgICAgICAgICAgICAgICAgIFsgMjMsIDUsIDIzIF0KICAgICAgICAgICAgICAgICAgICAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAicG9zaXRpb25zIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAzMi4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAzMi4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDI0LjAsIDQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDI0LjAsIC00LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMzIuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIC00LjAsIDMyLjAsIDQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCA0LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyA0LjAsIDMyLjAsIC00LjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAtNC4wLCAyNC4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAyNC4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCAtNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMzIuMCwgLTQuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDQuMCwgMjQuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMjQuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgLTQuMCwgMzIuMCwgNC4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgNC4wLCAzMi4wLCA0LjAgXQogICAgICAgICAgICAgICAgICBdLAogICAgICAgICAgICAgICAgICAidXZzIiA6IFsKICAgICAgICAgICAgICAgICAgICAgWyAwLjI1MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMS4wIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDEuMCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAxLjAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjUwLCAwLjg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjc1MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4wLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjg3NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAwLjAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC43NTAsIDAuNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC43NTAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuMjUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNTAsIDAuNzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC41MCwgMC44NzUwIF0sCiAgICAgICAgICAgICAgICAgICAgIFsgMC4yNTAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDEuMCwgMC43NTAgXSwKICAgICAgICAgICAgICAgICAgICAgWyAxLjAsIDAuODc1MCBdLAogICAgICAgICAgICAgICAgICAgICBbIDAuNzUwLCAwLjg3NTAgXQogICAgICAgICAgICAgICAgICBdCiAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAiaGVsbWV0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAiaGVhZCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMjQuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyA1LjAsIDIyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm1pcnJvciIgOiB0cnVlLAogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGFybSIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDUuMCwgMjIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibWlycm9yIiA6IHRydWUsCiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0Ym9vdCIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImxlZnRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAxLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAibGVmdGl0ZW0iLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJsZWZ0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgNi4wLCAxNS4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJsZWZ0bGVnIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRsZWdnaW5nIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJtaXJyb3IiIDogdHJ1ZSwKICAgICAgICAgICAgICAgIm5hbWUiIDogImxlZnRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAibGVmdGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogImJvZHkiLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGFybWFybW9yIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRhcm0iLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtNS4wLCAyMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGJvb3QiLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibG9jYXRvcnMiIDogewogICAgICAgICAgICAgICAgICAibGVhZF9ob2xkIiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIm5hbWUiIDogInJpZ2h0aXRlbSIsCiAgICAgICAgICAgICAgICJwYXJlbnQiIDogInJpZ2h0YXJtIiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTYuMCwgMTUuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyb290IiwKICAgICAgICAgICAgICAgInBpdm90IiA6IFsgLTEuODk5OTk5OTc2MTU4MTQyLCAxMi4wLCAwLjAgXQogICAgICAgICAgICB9LAogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICJuYW1lIiA6ICJyaWdodGxlZ2dpbmciLAogICAgICAgICAgICAgICAicGFyZW50IiA6ICJyaWdodGxlZyIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIC0xLjg5OTk5OTk3NjE1ODE0MiwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgewogICAgICAgICAgICAgICAibmFtZSIgOiAicmlnaHRzb2NrIiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicmlnaHRsZWciLAogICAgICAgICAgICAgICAicGl2b3QiIDogWyAtMS44OTk5OTk5NzYxNTgxNDIsIDEyLjAsIDAuMCBdCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogInJvb3QiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIm5hbWUiIDogIndhaXN0IiwKICAgICAgICAgICAgICAgInBhcmVudCIgOiAicm9vdCIsCiAgICAgICAgICAgICAgICJwaXZvdCIgOiBbIDAuMCwgMTIuMCwgMC4wIF0KICAgICAgICAgICAgfQogICAgICAgICBdLAogICAgICAgICAiZGVzY3JpcHRpb24iIDogewogICAgICAgICAgICAiaWRlbnRpZmllciIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfZmFjZV9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICAgICAgICJ0ZXh0dXJlX2hlaWdodCIgOiA2NC4wLAogICAgICAgICAgICAidGV4dHVyZV93aWR0aCIgOiAzMi4wCiAgICAgICAgIH0KICAgICAgfQogICBdCn0K \ No newline at end of file diff --git a/data/new/compile.js b/data/new/compile.js index 9ba4669..a4ebce5 100644 --- a/data/new/compile.js +++ b/data/new/compile.js @@ -8,11 +8,14 @@ const fs = require('fs') const { ProtoDefCompiler } = require('protodef').Compiler +// Parse the YML files and turn to JSON function genProtoSchema() { const { parse, compile } = require('protodef-yaml/compiler') + let version // Create the packet_map.yml from proto.yml const parsed = parse('./proto.yml') + version = parsed['!version'] const packets = [] for (const key in parsed) { if (key.startsWith('%container')) { @@ -30,31 +33,39 @@ function genProtoSchema() { l1 += ` 0x${id.toString(16).padStart(2, '0')}: ${name}\n` l2 += ` if ${name}: ${fname}\n` } - const t = `!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` + // TODO: skip creating packet_map.yml and just generate the ProtoDef map JSON directly + const t = `#Auto-generated from proto.yml, do not modify\n!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` fs.writeFileSync('./packet_map.yml', t) compile('./proto.yml', 'protocol.json') + return version } -genProtoSchema() - -fs.writeFileSync('../newproto.json', JSON.stringify({ types: require('./protocol.json') }, null, 2)) -fs.unlinkSync('./protocol.json') //remove temp file - -function createProtocol() { +// Compile the ProtoDef JSON into JS +function createProtocol(version) { const compiler = new ProtoDefCompiler() - const protocol = require('../newproto.json').types + const protocol = require(`../${version}/protocol.json`).types compiler.addTypes(require('../../src/datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) compiler.addTypesToCompile(protocol) - fs.writeFileSync('../read.js', 'module.exports = ' + compiler.readCompiler.generate()) - fs.writeFileSync('../write.js', 'module.exports = ' + compiler.writeCompiler.generate()) - fs.writeFileSync('../size.js', 'module.exports = ' + compiler.sizeOfCompiler.generate()) + fs.writeFileSync(`../${version}/read.js`, 'module.exports = ' + compiler.readCompiler.generate()) + fs.writeFileSync(`../${version}/write.js`, 'module.exports = ' + compiler.writeCompiler.generate()) + fs.writeFileSync(`../${version}/size.js`, 'module.exports = ' + compiler.sizeOfCompiler.generate()) const compiledProto = compiler.compileProtoDefSync() return compiledProto } -console.log('Generating JS...') -createProtocol() \ No newline at end of file +function main() { + const version = genProtoSchema() + + fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: require('./protocol.json') }, null, 2)) + fs.unlinkSync('./protocol.json') //remove temp file + fs.unlinkSync('./packet_map.yml') //remove temp file + + console.log('Generating JS...') + createProtocol(version) +} + +main() \ No newline at end of file diff --git a/data/new/packet_map.yml b/data/new/packet_map.yml deleted file mode 100644 index 3734525..0000000 --- a/data/new/packet_map.yml +++ /dev/null @@ -1,317 +0,0 @@ -!import: types.yaml -mcpe_packet: - name: varint => - 0x01: login - 0x02: play_status - 0x03: server_to_client_handshake - 0x04: client_to_server_handshake - 0x05: disconnect - 0x06: resource_packs_info - 0x07: resource_pack_stack - 0x08: resource_pack_client_response - 0x09: text - 0x0a: set_time - 0x0b: start_game - 0x0c: add_player - 0x0d: add_entity - 0x0e: remove_entity - 0x0f: add_item_entity - 0x11: take_item_entity - 0x12: move_entity - 0x13: move_player - 0x14: rider_jump - 0x15: update_block - 0x16: add_painting - 0x17: tick_sync - 0x18: level_sound_event_old - 0x19: level_event - 0x1a: block_event - 0x1b: entity_event - 0x1c: mob_effect - 0x1d: update_attributes - 0x1e: inventory_transaction - 0x1f: mob_equipment - 0x20: mob_armor_equipment - 0x21: interact - 0x22: block_pick_request - 0x23: entity_pick_request - 0x24: player_action - 0x26: hurt_armor - 0x27: set_entity_data - 0x28: set_entity_motion - 0x29: set_entity_link - 0x2a: set_health - 0x2b: set_spawn_position - 0x2c: animate - 0x2d: respawn - 0x2e: container_open - 0x2f: container_close - 0x30: player_hotbar - 0x31: inventory_content - 0x32: inventory_slot - 0x33: container_set_data - 0x34: crafting_data - 0x35: crafting_event - 0x36: gui_data_pick_item - 0x37: adventure_settings - 0x38: block_entity_data - 0x39: player_input - 0x3a: level_chunk - 0x3b: set_commands_enabled - 0x3c: set_difficulty - 0x3d: change_dimension - 0x3e: set_player_game_type - 0x3f: player_list - 0x40: simple_event - 0x41: event - 0x42: spawn_experience_orb - 0x43: clientbound_map_item_data - 0x44: map_info_request - 0x45: request_chunk_radius - 0x46: chunk_radius_update - 0x47: item_frame_drop_item - 0x48: game_rules_changed - 0x49: camera - 0x4a: boss_event - 0x4b: show_credits - 0x4c: available_commands - 0x4d: command_request - 0x4e: command_block_update - 0x4f: command_output - 0x50: update_trade - 0x51: update_equipment - 0x52: resource_pack_data_info - 0x53: resource_pack_chunk_data - 0x54: resource_pack_chunk_request - 0x55: transfer - 0x56: play_sound - 0x57: stop_sound - 0x58: set_title - 0x59: add_behavior_tree - 0x5a: structure_block_update - 0x5b: show_store_offer - 0x5c: purchase_receipt - 0x5d: player_skin - 0x5e: sub_client_login - 0x5f: initiate_web_socket_connection - 0x60: set_last_hurt_by - 0x61: book_edit - 0x62: npc_request - 0x63: photo_transfer - 0x64: modal_form_request - 0x65: modal_form_response - 0x66: server_settings_request - 0x67: server_settings_response - 0x68: show_profile - 0x69: set_default_game_type - 0x6a: remove_objective - 0x6b: set_display_objective - 0x6c: set_score - 0x6d: lab_table - 0x6e: update_block_synced - 0x6f: move_entity_delta - 0x70: set_scoreboard_identity - 0x71: set_local_player_as_initialized - 0x72: update_soft_enum - 0x73: network_stack_latency - 0x75: script_custom_event - 0x76: spawn_particle_effect - 0x77: available_entity_identifiers - 0x78: level_sound_event_v2 - 0x79: network_chunk_publisher_update - 0x7a: biome_definition_list - 0x7b: level_sound_event - 0x7c: level_event_generic - 0x7d: lectern_update - 0x7e: video_stream_connect - 0x7f: add_ecs_entity - 0x80: remove_ecs_entity - 0x81: client_cache_status - 0x82: on_screen_texture_animation - 0x83: map_create_locked_copy - 0x84: structure_template_data_export_request - 0x85: structure_template_data_export_response - 0x86: update_block_properties - 0x87: client_cache_blob_status - 0x88: client_cache_miss_response - 0x89: education_settings - 0x8b: multiplayer_settings - 0x8c: settings_command - 0x8d: anvil_damage - 0x8e: completed_using_item - 0x8f: network_settings - 0x90: player_auth_input - 0x91: creative_content - 0x92: player_enchant_options - 0x93: item_stack_request - 0x94: item_stack_response - 0x95: player_armor_damage - 0x97: update_player_game_type - 0x9a: position_tracking_db_request - 0x99: position_tracking_db_broadcast - 0x9c: packet_violation_warning - 0x9d: motion_prediction_hints - 0x9e: animate_entity - 0x9f: camera_shake - 0xa0: player_fog - 0xa1: correct_player_move_prediction - 0xa2: item_component - 0xa3: filter_text_packet - - params: name ? - if login: packet_login - if play_status: packet_play_status - if server_to_client_handshake: packet_server_to_client_handshake - if client_to_server_handshake: packet_client_to_server_handshake - if disconnect: packet_disconnect - if resource_packs_info: packet_resource_packs_info - if resource_pack_stack: packet_resource_pack_stack - if resource_pack_client_response: packet_resource_pack_client_response - if text: packet_text - if set_time: packet_set_time - if start_game: packet_start_game - if add_player: packet_add_player - if add_entity: packet_add_entity - if remove_entity: packet_remove_entity - if add_item_entity: packet_add_item_entity - if take_item_entity: packet_take_item_entity - if move_entity: packet_move_entity - if move_player: packet_move_player - if rider_jump: packet_rider_jump - if update_block: packet_update_block - if add_painting: packet_add_painting - if tick_sync: packet_tick_sync - if level_sound_event_old: packet_level_sound_event_old - if level_event: packet_level_event - if block_event: packet_block_event - if entity_event: packet_entity_event - if mob_effect: packet_mob_effect - if update_attributes: packet_update_attributes - if inventory_transaction: packet_inventory_transaction - if mob_equipment: packet_mob_equipment - if mob_armor_equipment: packet_mob_armor_equipment - if interact: packet_interact - if block_pick_request: packet_block_pick_request - if entity_pick_request: packet_entity_pick_request - if player_action: packet_player_action - if hurt_armor: packet_hurt_armor - if set_entity_data: packet_set_entity_data - if set_entity_motion: packet_set_entity_motion - if set_entity_link: packet_set_entity_link - if set_health: packet_set_health - if set_spawn_position: packet_set_spawn_position - if animate: packet_animate - if respawn: packet_respawn - if container_open: packet_container_open - if container_close: packet_container_close - if player_hotbar: packet_player_hotbar - if inventory_content: packet_inventory_content - if inventory_slot: packet_inventory_slot - if container_set_data: packet_container_set_data - if crafting_data: packet_crafting_data - if crafting_event: packet_crafting_event - if gui_data_pick_item: packet_gui_data_pick_item - if adventure_settings: packet_adventure_settings - if block_entity_data: packet_block_entity_data - if player_input: packet_player_input - if level_chunk: packet_level_chunk - if set_commands_enabled: packet_set_commands_enabled - if set_difficulty: packet_set_difficulty - if change_dimension: packet_change_dimension - if set_player_game_type: packet_set_player_game_type - if player_list: packet_player_list - if simple_event: packet_simple_event - if event: packet_event - if spawn_experience_orb: packet_spawn_experience_orb - if clientbound_map_item_data: packet_clientbound_map_item_data - if map_info_request: packet_map_info_request - if request_chunk_radius: packet_request_chunk_radius - if chunk_radius_update: packet_chunk_radius_update - if item_frame_drop_item: packet_item_frame_drop_item - if game_rules_changed: packet_game_rules_changed - if camera: packet_camera - if boss_event: packet_boss_event - if show_credits: packet_show_credits - if available_commands: packet_available_commands - if command_request: packet_command_request - if command_block_update: packet_command_block_update - if command_output: packet_command_output - if update_trade: packet_update_trade - if update_equipment: packet_update_equipment - if resource_pack_data_info: packet_resource_pack_data_info - if resource_pack_chunk_data: packet_resource_pack_chunk_data - if resource_pack_chunk_request: packet_resource_pack_chunk_request - if transfer: packet_transfer - if play_sound: packet_play_sound - if stop_sound: packet_stop_sound - if set_title: packet_set_title - if add_behavior_tree: packet_add_behavior_tree - if structure_block_update: packet_structure_block_update - if show_store_offer: packet_show_store_offer - if purchase_receipt: packet_purchase_receipt - if player_skin: packet_player_skin - if sub_client_login: packet_sub_client_login - if initiate_web_socket_connection: packet_initiate_web_socket_connection - if set_last_hurt_by: packet_set_last_hurt_by - if book_edit: packet_book_edit - if npc_request: packet_npc_request - if photo_transfer: packet_photo_transfer - if modal_form_request: packet_modal_form_request - if modal_form_response: packet_modal_form_response - if server_settings_request: packet_server_settings_request - if server_settings_response: packet_server_settings_response - if show_profile: packet_show_profile - if set_default_game_type: packet_set_default_game_type - if remove_objective: packet_remove_objective - if set_display_objective: packet_set_display_objective - if set_score: packet_set_score - if lab_table: packet_lab_table - if update_block_synced: packet_update_block_synced - if move_entity_delta: packet_move_entity_delta - if set_scoreboard_identity: packet_set_scoreboard_identity - if set_local_player_as_initialized: packet_set_local_player_as_initialized - if update_soft_enum: packet_update_soft_enum - if network_stack_latency: packet_network_stack_latency - if script_custom_event: packet_script_custom_event - if spawn_particle_effect: packet_spawn_particle_effect - if available_entity_identifiers: packet_available_entity_identifiers - if level_sound_event_v2: packet_level_sound_event_v2 - if network_chunk_publisher_update: packet_network_chunk_publisher_update - if biome_definition_list: packet_biome_definition_list - if level_sound_event: packet_level_sound_event - if level_event_generic: packet_level_event_generic - if lectern_update: packet_lectern_update - if video_stream_connect: packet_video_stream_connect - if add_ecs_entity: packet_add_ecs_entity - if remove_ecs_entity: packet_remove_ecs_entity - if client_cache_status: packet_client_cache_status - if on_screen_texture_animation: packet_on_screen_texture_animation - if map_create_locked_copy: packet_map_create_locked_copy - if structure_template_data_export_request: packet_structure_template_data_export_request - if structure_template_data_export_response: packet_structure_template_data_export_response - if update_block_properties: packet_update_block_properties - if client_cache_blob_status: packet_client_cache_blob_status - if client_cache_miss_response: packet_client_cache_miss_response - if education_settings: packet_education_settings - if multiplayer_settings: packet_multiplayer_settings - if settings_command: packet_settings_command - if anvil_damage: packet_anvil_damage - if completed_using_item: packet_completed_using_item - if network_settings: packet_network_settings - if player_auth_input: packet_player_auth_input - if creative_content: packet_creative_content - if player_enchant_options: packet_player_enchant_options - if item_stack_request: packet_item_stack_request - if item_stack_response: packet_item_stack_response - if player_armor_damage: packet_player_armor_damage - if update_player_game_type: packet_update_player_game_type - if position_tracking_db_request: packet_position_tracking_db_request - if position_tracking_db_broadcast: packet_position_tracking_db_broadcast - if packet_violation_warning: packet_packet_violation_warning - if motion_prediction_hints: packet_motion_prediction_hints - if animate_entity: packet_animate_entity - if camera_shake: packet_camera_shake - if player_fog: packet_player_fog - if correct_player_move_prediction: packet_correct_player_move_prediction - if item_component: packet_item_component - if filter_text_packet: packet_filter_text_packet diff --git a/data/new/proto.yml b/data/new/proto.yml index 0a3bd85..f296075 100644 --- a/data/new/proto.yml +++ b/data/new/proto.yml @@ -1,4 +1,9 @@ -# Created from MiNET docs +# Created from MiNET and gophertunnel docs +# The version below is the latest version this protocol schema was updated for. +# The output protocol.json will be in the folder for the version +!version: 1.16.201 + +# Some ProtoDef aliases string: ["pstring",{"countType":"varint"}] ByteArray: ["buffer",{"countType":"varint"}] SignedByteArray: ["buffer",{"countType":"zigzag32"}] @@ -12,8 +17,10 @@ byterot: native MapInfo: native nbt: native +# load the packet map file !import: packet_map.yml +#todo: docs !StartDocs: Packets # # Login Sequence diff --git a/data/protocol.json b/data/protocol.json deleted file mode 100644 index f3affcd..0000000 --- a/data/protocol.json +++ /dev/null @@ -1,2517 +0,0 @@ -{ - "types": { - "string": [ - "pstring", - { - "countType": "i16" - } - ], - "lstring": [ - "pstring", - { - "countType": "li16" - } - ], - "vector3": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vector2": [ - "container", - [ - { - "name": "x", - "type": "f32" - }, - { - "name": "y", - "type": "f32" - } - ] - ], - "playerlocation": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "yaw", - "type": "f32" - }, - { - "name": "pitch", - "type": "f32" - }, - { - "name": "headYaw", - "type": "f32" - } - ] - ] - } - ], - "encapsulated_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0xfe": "mcpe" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "mcpe": "mcpe_packet" - } - } - ] - } - ] - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0x01": "game_login", - "0x02": "play_status", - "0x03": "server_to_client_handshake", - "0x04": "client_to_server_handshake", - "0x05": "disconnect", - "0x06": "resource_packs_info", - "0x07": "resource_pack_stack", - "0x08": "resource_pack_client_response", - "0x09": "text", - "0x0a": "set_time", - "0x0b": "start_game", - "0x0c": "add_player", - "0x0d": "add_entity", - "0x0e": "remove_entity", - "0x0f": "add_item_entity", - "0x11": "take_item_entity", - "0x12": "move_entity", - "0x13": "move_player", - "0x14": "rider_jump", - "0x15": "update_block", - "0x16": "add_painting", - "0x17": "explode", - "0x18": "level_sound_event_old", - "0x19": "level_event", - "0x1a": "block_event", - "0x1b": "entity_event", - "0x1c": "mob_effect", - "0x1d": "update_attributes", - "0x1e": "inventory_transaction", - "0x1f": "mob_equipment", - "0x20": "mob_armor_equipment", - "0x21": "interact", - "0x22": "block_pick_request", - "0x23": "entity_pick_request", - "0x24": "player_action", - "0x25": "entity_fall", - "0x26": "hurt_armor", - "0x27": "set_entity_data", - "0x28": "set_entity_motion", - "0x29": "set_entity_link", - "0x2a": "set_health", - "0x2b": "set_spawn_position", - "0x2c": "animate", - "0x2d": "respawn", - "0x2e": "container_open", - "0x2f": "container_close", - "0x30": "player_hotbar", - "0x31": "inventory_content", - "0x32": "inventory_slot", - "0x33": "container_set_data", - "0x34": "crafting_data", - "0x35": "crafting_event", - "0x36": "gui_data_pick_item", - "0x37": "adventure_settings", - "0x38": "block_entity_data", - "0x39": "player_input", - "0x3a": "full_chunk_data", - "0x3b": "set_commands_enabled", - "0x3c": "set_difficulty", - "0x3d": "change_dimension", - "0x3e": "set_player_game_type", - "0x3f": "player_list", - "0x40": "simple_event", - "0x41": "telemetry_event", - "0x42": "spawn_experience_orb", - "0x43": "clientbound_map_item_data_", - "0x44": "map_info_request", - "0x45": "request_chunk_radius", - "0x46": "chunk_radius_update", - "0x47": "item_frame_drop_item", - "0x48": "game_rules_changed", - "0x49": "camera", - "0x4a": "boss_event", - "0x4b": "show_credits", - "0x4c": "available_commands", - "0x4d": "command_request", - "0x4e": "command_block_update", - "0x4f": "command_output", - "0x50": "update_trade", - "0x51": "update_equipment", - "0x52": "resource_pack_data_info", - "0x53": "resource_pack_chunk_data", - "0x54": "resource_pack_chunk_request", - "0x55": "transfer", - "0x56": "play_sound", - "0x57": "stop_sound", - "0x58": "set_title", - "0x59": "add_behavior_tree", - "0x5a": "structure_block_update", - "0x5b": "show_store_offer", - "0x5c": "purchase_receipt", - "0x5d": "player_skin", - "0x5e": "sub_client_login", - "0x5f": "initiate_web_socket_connection", - "0x60": "set_last_hurt_by", - "0x61": "book_edit", - "0x62": "npc_request", - "0x63": "photo_transfer", - "0x64": "modal_form_request", - "0x65": "modal_form_response", - "0x66": "server_settings_request", - "0x67": "server_settings_response", - "0x68": "show_profile", - "0x69": "set_default_game_type", - "0x6a": "remove_objective", - "0x6b": "set_display_objective", - "0x6c": "set_score", - "0x6d": "lab_table", - "0x6e": "update_block_synced", - "0x6f": "move_entity_delta", - "0x70": "set_scoreboard_identity_packet", - "0x71": "set_local_player_as_initialized_packet", - "0x72": "update_soft_enum_packet", - "0x73": "network_stack_latency_packet", - "0x75": "script_custom_event_packet", - "0x76": "spawn_particle_effect", - "0x77": "available_entity_identifiers", - "0x78": "level_sound_event_v2", - "0x79": "network_chunk_publisher_update", - "0x7a": "biome_definition_list", - "0x7b": "level_sound_event" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "game_login": "packet_game_login", - "play_status": "packet_play_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "explode": "packet_explode", - "level_sound_event_old": "packet_level_sound_event_old", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "inventory_transaction": "packet_inventory_transaction", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "block_pick_request": "packet_block_pick_request", - "entity_pick_request": "packet_entity_pick_request", - "player_action": "packet_player_action", - "entity_fall": "packet_entity_fall", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "player_hotbar": "packet_player_hotbar", - "inventory_content": "packet_inventory_content", - "inventory_slot": "packet_inventory_slot", - "container_set_data": "packet_container_set_data", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "gui_data_pick_item": "packet_gui_data_pick_item", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "full_chunk_data": "packet_full_chunk_data", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "simple_event": "packet_simple_event", - "telemetry_event": "packet_telemetry_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data_": "packet_clientbound_map_item_data_", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_frame_drop_item": "packet_item_frame_drop_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "boss_event": "packet_boss_event", - "show_credits": "packet_show_credits", - "available_commands": "packet_available_commands", - "command_request": "packet_command_request", - "command_block_update": "packet_command_block_update", - "command_output": "packet_command_output", - "update_trade": "packet_update_trade", - "update_equipment": "packet_update_equipment", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request", - "transfer": "packet_transfer", - "play_sound": "packet_play_sound", - "stop_sound": "packet_stop_sound", - "set_title": "packet_set_title", - "add_behavior_tree": "packet_add_behavior_tree", - "structure_block_update": "packet_structure_block_update", - "show_store_offer": "packet_show_store_offer", - "purchase_receipt": "packet_purchase_receipt", - "player_skin": "packet_player_skin", - "sub_client_login": "packet_sub_client_login", - "initiate_web_socket_connection": "packet_initiate_web_socket_connection", - "set_last_hurt_by": "packet_set_last_hurt_by", - "book_edit": "packet_book_edit", - "npc_request": "packet_npc_request", - "photo_transfer": "packet_photo_transfer", - "modal_form_request": "packet_modal_form_request", - "modal_form_response": "packet_modal_form_response", - "server_settings_request": "packet_server_settings_request", - "server_settings_response": "packet_server_settings_response", - "show_profile": "packet_show_profile", - "set_default_game_type": "packet_set_default_game_type", - "remove_objective": "packet_remove_objective", - "set_display_objective": "packet_set_display_objective", - "set_score": "packet_set_score", - "lab_table": "packet_lab_table", - "update_block_synced": "packet_update_block_synced", - "move_entity_delta": "packet_move_entity_delta", - "set_scoreboard_identity_packet": "packet_set_scoreboard_identity_packet", - "set_local_player_as_initialized_packet": "packet_set_local_player_as_initialized_packet", - "update_soft_enum_packet": "packet_update_soft_enum_packet", - "network_stack_latency_packet": "packet_network_stack_latency_packet", - "script_custom_event_packet": "packet_script_custom_event_packet", - "spawn_particle_effect": "packet_spawn_particle_effect", - "available_entity_identifiers": "packet_available_entity_identifiers", - "level_sound_event_v2": "packet_level_sound_event_v2", - "network_chunk_publisher_update": "packet_network_chunk_publisher_update", - "biome_definition_list": "packet_biome_definition_list", - "level_sound_event": "packet_level_sound_event" - } - } - ] - } - ] - ], - "packet_game_login": [ - "container", - [ - { - "name": "protocol", - "type": "i32" - }, - { - "name": "edition", - "type": "i8" - }, - { - "name": "body", - "type": [ - "buffer", - { - "countType": "varint" - } - ] - } - ] - ], - "packet_play_status": [ - "container", - [ - { - "name": "status", - "type": "i32" - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "token", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "behahaviorpackinfos", - "type": "varint" - }, - { - "name": "resourcepackinfos", - "type": "varint" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behaviorpackidversions", - "type": "varint" - }, - { - "name": "resourcepackidversions", - "type": "varint" - }, - { - "name": "is_experimental", - "type": "bool" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": "u8" - }, - { - "name": "resourcepackids", - "type": "varint" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": "i8" - }, - { - "name": "source", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "1": "string", - "3": "string" - }, - "default": "void" - } - ] - }, - { - "name": "message", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "0": "string", - "1": "string", - "2": "string", - "3": "string", - "4": "string", - "5": "string" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "varint" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "player_gamemode", - "type": "varint" - }, - - { - "name": "spawn", - "type": "vector3" - }, - - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - - { - "name": "seed", - "type": "varint" - }, - { - "name": "dimension", - "type": "varint" - }, - { - "name": "generator", - "type": "varint" - }, - { - "name": "gamemode", - "type": "varint" - }, - { - "name": "difficulty", - "type": "varint" - }, - - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - }, - - { - "name": "has_achievements_disabled", - "type": "bool" - }, - { - "name": "time", - "type": "varint" - }, - { - "name": "edu_mode", - "type": "bool" - }, - { - "name": "has_edu_features_enabled", - "type": "bool" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightning_level", - "type": "lf32" - }, - { - "name": "has_confirmed_platform_locked_content", - "type": "bool" - }, - { - "name": "is_multiplayer", - "type": "bool" - }, - { - "name": "broadcast_to_lan", - "type": "bool" - }, - { - "name": "xbox_live_broadcast_mode", - "type": "varint" - }, - { - "name": "platform_broadcast_mode", - "type": "varint" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - - { - "name": "u8", - "type": "u8" - }, - - { - "name": "bonus_chest", - "type": "bool" - }, - { - "name": "map_enabled", - "type": "bool" - }, - { - "name": "permission_level", - "type": "varint" - }, - - { - "name": "server_chunk_tick_range", - "type": "i32" - }, - - { - "name": "has_locked_behavior_pack", - "type": "bool" - }, - { - "name": "has_locked_resource_pack", - "type": "bool" - }, - - { - "name": "is_from_locked_world_template", - "type": "bool" - }, - { - "name": "use_msa_gamertags_only", - "type": "bool" - }, - { - "name": "is_from_world_template", - "type": "bool" - }, - { - "name": "is_world_template_option_locked", - "type": "bool" - }, - { - "name": "use_v1_villagers", - "type": "bool" - }, - - { - "name": "level_id", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - }, - { - "name": "premium_world_template_id", - "type": "string" - }, - { - "name": "is_trial", - "type": "bool" - }, - { - "name": "current_tick", - "type": "i64" - }, - { - "name": "enchantment_seed", - "type": "varint" - }, - - { - "name": "blockstates", - "type": "u8" - }, - { - "name": "itemtable", - "type": "u8" - }, - { - "name": "multiplayer_correlation_id", - "type": "string" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "username", - "type": "string" - }, - - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - - { - "name": "position", - "type": "vector3" - }, - { - "name": "motion", - "type": "vector3" - }, - - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - - { - "name": "item", - "type": "u8" - }, - { - "name": "metadata", - "type": "u8" - }, - - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - - { - "name": "user_id", - "type": "i64" - }, - { - "name": "links", - "type": "u8" - }, - { - "name": "device_id", - "type": "string" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "is_from_fishing", - "type": "bool" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "target", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "position", - "type": "playerlocation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": "u8" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "other_runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_rider_jump": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "block_priority", - "type": "varint" - }, - { - "name": "storage", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "direction", - "type": "varint" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_explode": [ - "container", - [ - { - "name": "position", - "type": "vector3" - }, - { - "name": "radius", - "type": "varint" - }, - { - "name": "records", - "type": "varint" - } - ] - ], - "packet_level_sound_event_old": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "block_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "varint" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "data", - "type": "varint" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "case_1", - "type": "varint" - }, - { - "name": "case_2", - "type": "varint" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "data", - "type": "varint" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "varint" - }, - { - "name": "amplifier", - "type": "varint" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "varint" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "attributes", - "type": "varint" - } - ] - ], - "packet_inventory_transaction": [ - "container", - [ - { - "name": "transaction_type", - "type": "varint" - }, - { - "name": "transaction", - "type": "varint" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "windows_id", - "type": "u8" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "helmet", - "type": "varint" - }, - { - "name": "chestplate", - "type": "varint" - }, - { - "name": "leggings", - "type": "varint" - }, - { - "name": "boots", - "type": "varint" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": "u8" - }, - { - "name": "target_runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_block_pick_request": [ - "container", - [ - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - }, - { - "name": "add_user_data", - "type": "bool" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_entity_pick_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "u64" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "action_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "face", - "type": "varint" - } - ] - ], - "packet_entity_fall": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "fall_distance", - "type": "lf32" - }, - { - "name": "is_in_void", - "type": "bool" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "varint" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "metadata", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "velocity", - "type": "vector3" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "ridden_id", - "type": "varint" - }, - { - "name": "rider_id", - "type": "varint" - }, - { - "name": "link_type", - "type": "u8" - }, - { - "name": "unknown", - "type": "u8" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "varint" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "spawn_type", - "type": "varint" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "forced", - "type": "bool" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - } - ] - ], - "packet_player_hotbar": [ - "container", - [ - { - "name": "selected_slot", - "type": "varint" - }, - { - "name": "window_id", - "type": "u8" - }, - { - "name": "select_slot_", - "type": "bool" - } - ] - ], - "packet_inventory_content": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - }, - { - "name": "input", - "type": "varint" - } - ] - ], - "packet_inventory_slot": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "varint" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "property", - "type": "varint" - }, - { - "name": "value", - "type": "varint" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "varint" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "recipe_type", - "type": "varint" - }, - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": "varint" - }, - { - "name": "result", - "type": "varint" - } - ] - ], - "packet_gui_data_pick_item": [ - "container", - [] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "i64" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "jumping", - "type": "bool" - }, - { - "name": "sneaking", - "type": "bool" - } - ] - ], - "packet_full_chunk_data": [ - "container", - [ - { - "name": "chunk_x", - "type": "varint" - }, - { - "name": "chunk_z", - "type": "varint" - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "respawn", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "varint" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "varint" - } - ] - ], - "packet_simple_event": [ - "container", - [ - { - "name": "event_type", - "type": "u8" - } - ] - ], - "packet_telemetry_event": [ - "container", - [ - { - "name": "entity_id_self", - "type": "varint" - }, - { - "name": "unk1", - "type": "varint" - }, - { - "name": "unk2", - "type": "u8" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vector3" - }, - { - "name": "count", - "type": "varint" - } - ] - ], - "packet_clientbound_map_item_data_": [ - "container", - [ - { - "name": "mapinfo", - "type": "varint" - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "varint" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "varint" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "varint" - } - ] - ], - "packet_item_frame_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - } - ] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "u8" - } - ] - ], - "packet_camera": [ - "container", - [ - { - "name": "unknown1", - "type": "varint" - }, - { - "name": "unknown2", - "type": "varint" - } - ] - ], - "packet_boss_event": [ - "container", - [ - { - "name": "boss_entity_id", - "type": "varint" - }, - { - "name": "event_type", - "type": "varint" - } - ] - ], - "packet_show_credits": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "status", - "type": "varint" - } - ] - ], - "packet_available_commands": [ - "container", - [] - ], - "packet_command_request": [ - "container", - [ - { - "name": "command", - "type": "string" - }, - { - "name": "command_type", - "type": "varint" - }, - { - "name": "unknown_uuid", - "type": "string" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "unknown", - "type": "bool" - } - ] - ], - "packet_command_block_update": [ - "container", - [ - { - "name": "is_block", - "type": "bool" - } - ] - ], - "packet_command_output": [ - "container", - [] - ], - "packet_update_trade": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "window_type", - "type": "u8" - }, - { - "name": "unknown0", - "type": "varint" - }, - { - "name": "unknown1", - "type": "varint" - }, - { - "name": "unknown2", - "type": "varint" - }, - { - "name": "is_willing", - "type": "bool" - }, - { - "name": "trader_entity_id", - "type": "varint" - }, - { - "name": "player_entity_id", - "type": "varint" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_update_equipment": [ - "container", - [ - { - "name": "window_id", - "type": "u8" - }, - { - "name": "window_type", - "type": "u8" - }, - { - "name": "unknown", - "type": "u8" - }, - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "max_chunk_size", - "type": "u32" - }, - { - "name": "chunk_count", - "type": "u32" - }, - { - "name": "compressed_package_size", - "type": "u64" - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "u32" - }, - { - "name": "progress", - "type": "u64" - }, - { - "name": "length", - "type": "u32" - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "u32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "server_address", - "type": "string" - }, - { - "name": "port", - "type": "u8" - } - ] - ], - "packet_play_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "volume", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - } - ] - ], - "packet_stop_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "stop_all", - "type": "bool" - } - ] - ], - "packet_set_title": [ - "container", - [ - { - "name": "type", - "type": "varint" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "fade_in_time", - "type": "varint" - }, - { - "name": "stay_time", - "type": "varint" - }, - { - "name": "fade_out_time", - "type": "varint" - } - ] - ], - "packet_add_behavior_tree": [ - "container", - [ - { - "name": "behaviortree", - "type": "string" - } - ] - ], - "packet_structure_block_update": [ - "container", - [] - ], - "packet_show_store_offer": [ - "container", - [ - { - "name": "unknown0", - "type": "string" - }, - { - "name": "unknown1", - "type": "bool" - } - ] - ], - "packet_purchase_receipt": [ - "container", - [] - ], - "packet_player_skin": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "skin_id", - "type": "string" - }, - { - "name": "skin_name", - "type": "string" - }, - { - "name": "old_skin_name", - "type": "string" - } - ] - ], - "packet_sub_client_login": [ - "container", - [] - ], - "packet_initiate_web_socket_connection": [ - "container", - [ - { - "name": "server", - "type": "string" - } - ] - ], - "packet_set_last_hurt_by": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_book_edit": [ - "container", - [] - ], - "packet_npc_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "unknown0", - "type": "u8" - }, - { - "name": "unknown1", - "type": "string" - }, - { - "name": "unknown2", - "type": "u8" - } - ] - ], - "packet_photo_transfer": [ - "container", - [ - { - "name": "file_name", - "type": "string" - }, - { - "name": "image_data", - "type": "string" - }, - { - "name": "unknown2", - "type": "string" - } - ] - ], - "packet_modal_form_request": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_modal_form_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_server_settings_request": [ - "container", - [] - ], - "packet_server_settings_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_show_profile": [ - "container", - [ - { - "name": "xuid", - "type": "string" - } - ] - ], - "packet_set_default_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "varint" - } - ] - ], - "packet_remove_objective": [ - "container", - [ - { - "name": "objective_name", - "type": "string" - } - ] - ], - "packet_set_display_objective": [ - "container", - [ - { - "name": "display_slot", - "type": "string" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "criteria_name", - "type": "string" - }, - { - "name": "sort_order", - "type": "varint" - } - ] - ], - "packet_set_score": [ - "container", - [ - { - "name": "entries", - "type": "u8" - } - ] - ], - "packet_lab_table": [ - "container", - [ - { - "name": "useless_byte", - "type": "u8" - }, - { - "name": "lab_table_x", - "type": "varint" - }, - { - "name": "lab_table_y", - "type": "varint" - }, - { - "name": "lab_table_z", - "type": "varint" - }, - { - "name": "reaction_type", - "type": "u8" - } - ] - ], - "packet_update_block_synced": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "block_priority", - "type": "varint" - }, - { - "name": "data_layer_id", - "type": "varint" - }, - { - "name": "unknown0", - "type": "varint" - }, - { - "name": "unknown1", - "type": "varint" - } - ] - ], - "packet_move_entity_delta": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "flags", - "type": "u8" - } - ] - ], - "packet_set_scoreboard_identity_packet": [ - "container", - [ - { - "name": "entries", - "type": "u8" - } - ] - ], - "packet_set_local_player_as_initialized_packet": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_update_soft_enum_packet": [ - "container", - [] - ], - "packet_network_stack_latency_packet": [ - "container", - [ - { - "name": "timestamp", - "type": "i64" - }, - { - "name": "need_response", - "type": "bool" - } - ] - ], - "packet_script_custom_event_packet": [ - "container", - [ - { - "name": "event_name", - "type": "string" - }, - { - "name": "event_data", - "type": "string" - } - ] - ], - "packet_spawn_particle_effect": [ - "container", - [ - { - "name": "dimension_id", - "type": "u8" - }, - { - "name": "entity_id", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "particle_name", - "type": "string" - } - ] - ], - "packet_available_entity_identifiers": [ - "container", - [ - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_level_sound_event_v2": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "block_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_network_chunk_publisher_update": [ - "container", - [ - { - "name": "coordinates", - "type": "varint" - }, - { - "name": "radius", - "type": "varint" - } - ] - ], - "packet_biome_definition_list": [ - "container", - [ - { - "name": "namedtag", - "type": "varint" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "varint" - }, - { - "name": "position", - "type": "vector3" - }, - { - "name": "block_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ] - } -} diff --git a/data/provider.js b/data/provider.js new file mode 100644 index 0000000..3475db3 --- /dev/null +++ b/data/provider.js @@ -0,0 +1,45 @@ +const { Versions } = require('../src/options') +const { getFiles } = require('../src/datatypes/util') + +const fileMap = {} + +// Walks all the directories for each of the supported versions in options.js +// then builds a file map for each version +// { 'protocol.json': { '1.16.200': '1.16.200/protocol.json', '1.16.210': '1.16.210/...' } } +function loadVersions() { + for (const version in Versions) { + let files = [] + try { + files = getFiles(__dirname + '/' + version) + } catch {} + for (let file of files) { + const rfile = file.replace(__dirname + '/' + version + '/', '') + fileMap[rfile] ??= [] + fileMap[rfile].push([Versions[version], file]) + fileMap[rfile].sort().reverse() + } + } +} + +module.exports = (protocolVersion) => { + return { + // Returns the most recent file based on the specified protocolVersion + // e.g. if `version` is 1.16 and a file for 1.16 doesn't exist, load from 1.15 file + getPath(file) { + if (!fileMap[file]) { + throw Error('Unknown file ' + file) + } + for (const [ pver, path ] of fileMap[file]) { + if (pver <= protocolVersion) { + // console.debug('for', file, 'returining', path) + return path + } + } + throw Error('unknown file ' + file) + } + } +} + +loadVersions() +// console.log('file map', fileMap) +// module.exports(Versions['1.16.210']).open('creativeitems.json') \ No newline at end of file diff --git a/samples/clientTest.js b/examples/clientTest.js similarity index 100% rename from samples/clientTest.js rename to examples/clientTest.js diff --git a/examples/createRelay.js b/examples/createRelay.js new file mode 100644 index 0000000..008027b --- /dev/null +++ b/examples/createRelay.js @@ -0,0 +1,38 @@ +const { Relay } = require('../src/relay') + +function createRelay() { + console.log('Creating relay') + /** + * Example to create a non-transparent proxy (or 'Relay') connection to destination server + * In Relay we de-code and re-encode packets + */ + const relay = new Relay({ + /* Hostname and port for clients to listen to */ + hostname: '0.0.0.0', + port: 19130, + /** + * Who does the authentication + * If set to `client`, all connecting clients will be sent a message with a link to authenticate + * If set to `server`, the server will authenticate and only one client will be able to join + * (Default) If set to `none`, no authentication will be done + */ + auth: 'server', + + /** + * Sets if packets will automatically be forwarded. If set to false, you must listen for on('packet') + * events and + */ + auto: true, + + /* Where to send upstream packets to */ + destination: { + hostname: '127.0.0.1', + port: 19132, + // encryption: true + } + }) + + relay.create() +} + +createRelay() \ No newline at end of file diff --git a/examples/chunk b/examples/old/chunk similarity index 100% rename from examples/chunk rename to examples/old/chunk diff --git a/examples/client.js b/examples/old/client.js similarity index 100% rename from examples/client.js rename to examples/old/client.js diff --git a/examples/deserialize.js b/examples/old/deserialize.js similarity index 100% rename from examples/deserialize.js rename to examples/old/deserialize.js diff --git a/examples/server.js b/examples/old/server.js similarity index 100% rename from examples/server.js rename to examples/old/server.js diff --git a/examples/server_simple.js b/examples/old/server_simple.js similarity index 100% rename from examples/server_simple.js rename to examples/old/server_simple.js diff --git a/samples/serverTest.js b/examples/serverTest.js similarity index 69% rename from samples/serverTest.js rename to examples/serverTest.js index ac50b53..b03b27c 100644 --- a/samples/serverTest.js +++ b/examples/serverTest.js @@ -1,8 +1,9 @@ process.env.DEBUG = 'minecraft-protocol raknet' const { Server } = require('../src/server') -const CreativeItems = require('../data/creativeitems.json') +// const CreativeItems = require('../data/creativeitems.json') const NBT = require('prismarine-nbt') const fs = require('fs') +const DataProvider = require('../data/provider') let server = new Server({ @@ -10,6 +11,14 @@ let server = new Server({ }) server.create('0.0.0.0', 19132) +function getPath(packetPath) { + return DataProvider(server.options.protocolVersion).getPath(packetPath) +} + +function get(packetPath) { + return require(getPath('sample/' + packetPath)) +} + let ran = false server.on('connect', ({ client }) => { @@ -50,35 +59,35 @@ server.on('connect', ({ client }) => { client.queue('inventory_slot', {"inventory_id":120,"slot":i,"uniqueid":0,"item":{"network_id":0}}) } - client.queue('inventory_transaction', require('../src/packets/inventory_transaction.json')) - client.queue('player_list', require('../src/packets/player_list.json')) - client.queue('start_game', require('../src/packets/start_game.json')) + client.queue('inventory_transaction', get('packets/inventory_transaction.json')) + client.queue('player_list', get('packets/player_list.json')) + client.queue('start_game', get('packets/start_game.json')) client.queue('item_component', {"entries":[]}) - client.queue('set_spawn_position', require('../src/packets/set_spawn_position.json')) + client.queue('set_spawn_position', get('packets/set_spawn_position.json')) client.queue('set_time', { time: 5433771 }) client.queue('set_difficulty', { difficulty: 1 }) client.queue('set_commands_enabled', { enabled: true }) - client.queue('adventure_settings', require('../src/packets/adventure_settings.json')) + client.queue('adventure_settings', get('packets/adventure_settings.json')) - client.queue('biome_definition_list', require('../src/packets/biome_definition_list.json')) - client.queue('available_entity_identifiers', require('../src/packets/available_entity_identifiers.json')) + client.queue('biome_definition_list', get('packets/biome_definition_list.json')) + client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) - client.queue('update_attributes', require('../src/packets/update_attributes.json')) - client.queue('creative_content', require('../src/packets/creative_content.json')) - client.queue('inventory_content', require('../src/packets/inventory_content.json')) + client.queue('update_attributes', get('packets/update_attributes.json')) + client.queue('creative_content', get('packets/creative_content.json')) + client.queue('inventory_content', get('packets/inventory_content.json')) client.queue('player_hotbar', {"selected_slot":3,"window_id":0,"select_slot":true}) - client.queue('crafting_data', require('../src/packets/crafting_data.json')) - client.queue('available_commands', require('../src/packets/available_commands.json')) + client.queue('crafting_data', get('packets/crafting_data.json')) + client.queue('available_commands', get('packets/available_commands.json')) client.queue('chunk_radius_update', {"chunk_radius":5}) - client.queue('set_entity_data', require('../src/packets/set_entity_data.json')) + client.queue('set_entity_data', get('packets/set_entity_data.json')) - client.queue('game_rules_changed', require('../src/packets/game_rules_changed.json')) + client.queue('game_rules_changed', get('packets/game_rules_changed.json')) client.queue('respawn', {"x":646.9405517578125,"y":65.62001037597656,"z":77.86255645751953,"state":0,"runtime_entity_id":0}) - for (const file of fs.readdirSync('../src/chunks')) { - const buffer = Buffer.from(fs.readFileSync('../src/chunks/' + file, 'utf8'), 'hex') + for (const file of fs.readdirSync(`../data/${server.options.version}/sample/chunks`)) { + const buffer = Buffer.from(fs.readFileSync(`../data/${server.options.version}/sample/chunks/` + file, 'utf8'), 'hex') // console.log('Sending chunk', chunk) client.sendBuffer(buffer) } diff --git a/src/auth/chains.js b/src/auth/chains.js index 5083a03..20ded36 100644 --- a/src/auth/chains.js +++ b/src/auth/chains.js @@ -52,6 +52,8 @@ function verifyAuth(chain) { console.log('verified with mojang key!', x5u) } + // TODO: Handle `didVerify` = false + pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u finalKey = decoded.identityPublicKey || finalKey // non pem data = { ...data, ...decoded } @@ -87,22 +89,22 @@ function encodeLoginJWT(localChain, mojangChain) { module.exports = { encodeLoginJWT, decodeLoginJWT } -function testServer() { - const loginPacket = require('./login.json') +// function testServer() { +// const loginPacket = require('./login.json') - // console.log(loginPacket) - const authChains = JSON.parse(loginPacket.data.chain) - const skinChain = loginPacket.data.clientData +// // console.log(loginPacket) +// const authChains = JSON.parse(loginPacket.data.chain) +// const skinChain = loginPacket.data.clientData - try { - var { data, chain } = decodeLoginJWT(authChains.chain, skinChain) - } catch (e) { - console.error(e) - throw new Error('Failed to verify user') - } +// try { +// var { data, chain } = decodeLoginJWT(authChains.chain, skinChain) +// } catch (e) { +// console.error(e) +// throw new Error('Failed to verify user') +// } - console.log('Authed') - // console.log(loginPacket) -} +// console.log('Authed') +// // console.log(loginPacket) +// } -// testServer() \ No newline at end of file +// // testServer() \ No newline at end of file diff --git a/src/auth/encryption.js b/src/auth/encryption.js index d758f41..21ebbdb 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -2,11 +2,15 @@ const JWT = require('jsonwebtoken') const crypto = require('crypto') const { Ber } = require('asn1') const ec_pem = require('ec-pem') +const fs = require('fs') +const DataProvider = require('../../data/provider') const SALT = '🧂' const curve = 'secp384r1' function Encrypt(client, server, options) { + const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') + client.ecdhKeyPair = crypto.createECDH(curve) client.ecdhKeyPair.generateKeys() client.clientX509 = writeX509PublicKey(client.ecdhKeyPair.getPublicKey()) @@ -84,7 +88,6 @@ function Encrypt(client, server, options) { } client.on('server.client_handshake', startClientboundEncryption) - client.on('client.server_handshake', startServerboundEncryption) client.createClientChain = (mojangKey) => { @@ -118,7 +121,7 @@ function Encrypt(client, server, options) { SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', SkinData: 'AAAAAA==', SkinResourcePatch: 'ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfMTI4eDEyOCIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfMTI4eDEyOF9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICJhbmltYXRlZF9mYWNlIiA6ICJnZW9tZXRyeS5hbmltYXRlZF9mYWNlX3BlcnNvbmEtZTE5OTY3MmE4YzFhODdlMC0wIiwKICAgICAgImRlZmF1bHQiIDogImdlb21ldHJ5LnBlcnNvbmFfZTE5OTY3MmE4YzFhODdlMC0wIgogICB9Cn0K', - SkinGeometryData: require('./geom'), + SkinGeometryData: skinGeom, "SkinImageHeight": 1, "SkinImageWidth": 1, "ArmSize": "wide", diff --git a/src/auth/tests/encrypt.js b/src/auth/tests/encrypt.js deleted file mode 100644 index e5aca37..0000000 --- a/src/auth/tests/encrypt.js +++ /dev/null @@ -1,232 +0,0 @@ -const crypto = require('crypto') -const JWT = require('jsonwebtoken') -const constants = require('./constants') -const { Ber } = require('asn1') -const ec_pem = require('ec-pem'); - -// function Encrypt(client, options) { -// this.startClientboundEncryption = (pubKeyBuf) => { - -// } -// client.on('start_encrypt', this.startClientboundEncryption) -// } - -// module.exports = Encrypt - - -// Server -> Client : sent right after the client sends us a LOGIN_PACKET so -// we can start the encryption process -// @param {key} - The key from the client Login Packet final JWT chain -function startClientboundEncryption(pubKeyBuf) { - // create our ecdh keypair - const type = 'secp256k1' - const alice = crypto.createECDH(type) - const aliceKey = alice.generateKeys() - const alicePublicKey = aliceKey.toString('base64') - const alicePrivateKey = mcPubKeyToPem(alice.getPrivateKey('base64')) - // get our secret key hex encoded - // const aliceSecret = alice.computeSecret(pubKeyBuf, null, 'hex') - - // (yawkat:) - // From the public key of the remote and the private key of the local, - // a shared secret is generated using ECDH. The secret key bytes are - // then computed as sha256(server_token + shared_secret). These secret - // key bytes are 32 bytes long. - const salt = Buffer.from('', 'utf-8') - let secret = crypto.createHash('sha256').update(Buffer.concat([salt, pubKeyBuf])).digest() - console.log('alice', alicePrivateKey) - const pem = mcPubKeyToPem(alice.getPrivateKey().toString('base64')) - console.log('pem', pem) - - const token = JWT.sign({ - salt, - signedToken: alicePublicKey - }, pem, { algorithm: 'ES384' }) - - console.log('Token', token) - - // get our Secret Bytes from the secret key - - - // alice.setPrivateKey( - // crypto.createHash('sha256').update('alice', 'utf8').digest() - // ) - - // using (var sha = SHA256.Create()) - // { - // secret = sha.ComputeHash(secretPrepend.Concat(agreement.CalculateAgreement(remotePublicKey).ToByteArrayUnsigned()).ToArray()); - // } - - - - const bob = crypto.createECDH('secp256k1'); - - - // URI x5u = URI.create(Base64.getEncoder().encodeToString(serverKeyPair.getPublic().getEncoded())); - - // JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().claim("salt", Base64.getEncoder().encodeToString(token)).build(); - // SignedJWT jwt = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.ES384).x509CertURL(x5u).build(), claimsSet); - - // signJwt(jwt, (ECPrivateKey) serverKeyPair.getPrivate()); - - // return jwt; -} - -function testECDH() { - const crypto = require('crypto') - const alice = crypto.createECDH('secp256k1') - const bob = crypto.createECDH('secp256k1') - - // Note: This is a shortcut way to specify one of Alice's previous private - // keys. It would be unwise to use such a predictable private key in a real - // application. - alice.setPrivateKey( - crypto.createHash('sha256').update('alice', 'utf8').digest() - ); - - // Bob uses a newly generated cryptographically strong - // pseudorandom key pair bob.generateKeys(); - - const alice_secret = alice.computeSecret(bob.getPublicKey(), null, 'hex') - const bob_secret = bob.computeSecret(alice.getPublicKey(), null, 'hex') - - // alice_secret and bob_secret should be the same shared secret value - console.log(alice_secret === bob_secret) -} - -function testECDH2() { - const type = 'secp256k1' - const alice = crypto.createECDH(type); - const aliceKey = alice.generateKeys(); - - // Generate Bob's keys... - const bob = crypto.createECDH(type); - const bobKey = bob.generateKeys(); - - console.log("\nAlice private key:\t", alice.getPrivateKey().toString('hex')); - console.log("Alice public key:\t", aliceKey.toString('hex')) - - console.log("\nBob private key:\t", bob.getPrivateKey().toString('hex')); - console.log("Bob public key:\t", bobKey.toString('hex')); - - - // Exchange and generate the secret... - const aliceSecret = alice.computeSecret(bobKey); - const bobSecret = bob.computeSecret(aliceKey); - - console.log("\nAlice shared key:\t", aliceSecret.toString('hex')) - console.log("Bob shared key:\t\t", bobSecret.toString('hex')); - //wow it actually works?! -} - -function mcPubKeyToPem(mcPubKeyBuffer) { - console.log(mcPubKeyBuffer) - if (mcPubKeyBuffer[0] == '-') return mcPubKeyBuffer - let pem = '-----BEGIN PUBLIC KEY-----\n' - let base64PubKey = mcPubKeyBuffer.toString('base64') - const maxLineLength = 65 - while (base64PubKey.length > 0) { - pem += base64PubKey.substring(0, maxLineLength) + '\n' - base64PubKey = base64PubKey.substring(maxLineLength) - } - pem += '-----END PUBLIC KEY-----\n' - return pem -} - -function readX509PublicKey(key) { - var reader = new Ber.Reader(Buffer.from(key, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); -} - -function testMC() { - // const pubKeyBuf = Buffer.from(constants.PUBLIC_KEY, 'base64') - // const pem = mcPubKeyToPem(pubKeyBuf) - // console.log(mcPubKeyToPem(pubKeyBuf)) - // const publicKey = crypto.createPublicKey({ key: pem, format: 'der' }) - - const pubKeyBuf = readX509PublicKey(constants.PUBLIC_KEY) - - // console.log('Mojang pub key', pubKeyBuf.toString('hex'), publicKey) - startClientboundEncryption(pubKeyBuf) -} - -function testMC2() { - // const mojangPubKeyBuf = Buffer.from('MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V', 'base64') - // const pem = mcPubKeyToPem(mojangPubKeyBuf) - // const publicKey = crypto.createPublicKey({ key: pem }) - - const publicKey = readX509PublicKey(constants.PUBLIC_KEY) - - const curve = 'secp384r1' - const alice = crypto.createECDH(curve) - // const keys = crypto.generateKeyPair('ec',) - - // const bob = crypto.generateKeyPairSync('ec', { - // namedCurve: type - // }) - // alice.setPrivateKey(bob.privateKey.export({ type: 'pkcs8', format: 'pem' })) - // alice.setPublicKey(bob.publicKey.export({ type: 'spki', format: 'pem' })) - - // console.log(bob) - - const aliceKey = alice.generateKeys() - - const alicePEM = ec_pem(alice, curve) - - const alicePEMPrivate = alicePEM.encodePrivateKey() - const alicePEMPublic = alicePEM.encodePublicKey() - - // const alicePublicKey = aliceKey.toString('base64') - // const alicePrivateKey = alice.getPrivateKey().toString('base64') - const aliceSecret = alice.computeSecret(publicKey, null, 'hex') - - console.log('Alice private key PEM', alicePEMPrivate) - console.log('Alice public key PEM', alicePEMPublic) - console.log('Alice public key', alice.getPublicKey('base64')) - console.log('Alice secret key', aliceSecret) - - - var sign = crypto.createSign('RSA-SHA256') - sign.write('something') - sign.end() -// // const pem2 = -// // `-----BEGIN PRIVATE KEY----- -// // ${alice.getPrivateKey('base64')} -// // -----END PRIVATE KEY-----` - -// console.log('PEM', bob.privateKey) - const sig = sign.sign(alicePEMPrivate, 'hex') - console.log('Signature', sig) - - - - const token = JWT.sign({ - salt: 'HELLO', - signedToken: alice.getPublicKey('base64') - }, alicePEMPrivate, { algorithm: 'ES384' }) - console.log('Token', token) - - const verified = JWT.verify(token, alicePEMPublic, { algorithms: 'ES384' }) - console.log('Verified!', verified) -} - -function testMC3() { - var Ber = require('asn1').Ber; - var reader = new Ber.Reader(new Buffer(constants.PUBLIC_KEY, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - var pubKey = reader.readString(Ber.BitString, true).slice(1); - var server = crypto.createECDH('secp384r1'); - server.generateKeys(); - console.log(server.computeSecret(pubKey)); - -} - -// testECDH2() -testMC2() \ No newline at end of file diff --git a/src/auth/tests/encryptTest.js b/src/auth/tests/encryptTest.js deleted file mode 100644 index d1d83ef..0000000 --- a/src/auth/tests/encryptTest.js +++ /dev/null @@ -1,88 +0,0 @@ -const crypto = require('crypto') -const JWT = require('jsonwebtoken') -const constants = require('./constants') -const { Ber } = require('asn1') -const ec_pem = require('ec-pem') - -function readX509PublicKey(key) { - var reader = new Ber.Reader(Buffer.from(key, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); -} - -function writeX509PublicKey(key) { - var writer = new Ber.Writer(); - writer.startSequence(); - writer.startSequence(); - writer.writeOID("1.2.840.10045.2.1"); - writer.writeOID("1.3.132.0.34"); - writer.endSequence(); - writer.writeBuffer(Buffer.concat([Buffer.from([0x00]), key]), Ber.BitString); - writer.endSequence(); - return writer.buffer.toString("base64"); -} - -function test(pubKey = constants.PUBLIC_KEY) { - const publicKey = readX509PublicKey(pubKey) - const curve = 'secp384r1' - const alice = crypto.createECDH(curve) - const aliceKey = alice.generateKeys() - const alicePEM = ec_pem(alice, curve) - const alicePEMPrivate = alicePEM.encodePrivateKey() - const alicePEMPublic = alicePEM.encodePublicKey() - const aliceSecret = alice.computeSecret(publicKey, null, 'hex') - console.log('Alice private key PEM', alicePEMPrivate) - console.log('Alice public key PEM', alicePEMPublic) - console.log('Alice public key', alice.getPublicKey('hex')) - console.log('Alice secret key', aliceSecret) - - // Test signing manually - const sign = crypto.createSign('RSA-SHA256') - sign.write('🧂') - sign.end() - const sig = sign.sign(alicePEMPrivate, 'hex') - console.log('Signature', sig) - - // Test JWT sign+verify - const x509 = writeX509PublicKey(alice.getPublicKey()) - const token = JWT.sign({ - salt: 'HELLO', - signedToken: alice.getPublicKey('base64') - }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } }) - console.log('Encoded JWT', token) - // send the jwt to the client... - - const verified = JWT.verify(token, alicePEMPublic, { algorithms: 'ES384' }) - console.log('Decoded JWT', verified) - // Good -} - -/** - * Alice private key PEM -----BEGIN EC PRIVATE KEY----- -MIGkAgEBBDBGgHZwH3BzieyJrdrVTVLmrEoUxpDUSqSzS98lobTXeUxJR/OmywPV -57I8YtnsJlCgBwYFK4EEACKhZANiAATjvTRgjsxKruO7XbduSQoHeR/6ouIm4Rmc -La9EkSpLFpuYZfsdtq9Vcf2t3Q3+jIbXjD/wNo97P4Hr5ghXG8sCVV7jpqadOF8j -SzyfajLGfX9mkS5WWLAg+dpi/KiEo/g= ------END EC PRIVATE KEY----- - -Alice public key PEM -----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4700YI7MSq7ju123bkkKB3kf+qLiJuEZ -nC2vRJEqSxabmGX7HbavVXH9rd0N/oyG14w/8DaPez+B6+YIVxvLAlVe46amnThf -I0s8n2oyxn1/ZpEuVliwIPnaYvyohKP4 ------END PUBLIC KEY----- - -Alice public key 04e3bd34608ecc4aaee3bb5db76e490a07791ffaa2e226e1199c2daf44912a4b169b9865fb1db6af5571fdaddd0dfe8c86d78c3ff0368f7b3f81ebe608571bcb02555ee3a6a69d385f234b3c9f6a32c67d7f66912e5658b020f9da62fca884a3f8 -Alice secret key 76feb5d420b33907c4841a74baa707b717a29c021b17b6662fd46dba3227cac3e256eee9e890edb0308f66a3119b4914 -Signature 3066023100d5ea70b8fc5e441c5e93d9f7dcde031f54291011c950a4aa8625ea9b27f7c798a8bc4de40baf35d487a05db6b5c628c6023100ae06cc2ea65db77138163c546ccf13933faae3d91bd6aa7108b99539cdb1c86f1e8a3704cb099f0b00eebed4ee75ccb2 -Encoded JWT eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzYWx0IjoiSEVMTE8iLCJzaWduZWRUb2tlbiI6IkJPTzlOR0NPekVxdTQ3dGR0MjVKQ2dkNUgvcWk0aWJoR1p3dHIwU1JLa3NXbTVobCt4MjJyMVZ4L2EzZERmNk1odGVNUC9BMmozcy9nZXZtQ0ZjYnl3SlZYdU9tcHAwNFh5TkxQSjlxTXNaOWYyYVJMbFpZc0NENTJtTDhxSVNqK0E9PSIsImlhdCI6MTYxMTc4MDYwNX0._g8k086U7nD-Tthn8jGWuuM3Q4EfhgqCfFA1Q5ePmjqhqMHOJvmrCz6tWsCytr2i-a2M51fb9K_YDAHbZ66Kos9ZkjF4Tqz5fPS880fM9woZ_1xjh7nGcOQ6sbY81zyi -Decoded JWT { - salt: 'HELLO', - signedToken: 'BOO9NGCOzEqu47tdt25JCgd5H/qi4ibhGZwtr0SRKksWm5hl+x22r1Vx/a3dDf6MhteMP/A2j3s/gevmCFcbywJVXuOmpp04XyNLPJ9qMsZ9f2aRLlZYsCD52mL8qISj+A==', - iat: 1611780605 -} - */ - -test() \ No newline at end of file diff --git a/src/auth/tests/jwtTest.js b/src/auth/tests/jwtTest.js deleted file mode 100644 index acf5307..0000000 --- a/src/auth/tests/jwtTest.js +++ /dev/null @@ -1,49 +0,0 @@ -function test() { - const chain = require('./sampleChain.json').chain - - let data = {} - - // There are three JWT tokens sent to us, one signed by the client - // one signed by Mojang with the Mojang token we have and another one - // from Xbox with addition user profile data - // We verify that at least one of the tokens in the chain has been properly - // signed by Mojang by checking the x509 public key in the JWT headers - let didVerify = false - - let pubKey = mcPubKeyToPem(constants.PUBLIC_KEY_NEW) - console.log(pubKey) - for (var token of chain) { - // const decoded = jwt.decode(token, pubKey, 'ES384') - console.log('Decoding...', token) - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - console.log('Decoded...') - console.log('Decoded', decoded) - - // Check if signed by Mojang key - const [header] = token.split('.') - const hdec = Buffer.from(header, 'base64').toString('utf-8') - const hjson = JSON.parse(hdec) - if (hjson.x5u == constants.PUBLIC_KEY && !data.extraData?.XUID) { - didVerify = true - console.log('verified with mojang key!', hjson.x5u) - } - - pubKey = mcPubKeyToPem(decoded.identityPublicKey) - data = { ...data, ...decoded } - } - console.log('Result', data) -} - -function test2() { - const chain = require('./login.json') - const token = chain.data.clientData - // console.log(token) - - const pubKey = mcPubKeyToPem(constants.CDATA_PUBLIC_KEY) - - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - - // console.log('Decoded', decoded) - - fs.writeFileSync('clientData.json', JSON.stringify(decoded)) -} diff --git a/src/client.js b/src/client.js index 9419202..1bbd167 100644 --- a/src/client.js +++ b/src/client.js @@ -1,22 +1,25 @@ const fs = require('fs') const debug = require('debug')('minecraft-protocol') +const auth = require('./client/auth') +const Options = require('./options') const { Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { Encrypt } = require('./auth/encryption') -const auth = require('./client/auth') -const Options = require('./options') const { RakClient } = require('./Rak') +const { serialize } = require('./datatypes/util') + +const debugging = false class Client extends Connection { /** @param {{ version: number, hostname: string, port: number }} options */ constructor(options) { super() this.options = { ...Options.defaultOptions, ...options } - this.serializer = createSerializer() - this.deserializer = createDeserializer() this.validateOptions() + this.serializer = createSerializer(this.options.version) + this.deserializer = createDeserializer(this.options.version) - Encrypt(this, null, options) + Encrypt(this, null, this.options) if (options.password) { auth.authenticatePassword(this, options) @@ -28,26 +31,29 @@ class Client extends Connection { this.startQueue() this.inLog = (...args) => console.info('C ->', ...args) this.outLog = (...args) => console.info('C <-', ...args) - // this.on('decrypted', this.onDecryptedPacket) } validateOptions() { - // console.log('Options', this.options) if (!this.options.hostname || this.options.port == null) throw Error('Invalid hostname/port') - if (this.options.version < Options.MIN_VERSION) { - throw new Error(`Unsupported protocol version < ${Options.MIN_VERSION} : ${this.options.version}`) + + if (!Options.Versions[this.options.version]) { + console.warn('Supported versions: ', Options.Versions) + throw Error(`Unsupported version ${this.options.version}`) + } + this.options.protocolVersion = Options.Versions[this.options.version] + if (this.options.protocolVersion < Options.MIN_VERSION) { + throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) } } onEncapsulated = (encapsulated, inetAddr) => { - // log(inetAddr.address, ': Encapsulated', encapsulated) const buffer = Buffer.from(encapsulated.buffer) this.handle(buffer) } connect = async (sessionData) => { - const hostname = this.options.hostname || '127.0.0.1' - const port = this.options.port || 19132 + const hostname = this.options.hostname + const port = this.options.port this.connection = new RakClient({ useWorkers: true, hostname, port }) this.connection.onConnected = () => this.sendLogin() @@ -64,14 +70,13 @@ class Client extends Connection { ] const encodedChain = JSON.stringify({ chain }) - // const skinChain = JSON.stringify({}) const bodyLength = this.clientUserChain.length + encodedChain.length + 8 debug('Auth chain', chain) this.write('login', { - protocol_version: this.options.version, + protocol_version: this.options.protocolVersion, payload_size: bodyLength, chain: encodedChain, client_data: this.clientUserChain @@ -83,7 +88,7 @@ class Client extends Connection { // We're talking over UDP, so there is no connection to close, instead // we stop communicating with the server console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) - process.exit(1) + process.exit(1) // TODO: handle } close() { @@ -109,32 +114,28 @@ class Client extends Connection { } readPacket(packet) { - // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100)*/) - // No idea what this exotic 0xA0 packet is, it's not implemented anywhere - // and seems empty. Possible gibberish from the raknet impl - if (pakData.name == '160' || !pakData.name) { // eslint-ignore-line - console.warn('?? Ignoring extraneous packet ', des) - return - } - - // Packet verifying (decode + re-encode + match test) - if (pakData.name) { - this.tryRencode(pakData.name, pakData.params, packet) - } - - // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) - // Packet dumping - try { - if (!fs.existsSync(`./packets/${pakData.name}.json`)) { - fs.writeFileSync(`./packets/${pakData.name}.json`, serialize(pakData.params, 2)) - fs.writeFileSync(`./packets/${pakData.name}.txt`, packet.toString('hex')) + if (debugging) { + // Packet verifying (decode + re-encode + match test) + if (pakData.name) { + this.tryRencode(pakData.name, pakData.params, packet) } - } catch { } + // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) + // Packet dumping + try { + const root = __dirname + `../data/${this.options.version}/sample/` + if (!fs.existsSync(root + `packets/${pakData.name}.json`)) { + fs.writeFileSync(root + `packets/${pakData.name}.json`, serialize(pakData.params, 2)) + fs.writeFileSync(root + `packets/${pakData.name}.txt`, packet.toString('hex')) + } + } catch { } + } + + // Abstract some boilerplate before sending to listeners switch (des.data.name) { case 'server_to_client_handshake': this.emit('client.server_handshake', des.data.params) @@ -142,27 +143,22 @@ class Client extends Connection { case 'disconnect': // Client kicked this.onDisconnectRequest(des.data.params) break - case 'crafting_data': - fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) - break - case 'start_game': - fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) - break - case 'level_chunk': - // fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) - break + // case 'crafting_data': + // fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) + // break + // case 'start_game': + // fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) + // break + // case 'level_chunk': + // // fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) + // break default: // console.log('Sending to listeners') } - this.emit(des.data.name, des.data.params) + // Emit packet + this.emit(des.data.name, des.data.params) } } -var chunks = 0; - -function serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) -} - module.exports = { Client } \ No newline at end of file diff --git a/src/client/auth.js b/src/client/auth.js index 5502b43..20775d2 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -1,16 +1,5 @@ -const XboxLiveAuth = require('@xboxreplay/xboxlive-auth') -const debug = require('debug')('minecraft-protocol') -const fetch = require('node-fetch') -const authConstants = require('./authConstants') const { MsAuthFlow } = require('./authFlow.js') -const getFetchOptions = { - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'node-minecraft-protocol' - } -} - /** * Obtains Minecaft profile data using a Minecraft access token and starts the join sequence * @param {object} client - The client passed to protocol @@ -71,33 +60,25 @@ async function authenticateDeviceCode (client, options) { } } -function checkStatus (res) { - if (res.ok) { // res.status >= 200 && res.status < 300 - return res.json() - } else { - throw Error(res.statusText) - } -} - module.exports = { authenticatePassword, authenticateDeviceCode } -async function msaTest () { - // MsAuthFlow.resetTokenCaches() +// async function msaTest () { +// // MsAuthFlow.resetTokenCaches() - await authenticateDeviceCode({ - connect(...args) { - console.log('Connecting', args) - }, - emit(...e) { - console.log('Event', e) - } - }, {}) -} +// await authenticateDeviceCode({ +// connect(...args) { +// console.log('Connecting', args) +// }, +// emit(...e) { +// console.log('Event', e) +// } +// }, {}) +// } -// debug with node microsoftAuth.js -if (!module.parent) { - msaTest() -} +// // debug with node microsoftAuth.js +// if (!module.parent) { +// msaTest() +// } diff --git a/src/connection.js b/src/connection.js index 367896c..eda0ca9 100644 --- a/src/connection.js +++ b/src/connection.js @@ -2,11 +2,26 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') -const Reliability = require('jsp-raknet/protocol/reliability') - +const Versions = require('./options') const debug = require('debug')('minecraft-protocol') class Connection extends EventEmitter { + versionLessThan(version) { + if (typeof version === 'string') { + return Versions[version] < this.options.version + } else { + return version < this.options.version + } + } + + versionGreaterThan(version) { + if (typeof version === 'string') { + return Versions[version] > this.options.version + } else { + return version > this.options.version + } + } + startEncryption(iv) { this.encryptionEnabled = true this.inLog('Started encryption', this.sharedSecret, iv) @@ -15,14 +30,10 @@ class Connection extends EventEmitter { this.q2 = [] } - write(name, params) { // TODO: Batch - // console.log('Need to encode', name, params) - var s = this.connect ? 'C' : 'S' - if (this.downQ) s += 'P' - this.outLog('NB <- ' + s, name,params) + write(name, params) { + this.outLog('sending', name, params) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) - // console.log('Sending buf', packet.toString('hex').) batch.addEncodedPacket(packet) if (this.encryptionEnabled) { @@ -51,8 +62,6 @@ class Connection extends EventEmitter { //TODO: can we just build Batch before the queue loop? const batch = new BatchPacket() this.outLog('<- BATCH', this.q2) - // For now, we're over conservative so send max 3 packets - // per batch and hold the rest for the next tick const sending = [] for (let i = 0; i < this.q.length; i++) { const packet = this.q.shift() @@ -65,28 +74,10 @@ class Connection extends EventEmitter { } else { this.sendDecryptedBatch(batch) } - // this.q2 = [] } }, 20) } - writeRaw(name, buffer) { // skip protodef serializaion - // temporary hard coded stuff - const batch = new BatchPacket() - if (name == 'biome_definition_list') { - // so we can send nbt straight from file without parsing - const stream = new BinaryStream() - stream.writeUnsignedVarInt(0x7a) - stream.append(buffer) - batch.addEncodedPacket(stream.getBuffer()) - } - - if (this.encryptionEnabled) { - this.sendEncryptedBatch(batch) - } else { - this.sendDecryptedBatch(batch) - } - } /** * Sends a MCPE packet buffer @@ -121,21 +112,11 @@ class Connection extends EventEmitter { // TODO: Rename this to sendEncapsulated sendMCPE(buffer, immediate) { this.connection.sendReliable(buffer, immediate) - // if (this.worker) { - // this.outLog('-> buf', buffer) - // this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) - // } else { - // const sendPacket = new EncapsulatedPacket() - // sendPacket.reliability = Reliability.ReliableOrdered - // sendPacket.buffer = buffer - // this.connection.addEncapsulatedToQueue(sendPacket) - // if (immediate) this.connection.sendQueue() - // } } // These are callbacks called from encryption.js onEncryptedPacket = (buf) => { - this.outLog('ENC BUF', buf) + this.outLog('Enc buf', buf) const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header this.outLog('Sending wrapped encrypted batch', packet) @@ -143,8 +124,6 @@ class Connection extends EventEmitter { } onDecryptedPacket = (buf) => { - // console.log('🟢 Decrypted', buf) - const stream = new BinaryStream(buf) const packets = BatchPacket.getPackets(stream) @@ -168,10 +147,7 @@ class Connection extends EventEmitter { } } } - // console.log('[client] handled incoming ', buffer) } } -function serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) -} + module.exports = { Connection } \ No newline at end of file diff --git a/src/datatypes/promises.js b/src/datatypes/promises.js deleted file mode 100644 index c3763e1..0000000 --- a/src/datatypes/promises.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)) - }, - - waitFor(cb, withTimeout) { - return Promise.race([ - new Promise((res, rej) => cb(res)), - sleep(withTimeout) - ]) - } -} \ No newline at end of file diff --git a/src/datatypes/util.js b/src/datatypes/util.js new file mode 100644 index 0000000..1c8c3d8 --- /dev/null +++ b/src/datatypes/util.js @@ -0,0 +1,37 @@ +const fs = require('fs'); + +function getFiles(dir) { + var results = []; + var list = fs.readdirSync(dir); + list.forEach(function (file) { + file = dir + '/' + file; + var stat = fs.statSync(file); + if (stat && stat.isDirectory()) { + /* Recurse into a subdirectory */ + results = results.concat(getFiles(file)); + } else { + /* Is a file */ + results.push(file); + } + }); + return results; +} + +module.exports = { + sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)) + }, + + waitFor(cb, withTimeout) { + return Promise.race([ + new Promise((res, rej) => cb(res)), + sleep(withTimeout) + ]) + }, + + serialize(obj = {}, fmt) { + return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) + }, + + getFiles +} \ No newline at end of file diff --git a/src/options.js b/src/options.js index dc329ea..e6fb930 100644 --- a/src/options.js +++ b/src/options.js @@ -1,12 +1,16 @@ // Minimum supported version (< will be kicked) -const MIN_VERSION = 422 +const MIN_VERSION = '1.16.201' // Currently supported verson -const CURRENT_VERSION = 422 - +const CURRENT_VERSION = '1.16.201' const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 version: CURRENT_VERSION } -module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION } \ No newline at end of file +const Versions = { + '1.16.210': 428, + '1.16.201': 422 +} + +module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } \ No newline at end of file diff --git a/src/rak.js b/src/rak.js index ad216a0..09510ad 100644 --- a/src/rak.js +++ b/src/rak.js @@ -3,6 +3,7 @@ const Listener = require('jsp-raknet/listener') const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') const RakClient = require('jsp-raknet/client') const ConnWorker = require('./rakWorker') +const { waitFor } = require('./datatypes/util') try { var { Client, Server, PacketPriority, PacketReliability, McPingMessage } = require('raknet-native') } catch (e) { @@ -12,14 +13,14 @@ try { class RakNativeClient extends EventEmitter { constructor(options) { super() - this.onConnected = () => {} - this.onCloseConnection = () => {} - this.onEncapsulated = () => {} + this.onConnected = () => { } + this.onCloseConnection = () => { } + this.onEncapsulated = () => { } this.raknet = new Client(options.hostname, options.port, 'minecraft') this.raknet.on('encapsulated', thingy => { // console.log('Encap',thingy) - const { buffer, address, guid }=thingy + const { buffer, address, guid } = thingy this.onEncapsulated(buffer, address) }) this.raknet.on('connected', () => { @@ -51,18 +52,17 @@ class RakNativeClient extends EventEmitter { class RakNativeServer extends EventEmitter { constructor(options = {}) { super() - console.log('opts',options) - this.onOpenConnection = () => {} - this.onCloseConnection = () => {} - this.onEncapsulated = () => {} + this.onOpenConnection = () => { } + this.onCloseConnection = () => { } + this.onEncapsulated = () => { } this.raknet = new Server(options.hostname, options.port, { maxConnections: options.maxConnections || 3, - minecraft: { }, + minecraft: {}, message: new McPingMessage().toBuffer() }) - + this.raknet.on('openConnection', (client) => { - client.sendReliable = function(buffer, immediate) { + client.sendReliable = function (buffer, immediate) { const priority = immediate ? PacketPriority.IMMEDIATE_PRIORITY : PacketPriority.MEDIUM_PRIORITY return this.send(buffer, priority, PacketReliability.RELIABLE_ORDERED, 0) } @@ -70,12 +70,13 @@ class RakNativeServer extends EventEmitter { }) this.raknet.on('closeConnection', (client) => { - console.log('!!! Client CLOSED CONNECTION!') + console.warn('! Client closed connection') + // TODO: need to handle this properly.. this.onCloseConnection(client) }) this.raknet.on('encapsulated', (thingy) => { - const { buffer, address, guid }=thingy + const { buffer, address, guid } = thingy // console.log('ENCAP',thingy) this.onEncapsulated(buffer, address) }) @@ -89,8 +90,8 @@ class RakNativeServer extends EventEmitter { class RakJsClient extends EventEmitter { constructor(options = {}) { super() - this.onConnected = () => {} - this.onEncapsulated = () => {} + this.onConnected = () => { } + this.onEncapsulated = () => { } if (options.useWorkers) { this.connect = this.workerConnect this.sendReliable = this.workerSendReliable @@ -145,9 +146,9 @@ class RakJsServer extends EventEmitter { constructor(options = {}) { super() this.options = options - this.onOpenConnection = () => {} - this.onCloseConnection = () => {} - this.onEncapsulated = () => {} + this.onOpenConnection = () => { } + this.onCloseConnection = () => { } + this.onEncapsulated = () => { } if (options.useWorkers) { throw Error('nyi') @@ -159,13 +160,13 @@ class RakJsServer extends EventEmitter { async plainListen() { this.raknet = new Listener() await this.raknet.listen(this.options.hostname, this.options.port) - this.raknet.on('openConnection', (conn) => { - conn.sendReliable = function(buffer, immediate) { + this.raknet.on('openConnection', (conn) => { + conn.sendReliable = function (buffer, immediate) { const sendPacket = new EncapsulatedPacket() sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = buffer this.connection.addEncapsulatedToQueue(sendPacket) - if (immediate) this.raknet.sendQueue() + if (immediate) this.raknet.sendQueue() } this.onOpenConnection(conn) }) @@ -174,7 +175,7 @@ class RakJsServer extends EventEmitter { } } -module.exports = { - RakClient: Client ? RakNativeClient : RakJsClient, +module.exports = { + RakClient: Client ? RakNativeClient : RakJsClient, RakServer: Server ? RakNativeServer : RakJsServer } \ No newline at end of file diff --git a/src/relay.js b/src/relay.js index 0fee6af..08314d1 100644 --- a/src/relay.js +++ b/src/relay.js @@ -4,6 +4,7 @@ const { Client } = require("./client") const { Server } = require("./server") const { Player } = require("./serverPlayer") const debug = require('debug')('minecraft-protocol relay') +const { serialize } = require('./datatypes/util') /** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ @@ -67,7 +68,6 @@ class RelayPlayer extends Player { console.warn('Old', packet.toString('hex')) console.log('Failed to re-encode', name, params) process.exit(1) - throw Error('re-encoding fail for' + name + ' - ' + JSON.stringify(params)) } } @@ -159,7 +159,7 @@ class Relay extends Server { client.once('join', () => { // Intercept once handshaking done ds.upstream = client ds.flushUpQueue() - console.log('UPSTREAM HAS JOINED') + console.log('Connected to upstream server') client.readPacket = (packet) => ds.readUpstream(packet) }) this.upstreams.set(clientAddr.hash, client) @@ -167,7 +167,7 @@ class Relay extends Server { closeUpstreamConnection(clientAddr) { const up = this.upstreams.get(clientAddr.hash) - if (!up) throw Error(`unable to close non-existant connection ${clientAddr.hash}`) + if (!up) throw Error(`unable to close non-open connection ${clientAddr.hash}`) up.close() this.upstreams.delete(clientAddr.hash) debug('relay closed connection', clientAddr) @@ -188,43 +188,5 @@ class Relay extends Server { } } -function serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) -} - -function createRelay() { - console.log('Creating relay') - /** - * Example to create a non-transparent proxy (or 'Relay') connection to destination server - * In Relay we de-code and re-encode packets - */ - const relay = new Relay({ - /* Hostname and port for clients to listen to */ - hostname: '0.0.0.0', - port: 19130, - /** - * Who does the authentication - * If set to `client`, all connecting clients will be sent a message with a link to authenticate - * If set to `server`, the server will authenticate and only one client will be able to join - * (Default) If set to `none`, no authentication will be done - */ - auth: 'server', - - /** - * Sets if packets will automatically be forwarded. If set to false, you must listen for on('packet') - * events and - */ - auto: true, - - /* Where to send upstream packets to */ - destination: { - hostname: '127.0.0.1', - port: 19132, - // encryption: true - } - }) - - relay.create() -} - -createRelay() \ No newline at end of file +// Too many things called 'Proxy' ;) +module.exports = { Relay } \ No newline at end of file diff --git a/src/server.js b/src/server.js index 2e3a924..1dff4e7 100644 --- a/src/server.js +++ b/src/server.js @@ -9,18 +9,23 @@ class Server extends EventEmitter { constructor(options) { super() this.options = { ...Options.defaultOptions, ...options } - this.serializer = createSerializer() - this.deserializer = createDeserializer() + this.validateOptions() + this.serializer = createSerializer(this.options.version) + this.deserializer = createDeserializer(this.options.version) this.clients = {} this.clientCount = 0 - this.validateOptions() - this.inLog = (...args) => console.debug('S', ...args) - this.outLog = (...args) => console.debug('S', ...args) + this.inLog = (...args) => console.debug('C -> S', ...args) + this.outLog = (...args) => console.debug('S -> C', ...args) } validateOptions() { - if (this.options.version < Options.MIN_VERSION) { - throw new Error(`Unsupported protocol version < ${Options.MIN_VERSION} : ${this.options.version}`) + if (!Options.Versions[this.options.version]) { + console.warn('Supported versions: ', Options.Versions) + throw Error(`Unsupported version ${this.options.version}`) + } + this.options.protocolVersion = Options.Versions[this.options.version] + if (this.options.protocolVersion < Options.MIN_VERSION) { + throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) } } @@ -39,7 +44,7 @@ class Server extends EventEmitter { } onEncapsulated = (buffer, address) => { - debug(address, 'Encapsulated', buffer) + this.inLog('encapsulated', address, buffer) const client = this.clients[address] if (!client) { throw new Error(`packet from unknown inet addr: ${address}`) @@ -57,6 +62,4 @@ class Server extends EventEmitter { } } -const hash = (inetAddr) => inetAddr.address + '/' + inetAddr.port - module.exports = { Server } \ No newline at end of file diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 8d05c6a..3f41817 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -16,15 +16,14 @@ class Player extends Connection { this.server = server this.serializer = server.serializer this.deserializer = server.deserializer - // console.log('serializer/des',this.serializer,this.deserializer) this.connection = connection this.options = server.options Encrypt(this, server, this.options) this.startQueue() this.status = ClientStatus.Authenticating - this.inLog = (...args) => console.info('S ->', ...args) - this.outLog = (...args) => console.info('S <-', ...args) + this.inLog = (...args) => console.info('S -> C', ...args) + this.outLog = (...args) => console.info('C -> S', ...args) } getData() { @@ -33,17 +32,17 @@ class Player extends Connection { onLogin(packet) { let body = packet.data - debug('Body', body) + // debug('Login body', body) this.emit('loggingIn', body) const clientVer = body.protocol_version - if (this.server.options.version) { - if (this.server.options.version < clientVer) { - this.sendDisconnectStatus(failed_client) + if (this.server.options.protocolVersion) { + if (this.server.options.protocolVersion < clientVer) { + this.sendDisconnectStatus('failed_client') return } } else if (clientVer < MIN_VERSION) { - this.sendDisconnectStatus(failed_client) + this.sendDisconnectStatus('failed_client') return } @@ -55,6 +54,7 @@ class Player extends Connection { var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) } catch (e) { console.error(e) + // TODO: disconnect user throw new Error('Failed to verify user') } console.log('Verified user', 'got pub key', key, userData) @@ -66,7 +66,6 @@ class Player extends Connection { this.version = clientVer } - /** * Disconnects a client before it has joined * @param {string} play_status diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index dee6469..d2c1794 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,20 +1,20 @@ -const { PassThrough, Transform } = require('readable-stream') +const { Transform } = require('readable-stream') const crypto = require('crypto') const aesjs = require('aes-js') const Zlib = require('zlib') -const CIPHER = 'aes-256-cfb8' +const CIPHER_ALG = 'aes-256-cfb8' function createCipher(secret, initialValue) { - if (crypto.getCiphers().includes(CIPHER)) { - return crypto.createCipheriv(CIPHER, secret, initialValue) + if (crypto.getCiphers().includes(CIPHER_ALG)) { + return crypto.createCipheriv(CIPHER_ALG, secret, initialValue) } return new Cipher(secret, initialValue) } function createDecipher(secret, initialValue) { - if (crypto.getCiphers().includes(CIPHER)) { - return crypto.createDecipheriv(CIPHER, secret, initialValue) + if (crypto.getCiphers().includes(CIPHER_ALG)) { + return crypto.createDecipheriv(CIPHER_ALG, secret, initialValue) } return new Decipher(secret, initialValue) } @@ -54,14 +54,11 @@ class Decipher extends Transform { function computeCheckSum(packetPlaintext, sendCounter, secretKeyBytes) { let digest = crypto.createHash('sha256'); let counter = Buffer.alloc(8) - // writeLI64(sendCounter, counter, 0); counter.writeBigInt64LE(sendCounter, 0) - // console.log('Send counter', counter) digest.update(counter); digest.update(packetPlaintext); digest.update(secretKeyBytes); let hash = digest.digest(); - // console.log('Hash', hash.toString('hex')) return hash.slice(0, 8); } @@ -74,21 +71,14 @@ function createEncryptor(client, iv) { function process(chunk) { const buffer = Zlib.deflateRawSync(chunk, { level: 7 }) - // client.outLog('🟡 Compressed', buffer, client.sendCounter) const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) client.sendCounter++ - // client.outLog('writing to cipher...', packet, client.secretKeyBytes, iv) client.cipher.write(packet) } - // const stream = new PassThrough() - client.cipher.on('data', client.onEncryptedPacket) - return (blob) => { - // client.outLog(client.options ? 'C':'S', '🟡 Encrypting', client.sendCounter, blob) - // stream.write(blob) process(blob) } } @@ -99,6 +89,8 @@ function createDecryptor(client, iv) { client.receiveCounter = client.receiveCounter || 0n function verify(chunk) { + // TODO: remove the extra logic here, probably fixed with new raknet impl + // console.log('Decryptor: checking checksum', client.receiveCounter, chunk) // client.outLog('🔵 Inflating', chunk) // First try to zlib decompress, then see how much bytes get read @@ -139,8 +131,6 @@ function createDecryptor(client, iv) { client.decipher.on('data', verify) return (blob) => { - // client.inLog(client.options ? 'C':'S', ' 🔵 Decrypting', client.receiveCounter, blob) - // client.inLog('Using shared key', client.secretKeyBytes, iv) client.decipher.write(blob) } } diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index e07b63c..c7a70ed 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,9 +1,9 @@ const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler const { FullPacketParser, Serializer } = require('protodef') -function createProtocol() { - const protocol = require('../../data/newproto.json').types - console.log('Proto', protocol) +// Compiles the ProtoDef schema at runtime +function createProtocol(version) { + const protocol = require(`../../data/${version}/protocol.json`).types var compiler = new ProtoDefCompiler() compiler.addTypesToCompile(protocol) compiler.addTypes(require('../datatypes/compiler-minecraft')) @@ -13,8 +13,8 @@ function createProtocol() { return compiledProto } - -function getProtocol() { +// Loads already generated read/write/sizeof code +function getProtocol(version) { const compiler = new ProtoDefCompiler() compiler.addTypes(require('../datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) @@ -26,22 +26,19 @@ function getProtocol() { } return new CompiledProtodef( - compile(compiler.sizeOfCompiler, '../../data/size.js'), - compile(compiler.writeCompiler, '../../data/write.js'), - compile(compiler.readCompiler, '../../data/read.js') - // compiler.sizeOfCompiler.compile(fs.readFileSync(__dirname + '/../../data/size.js', 'utf-8')), - // compiler.writeCompiler.compile(fs.readFileSync(__dirname + '/../../data/write.js', 'utf-8')), - // compiler.readCompiler.compile(fs.readFileSync(__dirname + '/../../data/read.js', 'utf-8')) + compile(compiler.sizeOfCompiler, `../../data/${version}/size.js`), + compile(compiler.writeCompiler, `../../data/${version}/write.js`), + compile(compiler.readCompiler, `../../data/${version}/read.js`) ) } -function createSerializer() { - var proto = getProtocol() +function createSerializer(version) { + var proto = getProtocol(version) return new Serializer(proto, 'mcpe_packet'); } -function createDeserializer() { - var proto = getProtocol() +function createDeserializer(version) { + var proto = getProtocol(version) return new FullPacketParser(proto, 'mcpe_packet'); } From 1c582acdb50720d8b48ad4e9614c1e227c00cccf Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 13 Mar 2021 13:38:31 -0500 Subject: [PATCH 117/458] Standard (#44) * standard * remove old examples --- .eslintignore | 1 + babel.config.js | 3 + data/new/compile.js | 98 ++++++++-------- data/provider.js | 17 +-- examples/clientTest.js | 9 +- examples/createRelay.js | 6 +- examples/old/chunk | Bin 83200 -> 0 bytes examples/old/client.js | 25 ----- examples/old/deserialize.js | 16 --- examples/old/server.js | 108 ------------------ examples/old/server_simple.js | 31 ------ examples/serverTest.js | 117 ++++++++++---------- index.js | 3 - package.json | 18 ++- src/auth/chains.js | 128 ++++++++++----------- src/auth/constants.js | 2 +- src/auth/encryption.js | 76 ++++++------- src/client.js | 21 ++-- src/client/auth.js | 4 +- src/client/authConstants.js | 4 +- src/client/authFlow.js | 9 +- src/client/tokens.js | 47 ++++---- src/connection.js | 35 +++--- src/datatypes/BatchPacket.js | 20 ++-- src/datatypes/compiler-minecraft.js | 21 +--- src/datatypes/minecraft.js | 166 ++++++++++++++-------------- src/datatypes/util.js | 52 ++++----- src/datatypes/varlong.js | 8 +- src/options.js | 2 +- src/rak.js | 44 ++++---- src/rakWorker.js | 18 +-- src/relay.js | 35 +++--- src/server.js | 8 +- src/serverPlayer.js | 31 +++--- src/transforms/encryption.js | 71 ++++++------ src/transforms/serializer.js | 20 ++-- 36 files changed, 541 insertions(+), 733 deletions(-) create mode 100644 .eslintignore create mode 100644 babel.config.js delete mode 100644 examples/old/chunk delete mode 100644 examples/old/client.js delete mode 100644 examples/old/deserialize.js delete mode 100644 examples/old/server.js delete mode 100644 examples/old/server_simple.js delete mode 100644 index.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..b59f7e3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +test/ \ No newline at end of file diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..7db9b6f --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ['@babel/preset-env'] +} diff --git a/data/new/compile.js b/data/new/compile.js index a4ebce5..5c67af1 100644 --- a/data/new/compile.js +++ b/data/new/compile.js @@ -1,71 +1,71 @@ /** * This is a utility script that converts the YAML here into ProtoDef schema code and (soon) docs/typescript definitions. * It also pre-compiles JS code from the schema for easier development. - * + * * You can run this with `npm run build` - * + * */ const fs = require('fs') const { ProtoDefCompiler } = require('protodef').Compiler // Parse the YML files and turn to JSON -function genProtoSchema() { - const { parse, compile } = require('protodef-yaml/compiler') - let version +function genProtoSchema () { + const { parse, compile } = require('protodef-yaml/compiler') - // Create the packet_map.yml from proto.yml - const parsed = parse('./proto.yml') - version = parsed['!version'] - const packets = [] - for (const key in parsed) { - if (key.startsWith('%container')) { - const [, name] = key.split(',') - if (name.startsWith('packet_')) { - const children = parsed[key] - const packetName = name.replace('packet_', '') - const packetID = children['!id'] - packets.push([packetID, packetName, name]) - } - } + // Create the packet_map.yml from proto.yml + const parsed = parse('./proto.yml') + const version = parsed['!version'] + const packets = [] + for (const key in parsed) { + if (key.startsWith('%container')) { + const [, name] = key.split(',') + if (name.startsWith('packet_')) { + const children = parsed[key] + const packetName = name.replace('packet_', '') + const packetID = children['!id'] + packets.push([packetID, packetName, name]) + } } - let l1 = l2 = '' - for (const [id,name,fname] of packets) { - l1 += ` 0x${id.toString(16).padStart(2, '0')}: ${name}\n` - l2 += ` if ${name}: ${fname}\n` - } - // TODO: skip creating packet_map.yml and just generate the ProtoDef map JSON directly - const t = `#Auto-generated from proto.yml, do not modify\n!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` - fs.writeFileSync('./packet_map.yml', t) + } + let l1 = '' + let l2 = '' + for (const [id, name, fname] of packets) { + l1 += ` 0x${id.toString(16).padStart(2, '0')}: ${name}\n` + l2 += ` if ${name}: ${fname}\n` + } + // TODO: skip creating packet_map.yml and just generate the ProtoDef map JSON directly + const t = `#Auto-generated from proto.yml, do not modify\n!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` + fs.writeFileSync('./packet_map.yml', t) - compile('./proto.yml', 'protocol.json') - return version + compile('./proto.yml', 'protocol.json') + return version } // Compile the ProtoDef JSON into JS -function createProtocol(version) { - const compiler = new ProtoDefCompiler() - const protocol = require(`../${version}/protocol.json`).types - compiler.addTypes(require('../../src/datatypes/compiler-minecraft')) - compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) - compiler.addTypesToCompile(protocol) +function createProtocol (version) { + const compiler = new ProtoDefCompiler() + const protocol = require(`../${version}/protocol.json`).types + compiler.addTypes(require('../../src/datatypes/compiler-minecraft')) + compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) + compiler.addTypesToCompile(protocol) - fs.writeFileSync(`../${version}/read.js`, 'module.exports = ' + compiler.readCompiler.generate()) - fs.writeFileSync(`../${version}/write.js`, 'module.exports = ' + compiler.writeCompiler.generate()) - fs.writeFileSync(`../${version}/size.js`, 'module.exports = ' + compiler.sizeOfCompiler.generate()) + fs.writeFileSync(`../${version}/read.js`, 'module.exports = ' + compiler.readCompiler.generate()) + fs.writeFileSync(`../${version}/write.js`, 'module.exports = ' + compiler.writeCompiler.generate()) + fs.writeFileSync(`../${version}/size.js`, 'module.exports = ' + compiler.sizeOfCompiler.generate()) - const compiledProto = compiler.compileProtoDefSync() - return compiledProto + const compiledProto = compiler.compileProtoDefSync() + return compiledProto } -function main() { - const version = genProtoSchema() +function main () { + const version = genProtoSchema() - fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: require('./protocol.json') }, null, 2)) - fs.unlinkSync('./protocol.json') //remove temp file - fs.unlinkSync('./packet_map.yml') //remove temp file - - console.log('Generating JS...') - createProtocol(version) + fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: require('./protocol.json') }, null, 2)) + fs.unlinkSync('./protocol.json') // remove temp file + fs.unlinkSync('./packet_map.yml') // remove temp file + + console.log('Generating JS...') + createProtocol(version) } -main() \ No newline at end of file +main() diff --git a/data/provider.js b/data/provider.js index 3475db3..437d53a 100644 --- a/data/provider.js +++ b/data/provider.js @@ -1,19 +1,20 @@ const { Versions } = require('../src/options') const { getFiles } = require('../src/datatypes/util') +const { join } = require('path') const fileMap = {} // Walks all the directories for each of the supported versions in options.js // then builds a file map for each version // { 'protocol.json': { '1.16.200': '1.16.200/protocol.json', '1.16.210': '1.16.210/...' } } -function loadVersions() { +function loadVersions () { for (const version in Versions) { let files = [] - try { - files = getFiles(__dirname + '/' + version) + try { + files = getFiles(join(__dirname, '/', version)) } catch {} - for (let file of files) { - const rfile = file.replace(__dirname + '/' + version + '/', '') + for (const file of files) { + const rfile = file.replace(join(__dirname, '/', version), '') fileMap[rfile] ??= [] fileMap[rfile].push([Versions[version], file]) fileMap[rfile].sort().reverse() @@ -25,11 +26,11 @@ module.exports = (protocolVersion) => { return { // Returns the most recent file based on the specified protocolVersion // e.g. if `version` is 1.16 and a file for 1.16 doesn't exist, load from 1.15 file - getPath(file) { + getPath (file) { if (!fileMap[file]) { throw Error('Unknown file ' + file) } - for (const [ pver, path ] of fileMap[file]) { + for (const [pver, path] of fileMap[file]) { if (pver <= protocolVersion) { // console.debug('for', file, 'returining', path) return path @@ -42,4 +43,4 @@ module.exports = (protocolVersion) => { loadVersions() // console.log('file map', fileMap) -// module.exports(Versions['1.16.210']).open('creativeitems.json') \ No newline at end of file +// module.exports(Versions['1.16.210']).open('creativeitems.json') diff --git a/examples/clientTest.js b/examples/clientTest.js index 11b9b3a..a3d4b2b 100644 --- a/examples/clientTest.js +++ b/examples/clientTest.js @@ -1,9 +1,7 @@ process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('../src/client') -const fs = require('fs') -// console.log = () => -async function test() { +async function test () { const client = new Client({ hostname: '127.0.0.1', port: 19132 @@ -32,11 +30,8 @@ async function test() { client.queue('client_cache_status', { enabled: false }) client.queue('request_chunk_radius', { chunk_radius: 1 }) client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) - }) - - // var read = 0; // client.on('level_chunk', (packet) => { // read++ @@ -44,4 +39,4 @@ async function test() { // }) } -test() \ No newline at end of file +test() diff --git a/examples/createRelay.js b/examples/createRelay.js index 008027b..31d8553 100644 --- a/examples/createRelay.js +++ b/examples/createRelay.js @@ -1,6 +1,6 @@ const { Relay } = require('../src/relay') -function createRelay() { +function createRelay () { console.log('Creating relay') /** * Example to create a non-transparent proxy (or 'Relay') connection to destination server @@ -27,7 +27,7 @@ function createRelay() { /* Where to send upstream packets to */ destination: { hostname: '127.0.0.1', - port: 19132, + port: 19132 // encryption: true } }) @@ -35,4 +35,4 @@ function createRelay() { relay.create() } -createRelay() \ No newline at end of file +createRelay() diff --git a/examples/old/chunk b/examples/old/chunk deleted file mode 100644 index 4152a449e50dace389356c21650ac8bea1744cea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83200 zcmeI3OK#j&5JibJj2Hpi0wT(i^>Mr;O?n^607EsEy<+xoKpbl=6C^*)7d>`FV?{ky&fD$T!+$)Q5DP-dP%bXUh~)0 zpY8ppHaLHM!)JLEZ@8|u??aJZ{r)HLwyBl1_GZeS@{%7A3*JP?I4E@VxS%8LzX!3~ zzwcSjejn0i`5@=lvQ%q750lN&twuemSZTBwrF{7MLdbT&m9&?q-JBo5G7jajERim< z4|xB!yE&yg@{1Dnv@&ng-R-)e1=QUu{K=mvPDQl)g7vD-bfw0x}#HQ`;IErq!e+m-rsS?gvuI?YcU z;43D*|7;WWo?gmF+Ve@8&Qf(Dp-U)(dCeLxew)T+Z?;^ z^uBYkv{3Y+4K=!v)ABUM{O-m}kDG0|FsgYp)s1wTxeLu_srf=emr?*UveuL8I=#BP zDo1bPrY#l+o6c=i+KbaUciEheQnOOdyzn~ROjNX~brW6hZqm|hnMd!UeT0-UoeL{H zU!3;(VfE&$4nKeH#3n1f+smf2#Q3?ep0}CE=TFsDu~}A-kx#{*FSQ(B$*Hc=ljF;AK(#gR4`k@c}2rXT(OUQO>I@>Kkn`4wXFvD&soRHqzzpTSO31`z&H&_dmA4jbjEs9hf zQ6w}ZB0>>$S+qwBqg9QgOWh-XdjH_*-ddBQufSh>E;#6DY3`NzwfN)a|2q7&OL?FE zqJ8eT2OsnP7v?vo{2t8MUq|o$DO$F-O?K;atKL5;Zto#(DE360zJELF3-j+|ejjvk z{@rfZ?cR-}#9fLquS<=XAKIf-tBwdMd6g1X_AYyqV{h5`{#X2WZ~hp^9|i1d+1hn> zQg^-E$?_=j4NiPwQqEUd#9xsf^$?9Jdz>jxuYV`8^6y?({#~cO(vL@^aW4=M)zG?y zM%NOx3Q=Wm)nmgwz81AVYB9fDKb)_xY$hU&yc#Urw`8EjGIvDXB-<@!|3BU6=dGOx zjXlf$cH+dpF$mv?O}aDPb$^L31pE=9v8V8dT%CK1B6)CzJZWy-EZXm1q&?RDs9pEh z^GE-FjaxSee~j!(TcTe=}Yje0Z zC0L}l)Q;so<=^Pa`}maBm6zkF)+k7T1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14c zNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCNZ@1W14cNPq-LfCL^pfg1;~w|L|6 zlVPF1p?)m<<9#-_pkBoTp!$j!S~DafB(T=!Ltwh{gK?w_aFR%LdX*@CzlD4Icj6oV5gUIs z^eX8q{M|PO{SW;0DCy^Re>2icBOeoJ_xBf_maW_P-oR zDs|RJBPYvNEv)UaxnZoj=_7n2s!!t|JX-&SwkH13$DBWkvEKOW8M2IaByTq_`J))i z8rJ7mUn$lodo}6-<^Uc35zW9Htx8^l`9@6s)<=3RA#tocN9LDe(?`?Kt^RSc^)d0U zmec#UE>{2Qw={F``PEVOLduBE%o0RUHq{U!1@E!IQ^Q zdwy~C@}<;b_b{BEUtWe5IXu6-x{`&h?1ntOxV%DvXwAM*eR;L*Eqfu!OL;VTCTICG z3@2yer0PPRlasR-FG8Q64`(8?9-fNI`unGwLJ!B=jcM6%ar)iUr<={D`{lQv_>T;D J2Oj4g_!n1^QO5uP diff --git a/examples/old/client.js b/examples/old/client.js deleted file mode 100644 index 65b703f..0000000 --- a/examples/old/client.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; -var pmp = require('../'); - -if(process.argv.length !=5) { - console.log("Usage: node client.js "); - process.exit(1); -} - -var client = pmp.createClient({ - host: process.argv[2], - port: parseInt(process.argv[3]), - username:process.argv[4] -}); - -client.on('mcpe', packet => console.log(packet)); - -client.on('set_spawn_position', () => { - client.writeMCPE('request_chunk_radius', { - chunkRadius:8 - }); -}); - -client.on('error',function(err){ - console.log(err); -}); diff --git a/examples/old/deserialize.js b/examples/old/deserialize.js deleted file mode 100644 index bc9132f..0000000 --- a/examples/old/deserialize.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; -var mcpe = require('../'); -var Parser = require('protodef').Parser; - -var parser = new Parser(mcpe.createProtocol(),'mcpe_packet'); -var serializer = mcpe.createSerializer(); - -parser.write(new Buffer('9F000000010000007E000000804800B0', 'hex')); - -parser.on('error', function(err) { - console.log(err.stack); -}) - -parser.on('data', function(chunk) { - console.log(JSON.stringify(chunk, null, 2)); -}); diff --git a/examples/old/server.js b/examples/old/server.js deleted file mode 100644 index 7116391..0000000 --- a/examples/old/server.js +++ /dev/null @@ -1,108 +0,0 @@ -'use strict'; - -var pmp = require('../'); -var fs = require("fs"); - -if(process.argv.length !=4) { - console.log("Usage: node server.js "); - process.exit(1); -} - -var server = pmp.createServer({ - host: process.argv[2], - port: parseInt(process.argv[3]), - name: 'MCPE;Minecraft: PE Server;81 81;0.15.0;0;20' -}); - -server.on('connection', function(client) { - - - client.on("mcpe",packet => console.log(packet)); - - client.on("login_mcpe",packet => { - client.writeMCPE("player_status",{ - status:0 - }); - - client.writeMCPE('move_player', { - entityId: [0,0], - x: 1, - y: 64 + 1.62, - z: 1, - yaw: 0, - headYaw: 0, - pitch: 0, - mode: 0, - onGround: 1 - }); - - client.writeMCPE("start_game",{ - seed:-1, - dimension:0, - generator:1, - gamemode:1, - entityId:[0,0], - spawnX:1, - spawnY:1, - spawnZ:1, - x:0, - y:1+1.62, - z:0, - isLoadedInCreative:0, - dayCycleStopTime:0, - eduMode:0, - worldName:"" - }); - - client.writeMCPE('set_spawn_position', { - x: 1, - y: 64, - z: 1 - }); - client.writeMCPE("set_time",{ - time:0, - started:1 - }); - - client.writeMCPE('respawn', { - x: 1, - y: 64, - z: 1 - }); - }); - - client.on("chunk_radius_update",() => { - client.writeMCPE('chunk_radius_update',{ - chunk_radius:1 - }); - - for (let x = -1; x <=1; x++) { - for (let z = -1; z <=1; z++) { - client.writeBatch([{name:"full_chunk_data",params:{ - chunkX: x, - chunkZ: z, - order: 1, - chunkData:fs.readFileSync(__dirname+"/chunk") - }}]); - } - } - - client.writeMCPE('player_status', { - status: 3 - }); - - client.writeMCPE('set_time', { - time: 0, - started: 1 - }); - - }); - - client.on('error', function(err) { - console.log(err.stack); - }); - - client.on('end',function() { - console.log("client left"); - }) -}); diff --git a/examples/old/server_simple.js b/examples/old/server_simple.js deleted file mode 100644 index 846666e..0000000 --- a/examples/old/server_simple.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -var pmp = require('../'); -var fs = require("fs"); - -if(process.argv.length !=4) { - console.log("Usage: node server.js "); - process.exit(1); -} - -var server = pmp.createServer({ - host: process.argv[2], - port: parseInt(process.argv[3]), - name: 'MCPE;Minecraft: PE Server;81 81;0.15.0;0;20' -}); - -server.on('connection', function(client) { - client.on("mcpe", packet => console.log(packet)); - - client.on("login_mcpe", data => { - console.log(client.displayName + '(' + client.XUID + ') ' + ' joined the game'); - }); - - client.on('error', err => { - console.error(err); - }); - - client.on('end', () => { - console.log("client left"); - }) -}); diff --git a/examples/serverTest.js b/examples/serverTest.js index b03b27c..5006736 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -1,25 +1,23 @@ +const fs = require('fs') process.env.DEBUG = 'minecraft-protocol raknet' const { Server } = require('../src/server') // const CreativeItems = require('../data/creativeitems.json') -const NBT = require('prismarine-nbt') -const fs = require('fs') const DataProvider = require('../data/provider') - -let server = new Server({ +const server = new Server({ }) server.create('0.0.0.0', 19132) -function getPath(packetPath) { +function getPath (packetPath) { return DataProvider(server.options.protocolVersion).getPath(packetPath) } -function get(packetPath) { +function get (packetPath) { return require(getPath('sample/' + packetPath)) } -let ran = false +// const ran = false server.on('connect', ({ client }) => { /** @type {Player} */ @@ -29,26 +27,26 @@ server.on('connect', ({ client }) => { // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It // sends a list of the resource packs it has and basic information on them like the version and description. client.write('resource_packs_info', { - 'must_accept': false, - 'has_scripts': false, - 'behaviour_packs': [], - 'texture_packs': [] + must_accept: false, + has_scripts: false, + behaviour_packs: [], + texture_packs: [] }) client.once('resource_pack_client_response', async (packet) => { // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs // should be applied (and downloaded) by the client. client.write('resource_pack_stack', { - 'must_accept': false, - 'behavior_packs': [], - 'resource_packs': [], - 'game_version': '', - 'experiments': [], - 'experiments_previously_used': false + must_accept: false, + behavior_packs: [], + resource_packs: [], + game_version: '', + experiments: [], + experiments_previously_used: false }) client.once('resource_pack_client_response', async (packet) => { - + }) client.write('network_settings', { @@ -56,35 +54,35 @@ server.on('connect', ({ client }) => { }) for (let i = 0; i < 3; i++) { - client.queue('inventory_slot', {"inventory_id":120,"slot":i,"uniqueid":0,"item":{"network_id":0}}) + client.queue('inventory_slot', { inventory_id: 120, slot: i, uniqueid: 0, item: { network_id: 0 } }) } client.queue('inventory_transaction', get('packets/inventory_transaction.json')) client.queue('player_list', get('packets/player_list.json')) client.queue('start_game', get('packets/start_game.json')) - client.queue('item_component', {"entries":[]}) + client.queue('item_component', { entries: [] }) client.queue('set_spawn_position', get('packets/set_spawn_position.json')) client.queue('set_time', { time: 5433771 }) client.queue('set_difficulty', { difficulty: 1 }) client.queue('set_commands_enabled', { enabled: true }) client.queue('adventure_settings', get('packets/adventure_settings.json')) - + client.queue('biome_definition_list', get('packets/biome_definition_list.json')) client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) client.queue('update_attributes', get('packets/update_attributes.json')) client.queue('creative_content', get('packets/creative_content.json')) client.queue('inventory_content', get('packets/inventory_content.json')) - client.queue('player_hotbar', {"selected_slot":3,"window_id":0,"select_slot":true}) + client.queue('player_hotbar', { selected_slot: 3, window_id: 0, select_slot: true }) client.queue('crafting_data', get('packets/crafting_data.json')) client.queue('available_commands', get('packets/available_commands.json')) - client.queue('chunk_radius_update', {"chunk_radius":5}) + client.queue('chunk_radius_update', { chunk_radius: 5 }) client.queue('set_entity_data', get('packets/set_entity_data.json')) client.queue('game_rules_changed', get('packets/game_rules_changed.json')) - client.queue('respawn', {"x":646.9405517578125,"y":65.62001037597656,"z":77.86255645751953,"state":0,"runtime_entity_id":0}) + client.queue('respawn', { x: 646.9405517578125, y: 65.62001037597656, z: 77.86255645751953, state: 0, runtime_entity_id: 0 }) for (const file of fs.readdirSync(`../data/${server.options.version}/sample/chunks`)) { const buffer = Buffer.from(fs.readFileSync(`../data/${server.options.version}/sample/chunks/` + file, 'utf8'), 'hex') @@ -97,18 +95,17 @@ server.on('connect', ({ client }) => { // } setInterval(() => { - client.write('network_chunk_publisher_update', {"coordinates":{"x":646,"y":130,"z":77},"radius":64}) + client.write('network_chunk_publisher_update', { coordinates: { x: 646, y: 130, z: 77 }, radius: 64 }) }, 9500) - setTimeout(() => { client.write('play_status', { status: 'player_spawn' }) }, 8000) // Respond to tick synchronization packets - client.on('tick_sync', ({ request_time }) => { + client.on('tick_sync', (packet) => { client.queue('tick_sync', { - request_time, + request_time: packet.request_time, response_time: BigInt(Date.now()) }) }) @@ -116,43 +113,41 @@ server.on('connect', ({ client }) => { }) }) -async function sleep(ms) { - return new Promise(res => { - setTimeout(() => { res() }, ms) - }) -} - // CHUNKS // const { ChunkColumn, Version } = require('bedrock-provider') -const mcData = require('minecraft-data')('1.16') -var chunks = [] -async function buildChunks() { - // "x": 40, - // "z": 4, - - const stone = mcData.blocksByName.stone +// const mcData = require('minecraft-data')('1.16') +// const chunks = [] +// async function buildChunks () { +// // "x": 40, +// // "z": 4, - for (var cx = 35; cx < 45; cx++) { - for (var cz = 0; cz < 8; cz++) { - const column = new ChunkColumn(Version.v1_2_0_bis, x, z) - for (var x = 0; x < 16; x++) { - for (var y = 0; y < 60; y++) { - for (var z = 0; z < 16; z++) { - column.setBlock(x,y,z,stone) - } - } - } +// const stone = mcData.blocksByName.stone - const ser = await column.networkEncodeNoCache() +// for (let cx = 35; cx < 45; cx++) { +// for (let cz = 0; cz < 8; cz++) { +// const column = new ChunkColumn(Version.v1_2_0_bis, x, z) +// for (let x = 0; x < 16; x++) { +// for (let y = 0; y < 60; y++) { +// for (let z = 0; z < 16; z++) { +// column.setBlock(x, y, z, stone) +// } +// } +// } - chunks.push({ - x:cx, z:cz, sub_chunk_count: column.sectionsLen, cache_enabled: false, - blobs: [], payload: ser - }) - } - } +// const ser = await column.networkEncodeNoCache() - // console.log('Chunks',chunks) -} +// chunks.push({ +// x: cx, +// z: cz, +// sub_chunk_count: column.sectionsLen, +// cache_enabled: false, +// blobs: [], +// payload: ser +// }) +// } +// } -// buildChunks() \ No newline at end of file +// // console.log('Chunks',chunks) +// } + +// // buildChunks() diff --git a/index.js b/index.js deleted file mode 100644 index b3da4d2..0000000 --- a/index.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -module.exports = require('./dist/index.js'); diff --git a/package.json b/package.json index 043dc14..0797ea3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,11 @@ "main": "index.js", "scripts": { "build": "cd data/new && node compile.js", - "test": "echo \"Error: no test specified\" && exit 1" + "prepare": "npm run build", + "test": "mocha", + "pretest": "npm run lint", + "lint": "standard", + "fix": "standard --fix" }, "keywords": [ "minecraft", @@ -19,19 +23,25 @@ "@xboxreplay/xboxlive-auth": "^3.3.3", "aes-js": "^3.1.2", "asn1": "^0.2.4", - "bedrock-provider": "github:extremeheat/bedrock-provider", + "bedrock-provider": "^0.1.1", "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", "jsp-raknet": "github:extremeheat/raknet#client", "minecraft-folder-path": "^1.1.0", "prismarine-nbt": "^1.5.0", - "protodef": "github:extremeheat/node-protodef#compiler", + "protodef": "github:extremeheat/node-protodef#compiler2", "raknet-native": "^0.1.0", "uuid-1345": "^0.99.7" }, "devDependencies": { - "mocha": "^2.5.3" + "@babel/eslint-parser": "^7.13.10", + "babel-eslint": "^10.1.0", + "mocha": "^2.5.3", + "standard": "^16.0.3" + }, + "standard": { + "parser": "babel-eslint" }, "repository": { "type": "git", diff --git a/src/auth/chains.js b/src/auth/chains.js index 20ded36..2c350d8 100644 --- a/src/auth/chains.js +++ b/src/auth/chains.js @@ -4,81 +4,81 @@ const constants = require('./constants') // Refer to the docs: // https://web.archive.org/web/20180917171505if_/https://confluence.yawk.at/display/PEPROTOCOL/Game+Packets#GamePackets-Login -function mcPubKeyToPem(mcPubKeyBuffer) { - console.log(mcPubKeyBuffer) - if (mcPubKeyBuffer[0] == '-') return mcPubKeyBuffer - let pem = '-----BEGIN PUBLIC KEY-----\n' - let base64PubKey = mcPubKeyBuffer.toString('base64') - const maxLineLength = 65 - while (base64PubKey.length > 0) { - pem += base64PubKey.substring(0, maxLineLength) + '\n' - base64PubKey = base64PubKey.substring(maxLineLength) - } - pem += '-----END PUBLIC KEY-----\n' - return pem +function mcPubKeyToPem (mcPubKeyBuffer) { + console.log(mcPubKeyBuffer) + if (mcPubKeyBuffer[0] === '-') return mcPubKeyBuffer + let pem = '-----BEGIN PUBLIC KEY-----\n' + let base64PubKey = mcPubKeyBuffer.toString('base64') + const maxLineLength = 65 + while (base64PubKey.length > 0) { + pem += base64PubKey.substring(0, maxLineLength) + '\n' + base64PubKey = base64PubKey.substring(maxLineLength) + } + pem += '-----END PUBLIC KEY-----\n' + return pem } -function getX5U(token) { - const [header] = token.split('.') - const hdec = Buffer.from(header, 'base64').toString('utf-8') - const hjson = JSON.parse(hdec) - return hjson.x5u +function getX5U (token) { + const [header] = token.split('.') + const hdec = Buffer.from(header, 'base64').toString('utf-8') + const hjson = JSON.parse(hdec) + return hjson.x5u } -function verifyAuth(chain) { - let data = {} +function verifyAuth (chain) { + let data = {} - // There are three JWT tokens sent to us, one signed by the client - // one signed by Mojang with the Mojang token we have and another one - // from Xbox with addition user profile data - // We verify that at least one of the tokens in the chain has been properly - // signed by Mojang by checking the x509 public key in the JWT headers - let didVerify = false - - let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it - let finalKey = null - console.log(pubKey) - for (var token of chain) { - // const decoded = jwt.decode(token, pubKey, 'ES384') - // console.log('Decoding...', token) - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - // console.log('Decoded...') - console.log('Decoded', decoded) - - // Check if signed by Mojang key - const x5u = getX5U(token) - if (x5u == constants.PUBLIC_KEY && !data.extraData?.XUID) { - didVerify = true - console.log('verified with mojang key!', x5u) - } - - // TODO: Handle `didVerify` = false - - pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u - finalKey = decoded.identityPublicKey || finalKey // non pem - data = { ...data, ...decoded } - } - // console.log('Result', data) - - return { key: finalKey, data } -} - -function verifySkin(publicKey, token) { - // console.log('token', token) - const pubKey = mcPubKeyToPem(publicKey) + // There are three JWT tokens sent to us, one signed by the client + // one signed by Mojang with the Mojang token we have and another one + // from Xbox with addition user profile data + // We verify that at least one of the tokens in the chain has been properly + // signed by Mojang by checking the x509 public key in the JWT headers + // let didVerify = false + let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it + let finalKey = null + console.log(pubKey) + for (const token of chain) { + // const decoded = jwt.decode(token, pubKey, 'ES384') + // console.log('Decoding...', token) const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + // console.log('Decoded...') + console.log('Decoded', decoded) - return decoded + // Check if signed by Mojang key + const x5u = getX5U(token) + if (x5u === constants.PUBLIC_KEY && !data.extraData?.XUID) { + // didVerify = true + console.log('verified with mojang key!', x5u) + } + + // TODO: Handle `didVerify` = false + + pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u + finalKey = decoded.identityPublicKey || finalKey // non pem + data = { ...data, ...decoded } + } + // console.log('Result', data) + + return { key: finalKey, data } } -function decodeLoginJWT(authTokens, skinTokens) { - const { key, data } = verifyAuth(authTokens) - const skinData = verifySkin(key, skinTokens) - return { key, userData: data, skinData } +function verifySkin (publicKey, token) { + // console.log('token', token) + const pubKey = mcPubKeyToPem(publicKey) + + const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + + return decoded } -function encodeLoginJWT(localChain, mojangChain) { +function decodeLoginJWT (authTokens, skinTokens) { + const { key, data } = verifyAuth(authTokens) + const skinData = verifySkin(key, skinTokens) + return { key, userData: data, skinData } +} + +function encodeLoginJWT (localChain, mojangChain) { const chains = [] chains.push(localChain) for (const chain of mojangChain) { @@ -107,4 +107,4 @@ module.exports = { encodeLoginJWT, decodeLoginJWT } // // console.log(loginPacket) // } -// // testServer() \ No newline at end of file +// // testServer() diff --git a/src/auth/constants.js b/src/auth/constants.js index 2ffbe1d..3e7ef06 100644 --- a/src/auth/constants.js +++ b/src/auth/constants.js @@ -1,3 +1,3 @@ module.exports = { - PUBLIC_KEY: 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V' + PUBLIC_KEY: 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8ELkixyLcwlZryUQcu1TvPOmI2B7vX83ndnWRUaXm74wFfa5f/lwQNTfrLVHa2PmenpGI6JhIMUJaWZrjmMj90NoKNFSNBuKdm8rYiXsfaz3K36x/1U26HpG0ZxK/V1V' } diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 21ebbdb..56afa1d 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -1,26 +1,26 @@ const JWT = require('jsonwebtoken') const crypto = require('crypto') const { Ber } = require('asn1') -const ec_pem = require('ec-pem') +const ecPem = require('ec-pem') const fs = require('fs') const DataProvider = require('../../data/provider') const SALT = '🧂' const curve = 'secp384r1' -function Encrypt(client, server, options) { +function Encrypt (client, server, options) { const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') client.ecdhKeyPair = crypto.createECDH(curve) client.ecdhKeyPair.generateKeys() client.clientX509 = writeX509PublicKey(client.ecdhKeyPair.getPublicKey()) - function startClientboundEncryption(publicKey) { + function startClientboundEncryption (publicKey) { console.warn('[encrypt] Pub key base64: ', publicKey) const pubKeyBuf = readX509PublicKey(publicKey.key) const alice = client.ecdhKeyPair - const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 + const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 const alicePEMPrivate = alicePEM.encodePrivateKey() // Shared secret from bob's public key + our private key client.sharedSecret = alice.computeSecret(pubKeyBuf) @@ -28,7 +28,7 @@ function Encrypt(client, server, options) { // Secret hash we use for packet encryption: // From the public key of the remote and the private key // of the local, a shared secret is generated using ECDH. - // The secret key bytes are then computed as + // The secret key bytes are then computed as // sha256(server_token + shared_secret). These secret key // bytes are 32 bytes long. const secretHash = crypto.createHash('sha256') @@ -49,13 +49,13 @@ function Encrypt(client, server, options) { }) // The encryption scheme is AES/CFB8/NoPadding with the - // secret key being the result of the sha256 above and + // secret key being the result of the sha256 above and // the IV being the first 16 bytes of this secret key. const initial = client.secretKeyBytes.slice(0, 16) client.startEncryption(initial) } - function startServerboundEncryption(token) { + function startServerboundEncryption (token) { console.warn('[encrypt] Starting serverbound encryption', token) const jwt = token?.token if (!jwt) { @@ -64,7 +64,7 @@ function Encrypt(client, server, options) { } // TODO: Should we do some JWT signature validation here? Seems pointless const alice = client.ecdhKeyPair - const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) + const [header, payload] = jwt.split('.').map(k => Buffer.from(k, 'base64')) const head = JSON.parse(String(header)) const body = JSON.parse(String(payload)) const serverPublicKey = readX509PublicKey(head.x5u) @@ -93,7 +93,7 @@ function Encrypt(client, server, options) { client.createClientChain = (mojangKey) => { mojangKey = mojangKey || require('./constants').PUBLIC_KEY const alice = client.ecdhKeyPair - const alicePEM = ec_pem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 + const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 const alicePEMPrivate = alicePEM.encodePrivateKey() const token = JWT.sign({ @@ -122,16 +122,16 @@ function Encrypt(client, server, options) { SkinData: 'AAAAAA==', SkinResourcePatch: 'ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfMTI4eDEyOCIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfMTI4eDEyOF9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICJhbmltYXRlZF9mYWNlIiA6ICJnZW9tZXRyeS5hbmltYXRlZF9mYWNlX3BlcnNvbmEtZTE5OTY3MmE4YzFhODdlMC0wIiwKICAgICAgImRlZmF1bHQiIDogImdlb21ldHJ5LnBlcnNvbmFfZTE5OTY3MmE4YzFhODdlMC0wIgogICB9Cn0K', SkinGeometryData: skinGeom, - "SkinImageHeight": 1, - "SkinImageWidth": 1, - "ArmSize": "wide", - "CapeData": "", - "CapeId": "", - "CapeImageHeight": 0, - "CapeImageWidth": 0, - "CapeOnClassicSkin": false, + SkinImageHeight: 1, + SkinImageWidth: 1, + ArmSize: 'wide', + CapeData: '', + CapeId: '', + CapeImageHeight: 0, + CapeImageWidth: 0, + CapeOnClassicSkin: false, PlatformOfflineId: '', - PlatformOnlineId: '', //chat + PlatformOnlineId: '', // chat // a bunch of meaningless junk CurrentInputMode: 1, DefaultInputMode: 1, @@ -144,7 +144,7 @@ function Encrypt(client, server, options) { PieceTintColors: [], SkinAnimationData: '', ThirdPartyNameOnly: false, - "SkinColor": "#ffffcd96", + SkinColor: '#ffffcd96' } payload = require('./logPack.json') const customPayload = options.userData || {} @@ -155,33 +155,33 @@ function Encrypt(client, server, options) { } } -function toBase64(string) { +function toBase64 (string) { return Buffer.from(string).toString('base64') } -function readX509PublicKey(key) { - var reader = new Ber.Reader(Buffer.from(key, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - return Buffer.from(reader.readString(Ber.BitString, true)).slice(1); +function readX509PublicKey (key) { + const reader = new Ber.Reader(Buffer.from(key, 'base64')) + reader.readSequence() + reader.readSequence() + reader.readOID() // Hey, I'm an elliptic curve + reader.readOID() // This contains the curve type, could be useful + return Buffer.from(reader.readString(Ber.BitString, true)).slice(1) } -function writeX509PublicKey(key) { - var writer = new Ber.Writer(); - writer.startSequence(); - writer.startSequence(); - writer.writeOID("1.2.840.10045.2.1"); - writer.writeOID("1.3.132.0.34"); - writer.endSequence(); - writer.writeBuffer(Buffer.concat([Buffer.from([0x00]), key]), Ber.BitString); - writer.endSequence(); - return writer.buffer.toString("base64"); +function writeX509PublicKey (key) { + const writer = new Ber.Writer() + writer.startSequence() + writer.startSequence() + writer.writeOID('1.2.840.10045.2.1') + writer.writeOID('1.3.132.0.34') + writer.endSequence() + writer.writeBuffer(Buffer.concat([Buffer.from([0x00]), key]), Ber.BitString) + writer.endSequence() + return writer.buffer.toString('base64') } module.exports = { readX509PublicKey, writeX509PublicKey, Encrypt -} \ No newline at end of file +} diff --git a/src/client.js b/src/client.js index 1bbd167..1f859e2 100644 --- a/src/client.js +++ b/src/client.js @@ -12,7 +12,7 @@ const debugging = false class Client extends Connection { /** @param {{ version: number, hostname: string, port: number }} options */ - constructor(options) { + constructor (options) { super() this.options = { ...Options.defaultOptions, ...options } this.validateOptions() @@ -33,7 +33,7 @@ class Client extends Connection { this.outLog = (...args) => console.info('C <-', ...args) } - validateOptions() { + validateOptions () { if (!this.options.hostname || this.options.port == null) throw Error('Invalid hostname/port') if (!Options.Versions[this.options.version]) { @@ -61,7 +61,7 @@ class Client extends Connection { this.connection.connect() } - sendLogin() { + sendLogin () { this.createClientChain() const chain = [ @@ -84,23 +84,22 @@ class Client extends Connection { this.emit('loggingIn') } - onDisconnectRequest(packet) { + onDisconnectRequest (packet) { // We're talking over UDP, so there is no connection to close, instead // we stop communicating with the server console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) process.exit(1) // TODO: handle } - close() { + close () { console.warn('Close not implemented!!') } - tryRencode(name, params, actual) { + tryRencode (name, params, actual) { const packet = this.serializer.createPacketBuffer({ name, params }) - console.assert(packet.toString('hex') == actual.toString('hex')) + console.assert(packet.toString('hex') === actual.toString('hex')) if (packet.toString('hex') !== actual.toString('hex')) { - const ours = packet.toString('hex').match(/.{1,16}/g).join('\n') const theirs = actual.toString('hex').match(/.{1,16}/g).join('\n') @@ -113,10 +112,10 @@ class Client extends Connection { } } - readPacket(packet) { + readPacket (packet) { const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } - this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100)*/) + this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100) */) if (debugging) { // Packet verifying (decode + re-encode + match test) @@ -161,4 +160,4 @@ class Client extends Connection { } } -module.exports = { Client } \ No newline at end of file +module.exports = { Client } diff --git a/src/client/auth.js b/src/client/auth.js index 20775d2..f4d139f 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -9,7 +9,7 @@ const { MsAuthFlow } = require('./authFlow.js') async function postAuthenticate (client, options, chains) { // First chain is Mojang stuff, second is Xbox profile data used by mc const jwt = chains[1] - const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) + const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) // eslint-disable-line const xboxProfile = JSON.parse(String(payload)) // This profile / session here could be simplified down to where it just passes the uuid of the player to encrypt.js @@ -17,7 +17,7 @@ async function postAuthenticate (client, options, chains) { // - Kashalls const profile = { name: xboxProfile?.extraData?.displayName || 'Player', - uuid: xboxProfile?.extraData?.identity || 'adfcf5ca-206c-404a-aec4-f59fff264c9b', //random + uuid: xboxProfile?.extraData?.identity || 'adfcf5ca-206c-404a-aec4-f59fff264c9b', // random xuid: xboxProfile?.extraData?.XUID || 0 } diff --git a/src/client/authConstants.js b/src/client/authConstants.js index 26e052d..65c2575 100644 --- a/src/client/authConstants.js +++ b/src/client/authConstants.js @@ -1,4 +1,4 @@ module.exports = { - XSTSRelyingParty: 'https://multiplayer.minecraft.net/', - MinecraftAuth: 'https://multiplayer.minecraft.net/authentication' + XSTSRelyingParty: 'https://multiplayer.minecraft.net/', + MinecraftAuth: 'https://multiplayer.minecraft.net/authentication' } diff --git a/src/client/authFlow.js b/src/client/authFlow.js index 1c0325f..7e496ba 100644 --- a/src/client/authFlow.js +++ b/src/client/authFlow.js @@ -13,15 +13,16 @@ const msalConfig = { // the minecraft client: // clientId: "000000004C12AE6F", clientId: '389b1b32-b5d5-43b2-bddc-84ce938d6737', // token from https://github.com/microsoft/Office365APIEditor - authority: 'https://login.microsoftonline.com/consumers', + authority: 'https://login.microsoftonline.com/consumers' } } -async function retry (methodFn, beforeRety, times) { +async function retry (methodFn, beforeRetry, times) { while (times--) { if (times !== 0) { try { return await methodFn() } catch (e) { debug(e) } - await beforeRety() + await new Promise(resolve => setTimeout(resolve, 2000)) + await beforeRetry() } else { return await methodFn() } @@ -111,7 +112,7 @@ class MsAuthFlow { async getMinecraftToken (publicKey) { // TODO: Fix cache, in order to do cache we also need to cache the ECDH keys so disable it // is this even a good idea to cache? - if (await this.mca.verifyTokens() && false) { + if (await this.mca.verifyTokens() && false) { // eslint-disable-line debug('[mc] Using existing tokens') return this.mca.getCachedAccessToken().chain } else { diff --git a/src/client/tokens.js b/src/client/tokens.js index 1959211..9ed3a18 100644 --- a/src/client/tokens.js +++ b/src/client/tokens.js @@ -8,7 +8,7 @@ const authConstants = require('./authConstants') // Manages Microsoft account tokens class MsaTokenManager { - constructor(msalConfig, scopes, cacheLocation) { + constructor (msalConfig, scopes, cacheLocation) { this.msaClientId = msalConfig.auth.clientId this.scopes = scopes this.cacheLocation = cacheLocation || path.join(__dirname, './msa-cache.json') @@ -42,7 +42,7 @@ class MsaTokenManager { this.msalConfig = msalConfig } - getUsers() { + getUsers () { const accounts = this.msaCache.Account const users = [] if (!accounts) return users @@ -52,7 +52,7 @@ class MsaTokenManager { return users } - getAccessToken() { + getAccessToken () { const tokens = this.msaCache.AccessToken if (!tokens) return const account = Object.values(tokens).filter(t => t.client_id === this.msaClientId)[0] @@ -65,7 +65,7 @@ class MsaTokenManager { return { valid, until: until, token: account.secret } } - getRefreshToken() { + getRefreshToken () { const tokens = this.msaCache.RefreshToken if (!tokens) return const account = Object.values(tokens).filter(t => t.client_id === this.msaClientId)[0] @@ -76,7 +76,7 @@ class MsaTokenManager { return { token: account.secret } } - async refreshTokens() { + async refreshTokens () { const rtoken = this.getRefreshToken() if (!rtoken) { throw new Error('Cannot refresh without refresh token') @@ -97,7 +97,7 @@ class MsaTokenManager { }) } - async verifyTokens() { + async verifyTokens () { const at = this.getAccessToken() const rt = this.getRefreshToken() if (!at || !rt || this.forceRefresh) { @@ -111,13 +111,14 @@ class MsaTokenManager { await this.refreshTokens() return true } catch (e) { + console.warn('Error refreshing token', e) // TODO: looks like an error happens here return false } } } // Authenticate with device_code flow - async authDeviceCode(dataCallback) { + async authDeviceCode (dataCallback) { const deviceCodeRequest = { deviceCodeCallback: (resp) => { debug('[msa] device_code response: ', resp) @@ -142,7 +143,7 @@ class MsaTokenManager { // Manages Xbox Live tokens for xboxlive.com class XboxTokenManager { - constructor(relyingParty, cacheLocation) { + constructor (relyingParty, cacheLocation) { this.relyingParty = relyingParty this.cacheLocation = cacheLocation || path.join(__dirname, './xbl-cache.json') try { @@ -152,7 +153,7 @@ class XboxTokenManager { } } - getCachedUserToken() { + getCachedUserToken () { const token = this.cache.userToken if (!token) return const until = new Date(token.NotAfter) @@ -162,7 +163,7 @@ class XboxTokenManager { return { valid, token: token.Token, data: token } } - getCachedXstsToken() { + getCachedXstsToken () { const token = this.cache.xstsToken if (!token) return const until = new Date(token.expiresOn) @@ -172,17 +173,17 @@ class XboxTokenManager { return { valid, token: token.XSTSToken, data: token } } - setCachedUserToken(data) { + setCachedUserToken (data) { this.cache.userToken = data fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) } - setCachedXstsToken(data) { + setCachedXstsToken (data) { this.cache.xstsToken = data fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) } - async verifyTokens() { + async verifyTokens () { const ut = this.getCachedUserToken() const xt = this.getCachedXstsToken() if (!ut || !xt || this.forceRefresh) { @@ -202,7 +203,7 @@ class XboxTokenManager { return false } - async getUserToken(msaAccessToken) { + async getUserToken (msaAccessToken) { debug('[xbl] obtaining xbox token with ms token', msaAccessToken) if (!msaAccessToken.startsWith('d=')) { msaAccessToken = 'd=' + msaAccessToken } const xblUserToken = await XboxLiveAuth.exchangeRpsTicketForUserToken(msaAccessToken) @@ -211,7 +212,7 @@ class XboxTokenManager { return xblUserToken } - async getXSTSToken(xblUserToken) { + async getXSTSToken (xblUserToken) { debug('[xbl] obtaining xsts token with xbox user token', xblUserToken.Token) const xsts = await XboxLiveAuth.exchangeUserTokenForXSTSIdentity( xblUserToken.Token, { XSTSRelyingParty: this.relyingParty, raw: false } @@ -224,7 +225,7 @@ class XboxTokenManager { // Manages Minecraft tokens for sessionserver.mojang.com class MinecraftTokenManager { - constructor(clientPublicKey, cacheLocation) { + constructor (clientPublicKey, cacheLocation) { this.clientPublicKey = clientPublicKey this.cacheLocation = cacheLocation || path.join(__dirname, './bed-cache.json') try { @@ -234,13 +235,13 @@ class MinecraftTokenManager { } } - getCachedAccessToken() { + getCachedAccessToken () { const token = this.cache.mca debug('[mc] token cache', this.cache) if (!token) return console.log('TOKEN', token) const jwt = token.chain[0] - const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) + const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) // eslint-disable-line const body = JSON.parse(String(payload)) const expires = new Date(body.exp * 1000) @@ -249,13 +250,13 @@ class MinecraftTokenManager { return { valid, until: expires, chain: token.chain } } - setCachedAccessToken(data) { + setCachedAccessToken (data) { data.obtainedOn = Date.now() this.cache.mca = data fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) } - async verifyTokens() { + async verifyTokens () { const at = this.getCachedAccessToken() if (!at || this.forceRefresh) { return false @@ -267,13 +268,13 @@ class MinecraftTokenManager { return false } - async getAccessToken(clientPublicKey, xsts) { + async getAccessToken (clientPublicKey, xsts) { debug('[mc] authing to minecraft', clientPublicKey, xsts) const getFetchOptions = { headers: { 'Content-Type': 'application/json', 'User-Agent': 'node-minecraft-protocol', - 'Authorization': `XBL3.0 x=${xsts.userHash};${xsts.XSTSToken}` + Authorization: `XBL3.0 x=${xsts.userHash};${xsts.XSTSToken}` } } const MineServicesResponse = await fetch(authConstants.MinecraftAuth, { @@ -288,7 +289,7 @@ class MinecraftTokenManager { } } -function checkStatus(res) { +function checkStatus (res) { if (res.ok) { // res.status >= 200 && res.status < 300 return res.json() } else { diff --git a/src/connection.js b/src/connection.js index eda0ca9..ba03549 100644 --- a/src/connection.js +++ b/src/connection.js @@ -5,8 +5,10 @@ const { EventEmitter } = require('events') const Versions = require('./options') const debug = require('debug')('minecraft-protocol') +const SKIP_BATCH = ['level_chunk', 'client_cache_blob_status', 'client_cache_miss_response'] + class Connection extends EventEmitter { - versionLessThan(version) { + versionLessThan (version) { if (typeof version === 'string') { return Versions[version] < this.options.version } else { @@ -14,7 +16,7 @@ class Connection extends EventEmitter { } } - versionGreaterThan(version) { + versionGreaterThan (version) { if (typeof version === 'string') { return Versions[version] > this.options.version } else { @@ -22,7 +24,7 @@ class Connection extends EventEmitter { } } - startEncryption(iv) { + startEncryption (iv) { this.encryptionEnabled = true this.inLog('Started encryption', this.sharedSecret, iv) this.decrypt = cipher.createDecryptor(this, iv) @@ -30,7 +32,7 @@ class Connection extends EventEmitter { this.q2 = [] } - write(name, params) { + write (name, params) { this.outLog('sending', name, params) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) @@ -43,10 +45,10 @@ class Connection extends EventEmitter { } } - queue(name, params) { + queue (name, params) { this.outLog('Q <- ', name, params) const packet = this.serializer.createPacketBuffer({ name, params }) - if (name == 'level_chunk' || name=='client_cache_blob_status' || name == 'client_cache_miss_response') { + if (SKIP_BATCH.includes(name)) { // Skip queue, send ASAP this.sendBuffer(packet) return @@ -55,11 +57,11 @@ class Connection extends EventEmitter { this.q2.push(name) } - startQueue() { + startQueue () { this.q = [] this.loop = setInterval(() => { if (this.q.length) { - //TODO: can we just build Batch before the queue loop? + // TODO: can we just build Batch before the queue loop? const batch = new BatchPacket() this.outLog('<- BATCH', this.q2) const sending = [] @@ -78,11 +80,10 @@ class Connection extends EventEmitter { }, 20) } - /** * Sends a MCPE packet buffer */ - sendBuffer(buffer, immediate = false) { + sendBuffer (buffer, immediate = false) { if (immediate) { const batch = new BatchPacket() batch.addEncodedPacket(buffer) @@ -97,20 +98,20 @@ class Connection extends EventEmitter { } } - sendDecryptedBatch(batch) { + sendDecryptedBatch (batch) { const buf = batch.encode() // send to raknet this.sendMCPE(buf, true) } - sendEncryptedBatch(batch) { + sendEncryptedBatch (batch) { const buf = batch.stream.getBuffer() debug('Sending encrypted batch', batch) this.encrypt(buf) } // TODO: Rename this to sendEncapsulated - sendMCPE(buffer, immediate) { + sendMCPE (buffer, immediate) { this.connection.sendReliable(buffer, immediate) } @@ -132,8 +133,8 @@ class Connection extends EventEmitter { } } - handle(buffer) { // handle encapsulated - if (buffer[0] == 0xfe) { // wrapper + handle (buffer) { // handle encapsulated + if (buffer[0] === 0xfe) { // wrapper if (this.encryptionEnabled) { this.decrypt(buffer.slice(1)) } else { @@ -142,7 +143,7 @@ class Connection extends EventEmitter { batch.decode() const packets = batch.getPackets() this.inLog('Reading ', packets.length, 'packets') - for (var packet of packets) { + for (const packet of packets) { this.readPacket(packet) } } @@ -150,4 +151,4 @@ class Connection extends EventEmitter { } } -module.exports = { Connection } \ No newline at end of file +module.exports = { Connection } diff --git a/src/datatypes/BatchPacket.js b/src/datatypes/BatchPacket.js index 52f4320..cdfb292 100644 --- a/src/datatypes/BatchPacket.js +++ b/src/datatypes/BatchPacket.js @@ -1,11 +1,11 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default -const Zlib = require('zlib'); +const Zlib = require('zlib') const NETWORK_ID = 0xfe // This is not a real MCPE packet, it's a wrapper that contains compressed/encrypted batched packets class BatchPacket { - constructor(stream) { + constructor (stream) { // Shared this.payload = Buffer.alloc(0) this.stream = stream || new BinaryStream() @@ -18,9 +18,9 @@ class BatchPacket { this.count = 0 } - decode() { + decode () { // Read header - const pid = this.stream.readByte(); + const pid = this.stream.readByte() if (!pid === NETWORK_ID) { throw new Error(`Batch ID mismatch: is ${BatchPacket.NETWORK_ID}, got ${pid}`) // this is not a BatchPacket } @@ -29,14 +29,14 @@ class BatchPacket { try { this.payload = Zlib.inflateRawSync(this.stream.readRemaining(), { chunkSize: 1024 * 1024 * 2 - }); + }) } catch (e) { console.error(e) console.debug(`[bp] Error decompressing packet ${pid}`) } } - encode() { + encode () { const buf = this.stream.getBuffer() console.log('Encoding payload', buf) const def = Zlib.deflateRawSync(buf, { level: this.compressionLevel }) @@ -45,13 +45,13 @@ class BatchPacket { return ret } - addEncodedPacket(packet) { + addEncodedPacket (packet) { this.stream.writeUnsignedVarInt(packet.byteLength) this.stream.append(packet) this.count++ } - getPackets() { + getPackets () { const stream = new BinaryStream() stream.buffer = this.payload const packets = [] @@ -64,7 +64,7 @@ class BatchPacket { return packets } - static getPackets(stream) { + static getPackets (stream) { const packets = [] while (!stream.feof()) { const length = stream.readUnsignedVarInt() @@ -76,4 +76,4 @@ class BatchPacket { } } -module.exports = BatchPacket \ No newline at end of file +module.exports = BatchPacket diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index a4ab558..b5fda57 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -1,3 +1,4 @@ +/* eslint-disable */ const UUID = require('uuid-1345') const minecraft = require('./minecraft') const { Read, Write, SizeOf } = require('./varlong') @@ -78,19 +79,6 @@ SizeOf.nbt = ['native', minecraft.nbt[2]] /** * Bits */ -// nvm, -// Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { -// return compiler.wrapCode(` -// const { value, size } = ${compiler.callType('buffer, offset', type)} -// const val = {} -// for (let i = 0; i < size; i++) { -// const hi = (value >> i) & 1 -// if () -// const v = value & -// if (flags[i]) -// } -// ` -// }] Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { return compiler.wrapCode(` @@ -104,7 +92,6 @@ Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { `.trim()) }] - Write.bitflags = ['parametrizable', (compiler, { type, flags }) => { return compiler.wrapCode(` const flags = ${JSON.stringify(flags)} @@ -155,12 +142,12 @@ SizeOf.enum_size_based_on_values_len = ['parametrizable', (compiler) => { }) }] -function js(fn) { +function js (fn) { return fn.toString().split('\n').slice(1, -1).join('\n').trim() } -function str(fn) { +function str (fn) { return fn.toString() + ')();(()=>{}' } -module.exports = { Read, Write, SizeOf } \ No newline at end of file +module.exports = { Read, Write, SizeOf } diff --git a/src/datatypes/minecraft.js b/src/datatypes/minecraft.js index f16b16c..9ca4920 100644 --- a/src/datatypes/minecraft.js +++ b/src/datatypes/minecraft.js @@ -1,139 +1,139 @@ -var nbt = require('prismarine-nbt') +/* eslint-disable */ +const nbt = require('prismarine-nbt') const UUID = require('uuid-1345') const proto = nbt.protos.littleVarint // TODO: deal with this: -var zigzag = require('prismarine-nbt/compiler-zigzag') +const zigzag = require('prismarine-nbt/compiler-zigzag') -function readUUID(buffer, offset) { - if (offset + 16 > buffer.length) - throw new PartialReadError(); +function readUUID (buffer, offset) { + if (offset + 16 > buffer.length) { throw new PartialReadError() } return { value: UUID.stringify(buffer.slice(offset, 16 + offset)), size: 16 - }; + } } -function writeUUID(value, buffer, offset) { - const buf = UUID.parse(value); - buf.copy(buffer, offset); - return offset + 16; +function writeUUID (value, buffer, offset) { + const buf = UUID.parse(value) + buf.copy(buffer, offset) + return offset + 16 } -function readNbt(buffer, offset) { - return proto.read(buffer, offset, "nbt") +function readNbt (buffer, offset) { + return proto.read(buffer, offset, 'nbt') } -function writeNbt(value, buffer, offset) { - return proto.write(value, buffer, offset, "nbt") +function writeNbt (value, buffer, offset) { + return proto.write(value, buffer, offset, 'nbt') } -function sizeOfNbt(value) { - return proto.sizeOf(value, "nbt") +function sizeOfNbt (value) { + return proto.sizeOf(value, 'nbt') } -function readEntityMetadata(buffer, offset, _ref) { - var type = _ref.type; - var endVal = _ref.endVal; +function readEntityMetadata (buffer, offset, _ref) { + const type = _ref.type + const endVal = _ref.endVal - var cursor = offset; - var metadata = []; - var item = undefined; + let cursor = offset + const metadata = [] + let item while (true) { - if (offset + 1 > buffer.length) throw new PartialReadError(); - item = buffer.readUInt8(cursor); + if (offset + 1 > buffer.length) throw new PartialReadError() + item = buffer.readUInt8(cursor) if (item === endVal) { return { value: metadata, size: cursor + 1 - offset - }; + } } - var results = this.read(buffer, cursor, type, {}); - metadata.push(results.value); - cursor += results.size; + const results = this.read(buffer, cursor, type, {}) + metadata.push(results.value) + cursor += results.size } } -function writeEntityMetadata(value, buffer, offset, _ref2) { - var type = _ref2.type; - var endVal = _ref2.endVal; +function writeEntityMetadata (value, buffer, offset, _ref2) { + const type = _ref2.type + const endVal = _ref2.endVal - var self = this; + const self = this value.forEach(function (item) { - offset = self.write(item, buffer, offset, type, {}); - }); - buffer.writeUInt8(endVal, offset); - return offset + 1; + offset = self.write(item, buffer, offset, type, {}) + }) + buffer.writeUInt8(endVal, offset) + return offset + 1 } -function sizeOfEntityMetadata(value, _ref3) { - var type = _ref3.type; +function sizeOfEntityMetadata (value, _ref3) { + const type = _ref3.type - var size = 1; - for (var i = 0; i < value.length; ++i) { - size += this.sizeOf(value[i], type, {}); + let size = 1 + for (let i = 0; i < value.length; ++i) { + size += this.sizeOf(value[i], type, {}) } - return size; + return size } -function readIpAddress(buffer, offset) { - var address = buffer[offset] + '.' + buffer[offset + 1] + '.' + buffer[offset + 2] + '.' + buffer[offset + 3]; +function readIpAddress (buffer, offset) { + const address = buffer[offset] + '.' + buffer[offset + 1] + '.' + buffer[offset + 2] + '.' + buffer[offset + 3] return { size: 4, value: address } } -function writeIpAddress(value, buffer, offset) { - var address = value.split('.'); +function writeIpAddress (value, buffer, offset) { + const address = value.split('.') address.forEach(function (b) { - buffer[offset] = parseInt(b); - offset++; - }); + buffer[offset] = parseInt(b) + offset++ + }) - return offset; + return offset } -function readEndOfArray(buffer, offset, typeArgs) { - var type = typeArgs.type; - var cursor = offset; - var elements = []; +function readEndOfArray (buffer, offset, typeArgs) { + const type = typeArgs.type + let cursor = offset + const elements = [] while (cursor < buffer.length) { - var results = this.read(buffer, cursor, type, {}); - elements.push(results.value); - cursor += results.size; + const results = this.read(buffer, cursor, type, {}) + elements.push(results.value) + cursor += results.size } return { value: elements, size: cursor - offset - }; -} - -function writeEndOfArray(value, buffer, offset, typeArgs) { - var type = typeArgs.type; - var self = this; - value.forEach(function (item) { - offset = self.write(item, buffer, offset, type, {}); - }); - return offset; -} - -function sizeOfEndOfArray(value, typeArgs) { - var type = typeArgs.type; - var size = 0; - for (var i = 0; i < value.length; ++i) { - size += this.sizeOf(value[i], type, {}); } - return size; +} + +function writeEndOfArray (value, buffer, offset, typeArgs) { + const type = typeArgs.type + const self = this + value.forEach(function (item) { + offset = self.write(item, buffer, offset, type, {}) + }) + return offset +} + +function sizeOfEndOfArray (value, typeArgs) { + const type = typeArgs.type + let size = 0 + for (let i = 0; i < value.length; ++i) { + size += this.sizeOf(value[i], type, {}) + } + return size } module.exports = { - 'uuid': [readUUID, writeUUID, 16], - 'nbt': [readNbt, writeNbt, sizeOfNbt], - 'entityMetadataLoop': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata], - 'ipAddress': [readIpAddress, writeIpAddress, 4], - 'endOfArray': [readEndOfArray, writeEndOfArray, sizeOfEndOfArray], - 'zigzag32': zigzag.zigzag32, - 'zigzag64': zigzag.zigzag64 -} \ No newline at end of file + uuid: [readUUID, writeUUID, 16], + nbt: [readNbt, writeNbt, sizeOfNbt], + entityMetadataLoop: [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata], + ipAddress: [readIpAddress, writeIpAddress, 4], + endOfArray: [readEndOfArray, writeEndOfArray, sizeOfEndOfArray], + zigzag32: zigzag.zigzag32, + zigzag64: zigzag.zigzag64 +} diff --git a/src/datatypes/util.js b/src/datatypes/util.js index 1c8c3d8..029df2b 100644 --- a/src/datatypes/util.js +++ b/src/datatypes/util.js @@ -1,37 +1,33 @@ -const fs = require('fs'); +const fs = require('fs') -function getFiles(dir) { - var results = []; - var list = fs.readdirSync(dir); - list.forEach(function (file) { - file = dir + '/' + file; - var stat = fs.statSync(file); +function getFiles (dir) { + let results = [] + const list = fs.readdirSync(dir) + list.forEach((file) => { + file = dir + '/' + file + const stat = fs.statSync(file) if (stat && stat.isDirectory()) { - /* Recurse into a subdirectory */ - results = results.concat(getFiles(file)); + results = results.concat(getFiles(file)) } else { - /* Is a file */ - results.push(file); + results.push(file) } - }); - return results; + }) + return results } -module.exports = { - sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)) - }, +function sleep (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) +} - waitFor(cb, withTimeout) { - return Promise.race([ - new Promise((res, rej) => cb(res)), - sleep(withTimeout) - ]) - }, +function waitFor (cb, withTimeout) { + return Promise.race([ + new Promise((resolve) => cb(resolve)), + sleep(withTimeout) + ]) +} - serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) - }, +function serialize (obj = {}, fmt) { + return JSON.stringify(obj, (k, v) => typeof v === 'bigint' ? v.toString() : v, fmt) +} - getFiles -} \ No newline at end of file +module.exports = { getFiles, sleep, waitFor, serialize } diff --git a/src/datatypes/varlong.js b/src/datatypes/varlong.js index fa1059f..5e57ad7 100644 --- a/src/datatypes/varlong.js +++ b/src/datatypes/varlong.js @@ -1,4 +1,4 @@ -function sizeOfVarLong(value) { +function sizeOfVarLong (value) { if (typeof value.valueOf() === 'object') { value = (BigInt(value[0]) << 32n) | BigInt(value[1]) } else if (typeof value !== 'bigint') value = BigInt(value) @@ -14,7 +14,7 @@ function sizeOfVarLong(value) { /** * Reads a 64-bit VarInt as a BigInt */ -function readVarLong(buffer, offset) { +function readVarLong (buffer, offset) { let result = BigInt(0) let shift = 0n let cursor = offset @@ -39,7 +39,7 @@ function readVarLong(buffer, offset) { /** * Writes a zigzag encoded 64-bit VarInt as a BigInt */ -function writeVarLong(value, buffer, offset) { +function writeVarLong (value, buffer, offset) { // if an array, turn it into a BigInt if (typeof value.valueOf() === 'object') { value = BigInt.asIntN(64, (BigInt(value[0]) << 32n)) | BigInt(value[1]) @@ -60,4 +60,4 @@ module.exports = { Read: { varint64: ['native', readVarLong] }, Write: { varint64: ['native', writeVarLong] }, SizeOf: { varint64: ['native', sizeOfVarLong] } -} \ No newline at end of file +} diff --git a/src/options.js b/src/options.js index e6fb930..9d204e1 100644 --- a/src/options.js +++ b/src/options.js @@ -13,4 +13,4 @@ const Versions = { '1.16.201': 422 } -module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } \ No newline at end of file +module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } diff --git a/src/rak.js b/src/rak.js index 09510ad..c08fe83 100644 --- a/src/rak.js +++ b/src/rak.js @@ -1,26 +1,25 @@ const { EventEmitter } = require('events') const Listener = require('jsp-raknet/listener') const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') +const Reliability = require('jsp-raknet/protocol/reliability') const RakClient = require('jsp-raknet/client') const ConnWorker = require('./rakWorker') const { waitFor } = require('./datatypes/util') try { - var { Client, Server, PacketPriority, PacketReliability, McPingMessage } = require('raknet-native') + var { Client, Server, PacketPriority, PacketReliability, McPingMessage } = require('raknet-native') // eslint-disable-line } catch (e) { console.debug('[raknet] native not found, using js', e) } class RakNativeClient extends EventEmitter { - constructor(options) { + constructor (options) { super() this.onConnected = () => { } this.onCloseConnection = () => { } this.onEncapsulated = () => { } this.raknet = new Client(options.hostname, options.port, 'minecraft') - this.raknet.on('encapsulated', thingy => { - // console.log('Encap',thingy) - const { buffer, address, guid } = thingy + this.raknet.on('encapsulated', ({ buffer, address }) => { this.onEncapsulated(buffer, address) }) this.raknet.on('connected', () => { @@ -28,7 +27,7 @@ class RakNativeClient extends EventEmitter { }) } - async ping() { + async ping () { this.raknet.ping() return waitFor((done) => { this.raknet.on('pong', (ret) => { @@ -39,18 +38,18 @@ class RakNativeClient extends EventEmitter { }, 1000) } - connect() { + connect () { this.raknet.connect() } - sendReliable(buffer, immediate) { + sendReliable (buffer, immediate) { const priority = immediate ? PacketPriority.IMMEDIATE_PRIORITY : PacketPriority.MEDIUM_PRIORITY return this.raknet.send(buffer, priority, PacketReliability.RELIABLE_ORDERED, 0) } } class RakNativeServer extends EventEmitter { - constructor(options = {}) { + constructor (options = {}) { super() this.onOpenConnection = () => { } this.onCloseConnection = () => { } @@ -75,20 +74,19 @@ class RakNativeServer extends EventEmitter { this.onCloseConnection(client) }) - this.raknet.on('encapsulated', (thingy) => { - const { buffer, address, guid } = thingy + this.raknet.on('encapsulated', ({ buffer, address }) => { // console.log('ENCAP',thingy) this.onEncapsulated(buffer, address) }) } - listen() { + listen () { this.raknet.listen() } } class RakJsClient extends EventEmitter { - constructor(options = {}) { + constructor (options = {}) { super() this.onConnected = () => { } this.onEncapsulated = () => { } @@ -101,23 +99,25 @@ class RakJsClient extends EventEmitter { } } - workerConnect(hostname = this.options.hostname, port = this.options.port) { + workerConnect (hostname = this.options.hostname, port = this.options.port) { this.worker = ConnWorker.connect(hostname, port) this.worker.on('message', (evt) => { switch (evt.type) { - case 'connected': + case 'connected': { this.onConnected() break - case 'encapsulated': + } + case 'encapsulated': { const [ecapsulated, address] = evt.args this.onEncapsulated(ecapsulated.buffer, address.hash) break + } } }) } - async plainConnect(hostname = this.options.hostname, port = this.options.port) { + async plainConnect (hostname = this.options.hostname, port = this.options.port) { this.raknet = new RakClient(hostname, port) await this.raknet.connect() @@ -129,11 +129,11 @@ class RakJsClient extends EventEmitter { this.raknet.on('encapsulated', (encapsulated, addr) => this.onEncapsulated(encapsulated.buffer, addr.hash)) } - workerSendReliable(buffer, immediate) { + workerSendReliable (buffer, immediate) { this.worker.postMessage({ type: 'queueEncapsulated', packet: buffer, immediate }) } - plainSendReliable(buffer, immediate) { + plainSendReliable (buffer, immediate) { const sendPacket = new EncapsulatedPacket() sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = buffer @@ -143,7 +143,7 @@ class RakJsClient extends EventEmitter { } class RakJsServer extends EventEmitter { - constructor(options = {}) { + constructor (options = {}) { super() this.options = options this.onOpenConnection = () => { } @@ -157,7 +157,7 @@ class RakJsServer extends EventEmitter { } } - async plainListen() { + async plainListen () { this.raknet = new Listener() await this.raknet.listen(this.options.hostname, this.options.port) this.raknet.on('openConnection', (conn) => { @@ -178,4 +178,4 @@ class RakJsServer extends EventEmitter { module.exports = { RakClient: Client ? RakNativeClient : RakJsClient, RakServer: Server ? RakNativeServer : RakJsServer -} \ No newline at end of file +} diff --git a/src/rakWorker.js b/src/rakWorker.js index 3dc837a..d9a4bc5 100644 --- a/src/rakWorker.js +++ b/src/rakWorker.js @@ -3,7 +3,7 @@ const { Worker, isMainThread, parentPort } = require('worker_threads') const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') const Reliability = require('jsp-raknet/protocol/reliability') -function connect(hostname, port) { +function connect (hostname, port) { if (isMainThread) { const worker = new Worker(__filename) worker.postMessage({ type: 'connect', hostname, port }) @@ -11,12 +11,12 @@ function connect(hostname, port) { } } -var raknet +let raknet -function main() { +function main () { parentPort.on('message', (evt) => { - if (evt.type == 'connect') { - const { hostname, port } =evt + if (evt.type === 'connect') { + const { hostname, port } = evt raknet = new RakClient(hostname, port) raknet.connect().then(() => { @@ -30,7 +30,7 @@ function main() { }) raknet.once('connected', (connection) => { - console.log(`[worker] connected!`) + console.log('[worker] connected!') globalThis.raknetConnection = connection parentPort.postMessage({ type: 'connected' }) }) @@ -45,8 +45,8 @@ function main() { raknet.on('raw', (buffer, inetAddr) => { console.log('Raw packet', buffer, inetAddr) }) - } else if (evt.type == 'queueEncapsulated') { - console.log('SEND' , globalThis.raknetConnection, evt.packet) + } else if (evt.type === 'queueEncapsulated') { + // console.log('SEND', globalThis.raknetConnection, evt.packet) const sendPacket = new EncapsulatedPacket() sendPacket.reliability = Reliability.ReliableOrdered @@ -61,4 +61,4 @@ function main() { } if (!isMainThread) main() -module.exports = { connect } \ No newline at end of file +module.exports = { connect } diff --git a/src/relay.js b/src/relay.js index 08314d1..dbb15c5 100644 --- a/src/relay.js +++ b/src/relay.js @@ -1,8 +1,7 @@ // process.env.DEBUG = 'minecraft-protocol raknet' -const fs = require('fs') -const { Client } = require("./client") -const { Server } = require("./server") -const { Player } = require("./serverPlayer") +const { Client } = require('./client') +const { Server } = require('./server') +const { Player } = require('./serverPlayer') const debug = require('debug')('minecraft-protocol relay') const { serialize } = require('./datatypes/util') @@ -11,7 +10,7 @@ const { serialize } = require('./datatypes/util') const debugging = true // Do re-encoding tests class RelayPlayer extends Player { - constructor(server, conn) { + constructor (server, conn) { super(server, conn) this.server = server this.conn = conn @@ -47,7 +46,7 @@ class RelayPlayer extends Player { } // Called when we get a packet from backend server (Backend -> PROXY -> Client) - readUpstream(packet) { + readUpstream (packet) { if (!this.startRelaying) { console.warn('The downstream client is not ready yet !!') this.downQ.push(packet) @@ -59,7 +58,7 @@ class RelayPlayer extends Player { const params = des.data.params this.upInLog('~ Bounce B->C', name, serialize(params).slice(0, 100)) // this.upInLog('~ ', des.buffer) - if (name == 'play_status' && params.status == 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect + if (name === 'play_status' && params.status === 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect if (debugging) { // some packet encode/decode testing stuff const rpacket = this.server.serializer.createPacketBuffer({ name, params }) @@ -76,7 +75,7 @@ class RelayPlayer extends Player { } // Send queued packets to the connected client - flushDownQueue() { + flushDownQueue () { for (const packet of this.downQ) { const des = this.server.deserializer.parsePacketBuffer(packet) this.write(des.data.name, des.data.params) @@ -85,10 +84,10 @@ class RelayPlayer extends Player { } // Send queued packets to the backend upstream server from the client - flushUpQueue() { - for (var e of this.upQ) { // Send the queue + flushUpQueue () { + for (const e of this.upQ) { // Send the queue const des = this.server.deserializer.parsePacketBuffer(e) - if (des.data.name == 'client_cache_status') { // Currently broken, force off the chunk cache + if (des.data.name === 'client_cache_status') { // Currently broken, force off the chunk cache this.upstream.write('client_cache_status', { enabled: false }) } else { this.upstream.write(des.data.name, des.data.params) @@ -98,8 +97,8 @@ class RelayPlayer extends Player { } // Called when the server gets a packet from the downstream player (Client -> PROXY -> Backend) - readPacket(packet) { - if (this.startRelaying) { // The downstream client conn is established & we got a packet to send to upstream server + readPacket (packet) { + if (this.startRelaying) { // The downstream client conn is established & we got a packet to send to upstream server if (!this.upstream) { // Upstream is still connecting/handshaking this.downInLog('Got downstream connected packet but upstream is not connected yet, added to q', this.upQ.length) this.upQ.push(packet) // Put into a queue @@ -138,16 +137,16 @@ class RelayPlayer extends Player { class Relay extends Server { /** * Creates a new non-transparent proxy connection to a destination server - * @param {Options} options + * @param {Options} options */ - constructor(options) { + constructor (options) { super(options) this.RelayPlayer = options.relayPlayer || RelayPlayer this.forceSingle = true this.upstreams = new Map() } - openUpstreamConnection(ds, clientAddr) { + openUpstreamConnection (ds, clientAddr) { const client = new Client({ hostname: this.options.destination.hostname, port: this.options.destination.port, @@ -165,7 +164,7 @@ class Relay extends Server { this.upstreams.set(clientAddr.hash, client) } - closeUpstreamConnection(clientAddr) { + closeUpstreamConnection (clientAddr) { const up = this.upstreams.get(clientAddr.hash) if (!up) throw Error(`unable to close non-open connection ${clientAddr.hash}`) up.close() @@ -189,4 +188,4 @@ class Relay extends Server { } // Too many things called 'Proxy' ;) -module.exports = { Relay } \ No newline at end of file +module.exports = { Relay } diff --git a/src/server.js b/src/server.js index 1dff4e7..94010d0 100644 --- a/src/server.js +++ b/src/server.js @@ -6,7 +6,7 @@ const Options = require('./options') const debug = require('debug')('minecraft-protocol') class Server extends EventEmitter { - constructor(options) { + constructor (options) { super() this.options = { ...Options.defaultOptions, ...options } this.validateOptions() @@ -18,7 +18,7 @@ class Server extends EventEmitter { this.outLog = (...args) => console.debug('S -> C', ...args) } - validateOptions() { + validateOptions () { if (!Options.Versions[this.options.version]) { console.warn('Supported versions: ', Options.Versions) throw Error(`Unsupported version ${this.options.version}`) @@ -52,7 +52,7 @@ class Server extends EventEmitter { client.handle(buffer) } - async create(hostname = this.options.hostname, port = this.options.port) { + async create (hostname = this.options.hostname, port = this.options.port) { this.raknet = new RakServer({ hostname, port }) await this.raknet.listen() console.debug('Listening on', hostname, port) @@ -62,4 +62,4 @@ class Server extends EventEmitter { } } -module.exports = { Server } \ No newline at end of file +module.exports = { Server } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 3f41817..4a33aed 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -2,7 +2,8 @@ const { Encrypt } = require('./auth/encryption') const { decodeLoginJWT } = require('./auth/chains') const { Connection } = require('./connection') const fs = require('fs') -const debug = require('debug')('minecraft-protocol') +// const debug = require('debug')('minecraft-protocol') +const { MIN_VERSION } = require('./options') const ClientStatus = { Authenticating: 0, @@ -11,7 +12,7 @@ const ClientStatus = { } class Player extends Connection { - constructor(server, connection) { + constructor (server, connection) { super() this.server = server this.serializer = server.serializer @@ -26,12 +27,12 @@ class Player extends Connection { this.outLog = (...args) => console.info('C -> S', ...args) } - getData() { + getData () { return this.userData } - onLogin(packet) { - let body = packet.data + onLogin (packet) { + const body = packet.data // debug('Login body', body) this.emit('loggingIn', body) @@ -51,7 +52,7 @@ class Player extends Connection { const skinChain = body.params.client_data try { - var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) + var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line } catch (e) { console.error(e) // TODO: disconnect user @@ -68,17 +69,17 @@ class Player extends Connection { /** * Disconnects a client before it has joined - * @param {string} play_status + * @param {string} playStatus */ - sendDisconnectStatus(play_status) { - this.write('play_status', { status: play_status }) + sendDisconnectStatus (playStatus) { + this.write('play_status', { status: playStatus }) this.connection.close() } /** * Disconnects a client after it has joined */ - disconnect(reason, hide = false) { + disconnect (reason, hide = false) { this.write('disconnect', { hide_disconnect_screen: hide, message: reason @@ -88,7 +89,7 @@ class Player extends Connection { // After sending Server to Client Handshake, this handles the client's // Client to Server handshake response. This indicates successful encryption - onHandshake() { + onHandshake () { // this.outLog('Sending login success!', this.status) // https://wiki.vg/Bedrock_Protocol#Play_Status this.write('play_status', { status: 'login_success' }) @@ -96,10 +97,10 @@ class Player extends Connection { this.emit('join') } - readPacket(packet) { + readPacket (packet) { // console.log('packet', packet) try { - var des = this.server.deserializer.parsePacketBuffer(packet) + var des = this.server.deserializer.parsePacketBuffer(packet) // eslint-disable-line } catch (e) { this.disconnect('Server error') console.warn('Packet parsing failed! Writing dump to ./packetdump.bin') @@ -117,10 +118,12 @@ class Player extends Connection { case 'client_to_server_handshake': // Emit the 'join' event this.onHandshake() + break case 'set_local_player_as_initialized': this.state = ClientStatus.Initialized // Emit the 'spawn' event this.emit('spawn') + break default: console.log('ignoring, unhandled') } @@ -128,4 +131,4 @@ class Player extends Connection { } } -module.exports = { Player, ClientStatus } \ No newline at end of file +module.exports = { Player, ClientStatus } diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index d2c1794..1822238 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -5,14 +5,14 @@ const Zlib = require('zlib') const CIPHER_ALG = 'aes-256-cfb8' -function createCipher(secret, initialValue) { +function createCipher (secret, initialValue) { if (crypto.getCiphers().includes(CIPHER_ALG)) { return crypto.createCipheriv(CIPHER_ALG, secret, initialValue) } return new Cipher(secret, initialValue) } -function createDecipher(secret, initialValue) { +function createDecipher (secret, initialValue) { if (crypto.getCiphers().includes(CIPHER_ALG)) { return crypto.createDecipheriv(CIPHER_ALG, secret, initialValue) } @@ -20,12 +20,12 @@ function createDecipher(secret, initialValue) { } class Cipher extends Transform { - constructor(secret, iv) { + constructor (secret, iv) { super() this.aes = new aesjs.ModeOfOperation.cfb(secret, iv, 1) // eslint-disable-line new-cap } - _transform(chunk, enc, cb) { + _transform (chunk, enc, cb) { try { const res = this.aes.encrypt(chunk) cb(null, res) @@ -36,12 +36,12 @@ class Cipher extends Transform { } class Decipher extends Transform { - constructor(secret, iv) { + constructor (secret, iv) { super() this.aes = new aesjs.ModeOfOperation.cfb(secret, iv, 1) // eslint-disable-line new-cap } - _transform(chunk, enc, cb) { + _transform (chunk, enc, cb) { try { const res = this.aes.decrypt(chunk) cb(null, res) @@ -51,26 +51,26 @@ class Decipher extends Transform { } } -function computeCheckSum(packetPlaintext, sendCounter, secretKeyBytes) { - let digest = crypto.createHash('sha256'); - let counter = Buffer.alloc(8) +function computeCheckSum (packetPlaintext, sendCounter, secretKeyBytes) { + const digest = crypto.createHash('sha256') + const counter = Buffer.alloc(8) counter.writeBigInt64LE(sendCounter, 0) - digest.update(counter); - digest.update(packetPlaintext); - digest.update(secretKeyBytes); - let hash = digest.digest(); - return hash.slice(0, 8); + digest.update(counter) + digest.update(packetPlaintext) + digest.update(secretKeyBytes) + const hash = digest.digest() + return hash.slice(0, 8) } -function createEncryptor(client, iv) { +function createEncryptor (client, iv) { client.cipher = createCipher(client.secretKeyBytes, iv) client.sendCounter = client.sendCounter || 0n // A packet is encrypted via AES256(plaintext + SHA256(send_counter + plaintext + secret_key)[0:8]). // The send counter is represented as a little-endian 64-bit long and incremented after each packet. - function process(chunk) { - const buffer = Zlib.deflateRawSync(chunk, { level: 7 }) + function process (chunk) { + const buffer = Zlib.deflateRawSync(chunk, { level: 7 }) const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) client.sendCounter++ client.cipher.write(packet) @@ -83,12 +83,11 @@ function createEncryptor(client, iv) { } } - -function createDecryptor(client, iv) { +function createDecryptor (client, iv) { client.decipher = createDecipher(client.secretKeyBytes, iv) client.receiveCounter = client.receiveCounter || 0n - function verify(chunk) { + function verify (chunk) { // TODO: remove the extra logic here, probably fixed with new raknet impl // console.log('Decryptor: checking checksum', client.receiveCounter, chunk) @@ -102,7 +101,7 @@ function createDecryptor(client, iv) { // Holds how much bytes we read, also where the checksum (should) start const inflatedLen = engine.bytesRead // It appears that mc sends extra bytes past the checksum. I don't think this is a raknet - // issue (as we are able to decipher properly, zlib works and should also have a checksum) so + // issue (as we are able to decipher properly, zlib works and should also have a checksum) so // there needs to be more investigation done. If you know what's wrong here, please make an issue :) const extraneousLen = chunk.length - inflatedLen - 8 if (extraneousLen > 0) { // Extra bytes @@ -115,16 +114,16 @@ function createDecryptor(client, iv) { throw new Error('Decrypted packet is missing checksum') } - const packet = chunk.slice(0, inflatedLen); - const checksum = chunk.slice(inflatedLen, inflatedLen + 8); + const packet = chunk.slice(0, inflatedLen) + const checksum = chunk.slice(inflatedLen, inflatedLen + 8) const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) client.receiveCounter++ - if (checksum.toString("hex") == computedCheckSum.toString("hex")) { + if (checksum.toString('hex') === computedCheckSum.toString('hex')) { client.onDecryptedPacket(buffer) } else { console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex')) - throw Error(`Checksum mismatch ${checksum.toString("hex")} != ${computedCheckSum.toString("hex")}`) + throw Error(`Checksum mismatch ${checksum.toString('hex')} != ${computedCheckSum.toString('hex')}`) } } @@ -139,16 +138,16 @@ module.exports = { createCipher, createDecipher, createEncryptor, createDecryptor } -function testDecrypt() { - const client = { - secretKeyBytes: Buffer.from('ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=', 'base64'), - onDecryptedPacket: (...data) => console.log('Decrypted', data) - } - const iv = Buffer.from('ZOBpyzki/M8UZv5tiBih0w==', 'base64') +// function testDecrypt () { +// const client = { +// secretKeyBytes: Buffer.from('ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=', 'base64'), +// onDecryptedPacket: (...data) => console.log('Decrypted', data) +// } +// const iv = Buffer.from('ZOBpyzki/M8UZv5tiBih0w==', 'base64') - const decrypt = createDecryptor(client, iv) - console.log('Dec', decrypt(Buffer.from('4B4FCA0C2A4114155D67F8092154AAA5EF', 'hex'))) - console.log('Dec 2', decrypt(Buffer.from('DF53B9764DB48252FA1AE3AEE4', 'hex'))) -} +// const decrypt = createDecryptor(client, iv) +// console.log('Dec', decrypt(Buffer.from('4B4FCA0C2A4114155D67F8092154AAA5EF', 'hex'))) +// console.log('Dec 2', decrypt(Buffer.from('DF53B9764DB48252FA1AE3AEE4', 'hex'))) +// } -// testDecrypt() \ No newline at end of file +// testDecrypt() diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index c7a70ed..bbaac1a 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -2,9 +2,9 @@ const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler const { FullPacketParser, Serializer } = require('protodef') // Compiles the ProtoDef schema at runtime -function createProtocol(version) { +function createProtocol (version) { const protocol = require(`../../data/${version}/protocol.json`).types - var compiler = new ProtoDefCompiler() + const compiler = new ProtoDefCompiler() compiler.addTypesToCompile(protocol) compiler.addTypes(require('../datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) @@ -14,7 +14,7 @@ function createProtocol(version) { } // Loads already generated read/write/sizeof code -function getProtocol(version) { +function getProtocol (version) { const compiler = new ProtoDefCompiler() compiler.addTypes(require('../datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) @@ -32,18 +32,18 @@ function getProtocol(version) { ) } -function createSerializer(version) { - var proto = getProtocol(version) - return new Serializer(proto, 'mcpe_packet'); +function createSerializer (version) { + const proto = getProtocol(version) + return new Serializer(proto, 'mcpe_packet') } -function createDeserializer(version) { - var proto = getProtocol(version) - return new FullPacketParser(proto, 'mcpe_packet'); +function createDeserializer (version) { + const proto = getProtocol(version) + return new FullPacketParser(proto, 'mcpe_packet') } module.exports = { createDeserializer: createDeserializer, createSerializer: createSerializer, createProtocol: createProtocol -} \ No newline at end of file +} From 66ba0c8a5c8d612ce180951ef9287803d9d156b6 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 13 Mar 2021 19:46:25 +0100 Subject: [PATCH 118/458] Bump mocha from 2.5.3 to 8.3.2 (#46) Bumps [mocha](https://github.com/mochajs/mocha) from 2.5.3 to 8.3.2. - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v2.5.3...v8.3.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0797ea3..d59dbdf 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "devDependencies": { "@babel/eslint-parser": "^7.13.10", "babel-eslint": "^10.1.0", - "mocha": "^2.5.3", + "mocha": "^8.3.2", "standard": "^16.0.3" }, "standard": { From ff787ba8adfac75181816360846e31d287701e15 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 13 Mar 2021 19:46:40 +0100 Subject: [PATCH 119/458] Bump uuid-1345 from 0.99.7 to 1.0.2 (#41) Bumps [uuid-1345](https://github.com/scravy/uuid-1345) from 0.99.7 to 1.0.2. - [Release notes](https://github.com/scravy/uuid-1345/releases) - [Commits](https://github.com/scravy/uuid-1345/compare/0.99.7...1.0.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d59dbdf..9de80f9 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "prismarine-nbt": "^1.5.0", "protodef": "github:extremeheat/node-protodef#compiler2", "raknet-native": "^0.1.0", - "uuid-1345": "^0.99.7" + "uuid-1345": "^1.0.2" }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", From 58e011e06d5aa4ecf03c5caf76779f0d11ab9647 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 13 Mar 2021 13:50:16 -0500 Subject: [PATCH 120/458] Login refactoring (#45) * Refactor auth + encryption Fix a bug with client account token caching * move some files --- data/{new => latest}/proto.yml | 94 +-------------- data/{new => latest}/types.yaml | 10 +- data/provider.js | 4 +- src/auth/chains.js | 110 ------------------ src/auth/encryption.js | 85 ++------------ src/auth/login.js | 73 ++++++++++++ src/auth/loginVerify.js | 83 +++++++++++++ src/client.js | 15 ++- src/client/tokens.js | 17 ++- src/server.js | 2 +- src/serverPlayer.js | 18 +-- src/transforms/encryption.js | 40 ++----- .../compile.js => tools/compileProtocol.js | 0 13 files changed, 218 insertions(+), 333 deletions(-) rename data/{new => latest}/proto.yml (96%) rename data/{new => latest}/types.yaml (98%) delete mode 100644 src/auth/chains.js create mode 100644 src/auth/login.js create mode 100644 src/auth/loginVerify.js rename data/new/compile.js => tools/compileProtocol.js (100%) diff --git a/data/new/proto.yml b/data/latest/proto.yml similarity index 96% rename from data/new/proto.yml rename to data/latest/proto.yml index f296075..6253c5a 100644 --- a/data/new/proto.yml +++ b/data/latest/proto.yml @@ -945,8 +945,7 @@ packet_inventory_slot: slot: varint # NewItem is the item to be put in the slot at Slot. It will overwrite any item that may currently # be present in that slot. - uniqueid: zigzag32 - item: Item + item: ItemStack # ContainerSetData is sent by the server to update specific data of a single container, meaning a block such # as a furnace or a brewing stand. This data is usually used by the client to display certain features @@ -1325,97 +1324,6 @@ packet_available_commands: 43: raw_text 46: json 53: command - # 15: unknown15 - # 16: unknown16 - # 125: unknown125 - # 126: unknown126 - # 22: unknown22 - # 10: unknown10 - # 39: unknown39 - # 18: unknown18 - # 20: unknown20 - # 19: unknown19 - # 7: unknown7 - # 23: unknown23 - # 24: unknown24 - # 13: unknown13 - # 25: unknown25 - # 40: unknown40 - # 56: unknown56 - # 26: unknown26 - # 27: unknown27 - # 28: unknown28 - # 31: unknown31 - # 30: unknown30 - # 0: unknown0 - # 32: unknown32 - # 49: unknown49 - # 12: unknown12 - # 35: unknown35 - # 36: unknown36 - # 38: unknown38 - # 44: unknown44 - # 47: unknown47 - # 45: unknown45 - # 48: unknown48 - # 55: unknown55 - # 54: unknown54 - # 50: unknown50 - # 51: unknown51 - # 52: unknown52 - # 9: unknown9 - # 123: unknown123 - # 57: unknown57 - # 58: unknown58 - # 59: unknown59 - # 60: unknown60 - # 61: unknown61 - # 63: unknown63 - # 75: unknown75 - # 64: unknown64 - # 67: unknown67 - # 66: unknown66 - # 73: unknown73 - # 72: unknown72 - # 74: unknown74 - # 62: unknown62 - # 68: unknown68 - # 69: unknown69 - # 65: unknown65 - # 70: unknown70 - # 71: unknown71 - # 76: unknown76 - # 77: unknown77 - # 79: unknown79 - # 78: unknown78 - # 80: unknown80 - # 81: unknown81 - # 82: unknown82 - # 83: unknown83 - # 84: unknown84 - # 87: unknown87 - # 88: unknown88 - # 92: unknown92 - # 89: unknown89 - # 90: unknown90 - # 91: unknown91 - # 93: unknown93 - # 95: unknown95 - # 94: unknown94 - # 98: unknown98 - # 96: unknown96 - # 97: unknown97 - # 99: unknown99 - # 100: unknown100 - # 101: unknown101 - # 102: unknown102 - # 103: unknown103 - # 104: unknown104 - # 105: unknown105 - # 106: unknown106 - # 107: unknown107 - # 108: unknown108 - # 124: unknown124 # In MC, this + prior field are combined to one 32bit bitfield enum_type: lu16 => 0x10: valid diff --git a/data/new/types.yaml b/data/latest/types.yaml similarity index 98% rename from data/new/types.yaml rename to data/latest/types.yaml index adf7b3b..6a8cecc 100644 --- a/data/new/types.yaml +++ b/data/latest/types.yaml @@ -408,10 +408,18 @@ Transaction: # mainly for purposes such as spawning eating particles at that position. head_pos: vec3f -ItemStacks: []varint +# An "ItemStack" here represents an Item instance. You can think about it like a pointer +# to an item class. The data for the class gets updated with the data in the `item` field +ItemStack: + # StackNetworkID is the network ID of the item stack. If the stack is empty, 0 is always written for this + # field. If not, the field should be set to 1 if the server authoritative inventories are disabled in the + # StartGame packet, or to a unique stack ID if it is enabled. runtime_id: zigzag32 + # Stack is the actual item stack of the item instance. item: Item +ItemStacks: ItemStack[]varint + RecipeIngredient: network_id: zigzag32 _: network_id? diff --git a/data/provider.js b/data/provider.js index 437d53a..098564a 100644 --- a/data/provider.js +++ b/data/provider.js @@ -14,7 +14,7 @@ function loadVersions () { files = getFiles(join(__dirname, '/', version)) } catch {} for (const file of files) { - const rfile = file.replace(join(__dirname, '/', version), '') + const rfile = file.replace(join(__dirname, '/', version) + '/', '') fileMap[rfile] ??= [] fileMap[rfile].push([Versions[version], file]) fileMap[rfile].sort().reverse() @@ -42,5 +42,3 @@ module.exports = (protocolVersion) => { } loadVersions() -// console.log('file map', fileMap) -// module.exports(Versions['1.16.210']).open('creativeitems.json') diff --git a/src/auth/chains.js b/src/auth/chains.js deleted file mode 100644 index 2c350d8..0000000 --- a/src/auth/chains.js +++ /dev/null @@ -1,110 +0,0 @@ -const JWT = require('jsonwebtoken') -const constants = require('./constants') - -// Refer to the docs: -// https://web.archive.org/web/20180917171505if_/https://confluence.yawk.at/display/PEPROTOCOL/Game+Packets#GamePackets-Login - -function mcPubKeyToPem (mcPubKeyBuffer) { - console.log(mcPubKeyBuffer) - if (mcPubKeyBuffer[0] === '-') return mcPubKeyBuffer - let pem = '-----BEGIN PUBLIC KEY-----\n' - let base64PubKey = mcPubKeyBuffer.toString('base64') - const maxLineLength = 65 - while (base64PubKey.length > 0) { - pem += base64PubKey.substring(0, maxLineLength) + '\n' - base64PubKey = base64PubKey.substring(maxLineLength) - } - pem += '-----END PUBLIC KEY-----\n' - return pem -} - -function getX5U (token) { - const [header] = token.split('.') - const hdec = Buffer.from(header, 'base64').toString('utf-8') - const hjson = JSON.parse(hdec) - return hjson.x5u -} - -function verifyAuth (chain) { - let data = {} - - // There are three JWT tokens sent to us, one signed by the client - // one signed by Mojang with the Mojang token we have and another one - // from Xbox with addition user profile data - // We verify that at least one of the tokens in the chain has been properly - // signed by Mojang by checking the x509 public key in the JWT headers - // let didVerify = false - - let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it - let finalKey = null - console.log(pubKey) - for (const token of chain) { - // const decoded = jwt.decode(token, pubKey, 'ES384') - // console.log('Decoding...', token) - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - // console.log('Decoded...') - console.log('Decoded', decoded) - - // Check if signed by Mojang key - const x5u = getX5U(token) - if (x5u === constants.PUBLIC_KEY && !data.extraData?.XUID) { - // didVerify = true - console.log('verified with mojang key!', x5u) - } - - // TODO: Handle `didVerify` = false - - pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u - finalKey = decoded.identityPublicKey || finalKey // non pem - data = { ...data, ...decoded } - } - // console.log('Result', data) - - return { key: finalKey, data } -} - -function verifySkin (publicKey, token) { - // console.log('token', token) - const pubKey = mcPubKeyToPem(publicKey) - - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - - return decoded -} - -function decodeLoginJWT (authTokens, skinTokens) { - const { key, data } = verifyAuth(authTokens) - const skinData = verifySkin(key, skinTokens) - return { key, userData: data, skinData } -} - -function encodeLoginJWT (localChain, mojangChain) { - const chains = [] - chains.push(localChain) - for (const chain of mojangChain) { - chains.push(chain) - } - return chains -} - -module.exports = { encodeLoginJWT, decodeLoginJWT } - -// function testServer() { -// const loginPacket = require('./login.json') - -// // console.log(loginPacket) -// const authChains = JSON.parse(loginPacket.data.chain) -// const skinChain = loginPacket.data.clientData - -// try { -// var { data, chain } = decodeLoginJWT(authChains.chain, skinChain) -// } catch (e) { -// console.error(e) -// throw new Error('Failed to verify user') -// } - -// console.log('Authed') -// // console.log(loginPacket) -// } - -// // testServer() diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 56afa1d..99d8d34 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -1,28 +1,25 @@ +const { Ber } = require('asn1') const JWT = require('jsonwebtoken') const crypto = require('crypto') -const { Ber } = require('asn1') const ecPem = require('ec-pem') -const fs = require('fs') -const DataProvider = require('../../data/provider') +const debug = require('debug')('minecraft-protocol') const SALT = '🧂' const curve = 'secp384r1' function Encrypt (client, server, options) { - const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') - client.ecdhKeyPair = crypto.createECDH(curve) client.ecdhKeyPair.generateKeys() client.clientX509 = writeX509PublicKey(client.ecdhKeyPair.getPublicKey()) function startClientboundEncryption (publicKey) { - console.warn('[encrypt] Pub key base64: ', publicKey) + debug('[encrypt] Client pub key base64: ', publicKey) const pubKeyBuf = readX509PublicKey(publicKey.key) const alice = client.ecdhKeyPair const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 const alicePEMPrivate = alicePEM.encodePrivateKey() - // Shared secret from bob's public key + our private key + // Shared secret from the client's public key + our private key client.sharedSecret = alice.computeSecret(pubKeyBuf) // Secret hash we use for packet encryption: @@ -34,10 +31,10 @@ function Encrypt (client, server, options) { const secretHash = crypto.createHash('sha256') secretHash.update(SALT) secretHash.update(client.sharedSecret) - console.log('[encrypt] Shared secret', client.sharedSecret) + // console.log('[encrypt] Shared secret', client.sharedSecret) client.secretKeyBytes = secretHash.digest() - console.log('[encrypt] Shared hash', client.secretKeyBytes) + // console.log('[encrypt] Shared hash', client.secretKeyBytes) const x509 = writeX509PublicKey(alice.getPublicKey()) const token = JWT.sign({ salt: toBase64(SALT), @@ -56,7 +53,7 @@ function Encrypt (client, server, options) { } function startServerboundEncryption (token) { - console.warn('[encrypt] Starting serverbound encryption', token) + debug('[encrypt] Starting serverbound encryption', token) const jwt = token?.token if (!jwt) { // TODO: allow connecting to servers without encryption @@ -69,7 +66,7 @@ function Encrypt (client, server, options) { const body = JSON.parse(String(payload)) const serverPublicKey = readX509PublicKey(head.x5u) client.sharedSecret = alice.computeSecret(serverPublicKey) - console.log('[encrypt] Shared secret', client.sharedSecret) + // console.log('[encrypt] Shared secret', client.sharedSecret) const salt = Buffer.from(body.salt, 'base64') @@ -78,7 +75,7 @@ function Encrypt (client, server, options) { secretHash.update(client.sharedSecret) client.secretKeyBytes = secretHash.digest() - console.log('[encrypt] Shared hash', client.secretKeyBytes) + // console.log('[encrypt] Shared hash', client.secretKeyBytes) const initial = client.secretKeyBytes.slice(0, 16) client.startEncryption(initial) @@ -89,70 +86,6 @@ function Encrypt (client, server, options) { client.on('server.client_handshake', startClientboundEncryption) client.on('client.server_handshake', startServerboundEncryption) - - client.createClientChain = (mojangKey) => { - mojangKey = mojangKey || require('./constants').PUBLIC_KEY - const alice = client.ecdhKeyPair - const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 - const alicePEMPrivate = alicePEM.encodePrivateKey() - - const token = JWT.sign({ - identityPublicKey: mojangKey, - certificateAuthority: true - }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: client.clientX509 } }) - - client.clientIdentityChain = token - client.createClientUserChain(alicePEMPrivate) - } - - client.createClientUserChain = (privateKey) => { - let payload = { - ServerAddress: options.hostname, - ThirdPartyName: client.profile.name, - DeviceOS: client.session?.deviceOS || 1, - GameVersion: options.version || '1.16.201', - ClientRandomId: Date.now(), // TODO make biggeer - DeviceId: '2099de18-429a-465a-a49b-fc4710a17bb3', // TODO random - LanguageCode: 'en_GB', // TODO locale - AnimatedImageData: [], - PersonaPieces: [], - PieceTintColours: [], - SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343701', - SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', - SkinData: 'AAAAAA==', - SkinResourcePatch: 'ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfMTI4eDEyOCIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfMTI4eDEyOF9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICJhbmltYXRlZF9mYWNlIiA6ICJnZW9tZXRyeS5hbmltYXRlZF9mYWNlX3BlcnNvbmEtZTE5OTY3MmE4YzFhODdlMC0wIiwKICAgICAgImRlZmF1bHQiIDogImdlb21ldHJ5LnBlcnNvbmFfZTE5OTY3MmE4YzFhODdlMC0wIgogICB9Cn0K', - SkinGeometryData: skinGeom, - SkinImageHeight: 1, - SkinImageWidth: 1, - ArmSize: 'wide', - CapeData: '', - CapeId: '', - CapeImageHeight: 0, - CapeImageWidth: 0, - CapeOnClassicSkin: false, - PlatformOfflineId: '', - PlatformOnlineId: '', // chat - // a bunch of meaningless junk - CurrentInputMode: 1, - DefaultInputMode: 1, - DeviceModel: '', - GuiScale: -1, - UIProfile: 0, - TenantId: '', - PremiumSkin: false, - PersonaSkin: false, - PieceTintColors: [], - SkinAnimationData: '', - ThirdPartyNameOnly: false, - SkinColor: '#ffffcd96' - } - payload = require('./logPack.json') - const customPayload = options.userData || {} - payload = { ...payload, ...customPayload } - - client.clientUserChain = JWT.sign(payload, privateKey, - { algorithm: 'ES384', header: { x5u: client.clientX509 } }) - } } function toBase64 (string) { diff --git a/src/auth/login.js b/src/auth/login.js new file mode 100644 index 0000000..e414c5d --- /dev/null +++ b/src/auth/login.js @@ -0,0 +1,73 @@ +const fs = require('fs') +const JWT = require('jsonwebtoken') +const DataProvider = require('../../data/provider') +const ecPem = require('ec-pem') +const curve = 'secp384r1' + +module.exports = (client, server, options) => { + const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') + + client.createClientChain = (mojangKey) => { + mojangKey = mojangKey || require('./constants').PUBLIC_KEY + const alice = client.ecdhKeyPair + const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 + const alicePEMPrivate = alicePEM.encodePrivateKey() + + const token = JWT.sign({ + identityPublicKey: mojangKey, + certificateAuthority: true + }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + + client.clientIdentityChain = token + client.createClientUserChain(alicePEMPrivate) + } + + client.createClientUserChain = (privateKey) => { + let payload = { + ServerAddress: options.hostname, + ThirdPartyName: client.profile.name, + DeviceOS: client.session?.deviceOS || 1, + GameVersion: options.version || '1.16.201', + ClientRandomId: Date.now(), // TODO make biggeer + DeviceId: '2099de18-429a-465a-a49b-fc4710a17bb3', // TODO random + LanguageCode: 'en_GB', // TODO locale + AnimatedImageData: [], + PersonaPieces: [], + PieceTintColours: [], + SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343701', + SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', + SkinData: 'AAAAAA==', + SkinResourcePatch: 'ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfMTI4eDEyOCIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfMTI4eDEyOF9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICJhbmltYXRlZF9mYWNlIiA6ICJnZW9tZXRyeS5hbmltYXRlZF9mYWNlX3BlcnNvbmEtZTE5OTY3MmE4YzFhODdlMC0wIiwKICAgICAgImRlZmF1bHQiIDogImdlb21ldHJ5LnBlcnNvbmFfZTE5OTY3MmE4YzFhODdlMC0wIgogICB9Cn0K', + SkinGeometryData: skinGeom, + SkinImageHeight: 1, + SkinImageWidth: 1, + ArmSize: 'wide', + CapeData: '', + CapeId: '', + CapeImageHeight: 0, + CapeImageWidth: 0, + CapeOnClassicSkin: false, + PlatformOfflineId: '', + PlatformOnlineId: '', // chat + // a bunch of meaningless junk + CurrentInputMode: 1, + DefaultInputMode: 1, + DeviceModel: '', + GuiScale: -1, + UIProfile: 0, + TenantId: '', + PremiumSkin: false, + PersonaSkin: false, + PieceTintColors: [], + SkinAnimationData: '', + ThirdPartyNameOnly: false, + SkinColor: '#ffffcd96' + } + payload = require('./logPack.json') + const customPayload = options.userData || {} + payload = { ...payload, ...customPayload } + + client.clientUserChain = JWT.sign(payload, privateKey, + { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + } +} diff --git a/src/auth/loginVerify.js b/src/auth/loginVerify.js new file mode 100644 index 0000000..6d21e41 --- /dev/null +++ b/src/auth/loginVerify.js @@ -0,0 +1,83 @@ +const JWT = require('jsonwebtoken') +const constants = require('./constants') + +module.exports = (client, server, options) => { + // Refer to the docs: + // https://web.archive.org/web/20180917171505if_/https://confluence.yawk.at/display/PEPROTOCOL/Game+Packets#GamePackets-Login + + function verifyAuth (chain) { + let data = {} + + // There are three JWT tokens sent to us, one signed by the client + // one signed by Mojang with the Mojang token we have and another one + // from Xbox with addition user profile data + // We verify that at least one of the tokens in the chain has been properly + // signed by Mojang by checking the x509 public key in the JWT headers + // let didVerify = false + + let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it + let finalKey = null + console.log(pubKey) + for (const token of chain) { + const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + console.log('Decoded', decoded) + + // Check if signed by Mojang key + const x5u = getX5U(token) + if (x5u === constants.PUBLIC_KEY && !data.extraData?.XUID) { + // didVerify = true + console.log('verified with mojang key!', x5u) + } + + // TODO: Handle `didVerify` = false + pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u + finalKey = decoded.identityPublicKey || finalKey // non pem + data = { ...data, ...decoded } + } + // console.log('Result', data) + + return { key: finalKey, data } + } + + function verifySkin (publicKey, token) { + const pubKey = mcPubKeyToPem(publicKey) + const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + return decoded + } + + client.decodeLoginJWT = (authTokens, skinTokens) => { + const { key, data } = verifyAuth(authTokens) + const skinData = verifySkin(key, skinTokens) + return { key, userData: data, skinData } + } + + client.encodeLoginJWT = (localChain, mojangChain) => { + const chains = [] + chains.push(localChain) + for (const chain of mojangChain) { + chains.push(chain) + } + return chains + } +} + +function getX5U (token) { + const [header] = token.split('.') + const hdec = Buffer.from(header, 'base64').toString('utf-8') + const hjson = JSON.parse(hdec) + return hjson.x5u +} + +function mcPubKeyToPem (mcPubKeyBuffer) { + console.log(mcPubKeyBuffer) + if (mcPubKeyBuffer[0] === '-') return mcPubKeyBuffer + let pem = '-----BEGIN PUBLIC KEY-----\n' + let base64PubKey = mcPubKeyBuffer.toString('base64') + const maxLineLength = 65 + while (base64PubKey.length > 0) { + pem += base64PubKey.substring(0, maxLineLength) + '\n' + base64PubKey = base64PubKey.substring(maxLineLength) + } + pem += '-----END PUBLIC KEY-----\n' + return pem +} diff --git a/src/client.js b/src/client.js index 1f859e2..5b6c960 100644 --- a/src/client.js +++ b/src/client.js @@ -1,12 +1,15 @@ -const fs = require('fs') -const debug = require('debug')('minecraft-protocol') -const auth = require('./client/auth') -const Options = require('./options') const { Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') -const { Encrypt } = require('./auth/encryption') const { RakClient } = require('./Rak') const { serialize } = require('./datatypes/util') +const fs = require('fs') +const debug = require('debug')('minecraft-protocol') +const Options = require('./options') +const auth = require('./client/auth') + +const { Encrypt } = require('./auth/encryption') +const Login = require('./auth/login') +const LoginVerify = require('./auth/loginVerify') const debugging = false @@ -20,6 +23,8 @@ class Client extends Connection { this.deserializer = createDeserializer(this.options.version) Encrypt(this, null, this.options) + Login(this, null, this.options) + LoginVerify(this, null, this.options) if (options.password) { auth.authenticatePassword(this, options) diff --git a/src/client/tokens.js b/src/client/tokens.js index 9ed3a18..af82f45 100644 --- a/src/client/tokens.js +++ b/src/client/tokens.js @@ -13,12 +13,7 @@ class MsaTokenManager { this.scopes = scopes this.cacheLocation = cacheLocation || path.join(__dirname, './msa-cache.json') - try { - this.msaCache = require(this.cacheLocation) - } catch (e) { - this.msaCache = {} - fs.writeFileSync(this.cacheLocation, JSON.stringify(this.msaCache)) - } + this.reloadCache() const beforeCacheAccess = async (cacheContext) => { cacheContext.tokenCache.deserialize(await fs.promises.readFile(this.cacheLocation, 'utf-8')) @@ -42,6 +37,15 @@ class MsaTokenManager { this.msalConfig = msalConfig } + reloadCache () { + try { + this.msaCache = require(this.cacheLocation) + } catch (e) { + this.msaCache = {} + fs.writeFileSync(this.cacheLocation, JSON.stringify(this.msaCache)) + } + } + getUsers () { const accounts = this.msaCache.Account const users = [] @@ -89,6 +93,7 @@ class MsaTokenManager { return new Promise((resolve, reject) => { this.msalApp.acquireTokenByRefreshToken(refreshTokenRequest).then((response) => { debug('[msa] refreshed token', JSON.stringify(response)) + this.reloadCache() resolve(response) }).catch((error) => { debug('[msa] failed to refresh', JSON.stringify(error)) diff --git a/src/server.js b/src/server.js index 94010d0..bb98d34 100644 --- a/src/server.js +++ b/src/server.js @@ -44,7 +44,7 @@ class Server extends EventEmitter { } onEncapsulated = (buffer, address) => { - this.inLog('encapsulated', address, buffer) + // this.inLog('encapsulated', address, buffer) const client = this.clients[address] if (!client) { throw new Error(`packet from unknown inet addr: ${address}`) diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 4a33aed..a699ec0 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -1,9 +1,10 @@ -const { Encrypt } = require('./auth/encryption') -const { decodeLoginJWT } = require('./auth/chains') const { Connection } = require('./connection') const fs = require('fs') -// const debug = require('debug')('minecraft-protocol') -const { MIN_VERSION } = require('./options') +const Options = require('./options') + +const { Encrypt } = require('./auth/encryption') +const Login = require('./auth/login') +const LoginVerify = require('./auth/loginVerify') const ClientStatus = { Authenticating: 0, @@ -19,7 +20,10 @@ class Player extends Connection { this.deserializer = server.deserializer this.connection = connection this.options = server.options - Encrypt(this, server, this.options) + + Encrypt(this, server, server.options) + Login(this, server, server.options) + LoginVerify(this, server, server.options) this.startQueue() this.status = ClientStatus.Authenticating @@ -42,7 +46,7 @@ class Player extends Connection { this.sendDisconnectStatus('failed_client') return } - } else if (clientVer < MIN_VERSION) { + } else if (clientVer < Options.MIN_VERSION) { this.sendDisconnectStatus('failed_client') return } @@ -52,7 +56,7 @@ class Player extends Connection { const skinChain = body.params.client_data try { - var { key, userData, chain } = decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line + var { key, userData, chain } = this.decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line } catch (e) { console.error(e) // TODO: disconnect user diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 1822238..41432c1 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -88,43 +88,21 @@ function createDecryptor (client, iv) { client.receiveCounter = client.receiveCounter || 0n function verify (chunk) { - // TODO: remove the extra logic here, probably fixed with new raknet impl - // console.log('Decryptor: checking checksum', client.receiveCounter, chunk) - // client.outLog('🔵 Inflating', chunk) - // First try to zlib decompress, then see how much bytes get read - const { buffer, engine } = Zlib.inflateRawSync(chunk, { - chunkSize: 1024 * 1024 * 2, - info: true - }) - - // Holds how much bytes we read, also where the checksum (should) start - const inflatedLen = engine.bytesRead - // It appears that mc sends extra bytes past the checksum. I don't think this is a raknet - // issue (as we are able to decipher properly, zlib works and should also have a checksum) so - // there needs to be more investigation done. If you know what's wrong here, please make an issue :) - const extraneousLen = chunk.length - inflatedLen - 8 - if (extraneousLen > 0) { // Extra bytes - // Info for debugging, todo: use debug() - const extraneousBytes = chunk.slice(inflatedLen + 8) - console.debug('Extraneous bytes!', extraneousLen, extraneousBytes.toString('hex')) - } else if (extraneousLen < 0) { - // No checksum or decompression failed - console.warn('Failed to decrypt', chunk.toString('hex')) - throw new Error('Decrypted packet is missing checksum') - } - - const packet = chunk.slice(0, inflatedLen) - const checksum = chunk.slice(inflatedLen, inflatedLen + 8) + const packet = chunk.slice(0, chunk.length - 8) + const checksum = chunk.slice(chunk.length - 8, chunk.length) const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) client.receiveCounter++ - if (checksum.toString('hex') === computedCheckSum.toString('hex')) { - client.onDecryptedPacket(buffer) - } else { - console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex')) + if (Buffer.compare(checksum, computedCheckSum) !== 0) { + // console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex')) throw Error(`Checksum mismatch ${checksum.toString('hex')} != ${computedCheckSum.toString('hex')}`) } + + Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buffer) => { + if (err) throw err + client.onDecryptedPacket(buffer) + }) } client.decipher.on('data', verify) diff --git a/data/new/compile.js b/tools/compileProtocol.js similarity index 100% rename from data/new/compile.js rename to tools/compileProtocol.js From 99cce3b371ce1e58a79f48ec7772d9d292af54e0 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sun, 14 Mar 2021 00:49:17 +0100 Subject: [PATCH 121/458] setup some CI and basics (#47) --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ .github/workflows/publish.yml | 32 ++++++++++++++++++++++++++++++++ .gitpod | 4 ++++ .gitpod.DockerFile | 8 ++++++++ .npmrc | 1 + 5 files changed, 70 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .gitpod create mode 100644 .gitpod.DockerFile create mode 100644 .npmrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e8525e8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..387db40 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,32 @@ +name: npm-publish +on: + push: + branches: + - master # Change this to your default branch +jobs: + npm-publish: + name: npm-publish + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@master + - name: Set up Node.js + uses: actions/setup-node@master + with: + node-version: 14.0.0 + - id: publish + uses: JS-DevTools/npm-publish@v1 + with: + token: ${{ secrets.NPM_AUTH_TOKEN }} + - name: Create Release + if: steps.publish.outputs.type != 'none' + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.publish.outputs.version }} + release_name: Release ${{ steps.publish.outputs.version }} + body: ${{ steps.publish.outputs.version }} + draft: false + prerelease: false \ No newline at end of file diff --git a/.gitpod b/.gitpod new file mode 100644 index 0000000..ff9c720 --- /dev/null +++ b/.gitpod @@ -0,0 +1,4 @@ +image: + file: .gitpod.DockerFile +tasks: +- command: npm install \ No newline at end of file diff --git a/.gitpod.DockerFile b/.gitpod.DockerFile new file mode 100644 index 0000000..061bf59 --- /dev/null +++ b/.gitpod.DockerFile @@ -0,0 +1,8 @@ +FROM gitpod/workspace-full:latest + +RUN bash -c ". .nvm/nvm.sh \ + && nvm install 14 \ + && nvm use 14 \ + && nvm alias default 14" + +RUN echo "nvm use default &>/dev/null" >> ~/.bashrc.d/51-nvm-fix \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..9cf9495 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false \ No newline at end of file From bd97a8e1b7f734764170448bdb1af6e9d608f260 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 13 Mar 2021 18:49:54 -0500 Subject: [PATCH 122/458] client close handling, add spawn event (#48) --- data/1.16.201/protocol.json | 33 +++++++++++++--------------- package.json | 2 +- src/auth/encryption.js | 2 ++ src/client.js | 44 ++++++++++++++++++++++++++----------- src/connection.js | 12 +++++++++- src/options.js | 9 ++++++-- src/rak.js | 19 ++++++++++++++++ src/relay.js | 4 +++- src/serverPlayer.js | 8 +------ tools/compileProtocol.js | 18 ++++++++++----- 10 files changed, 102 insertions(+), 49 deletions(-) diff --git a/data/1.16.201/protocol.json b/data/1.16.201/protocol.json index 4c90341..2dd5be8 100644 --- a/data/1.16.201/protocol.json +++ b/data/1.16.201/protocol.json @@ -1048,23 +1048,24 @@ } ] ], + "ItemStack": [ + "container", + [ + { + "name": "runtime_id", + "type": "zigzag32" + }, + { + "name": "item", + "type": "Item" + } + ] + ], "ItemStacks": [ "array", { "countType": "varint", - "type": [ - "container", - [ - { - "name": "runtime_id", - "type": "zigzag32" - }, - { - "name": "item", - "type": "Item" - } - ] - ] + "type": "ItemStack" } ], "RecipeIngredient": [ @@ -4600,13 +4601,9 @@ "name": "slot", "type": "varint" }, - { - "name": "uniqueid", - "type": "zigzag32" - }, { "name": "item", - "type": "Item" + "type": "ItemStack" } ] ], diff --git a/package.json b/package.json index 9de80f9..9984792 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Parse and serialize Minecraft Bedrock Edition packets", "main": "index.js", "scripts": { - "build": "cd data/new && node compile.js", + "build": "cd tools && node compileProtocol.js", "prepare": "npm run build", "test": "mocha", "pretest": "npm run lint", diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 99d8d34..95d87b1 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -1,4 +1,5 @@ const { Ber } = require('asn1') +const { ClientStatus } = require('../connection') const JWT = require('jsonwebtoken') const crypto = require('crypto') const ecPem = require('ec-pem') @@ -82,6 +83,7 @@ function Encrypt (client, server, options) { // It works! First encrypted packet :) client.write('client_to_server_handshake', {}) this.emit('join') + client.status = ClientStatus.Initializing } client.on('server.client_handshake', startClientboundEncryption) diff --git a/src/client.js b/src/client.js index 5b6c960..c9d94b4 100644 --- a/src/client.js +++ b/src/client.js @@ -1,4 +1,4 @@ -const { Connection } = require('./connection') +const { ClientStatus, Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { RakClient } = require('./Rak') const { serialize } = require('./datatypes/util') @@ -32,10 +32,12 @@ class Client extends Connection { auth.authenticateDeviceCode(this, options) } + this.startGameData = {} + this.on('session', this.connect) this.startQueue() - this.inLog = (...args) => console.info('C ->', ...args) - this.outLog = (...args) => console.info('C <-', ...args) + this.inLog = (...args) => debug('C ->', ...args) + this.outLog = (...args) => debug('C <-', ...args) } validateOptions () { @@ -62,11 +64,13 @@ class Client extends Connection { this.connection = new RakClient({ useWorkers: true, hostname, port }) this.connection.onConnected = () => this.sendLogin() + this.connection.onCloseConnection = () => this._close() this.connection.onEncapsulated = this.onEncapsulated this.connection.connect() } sendLogin () { + this.status = ClientStatus.Authenticating this.createClientChain() const chain = [ @@ -96,8 +100,25 @@ class Client extends Connection { process.exit(1) // TODO: handle } + onPlayStatus(statusPacket) { + if (this.status == ClientStatus.Initializing && this.options.autoInitPlayer === true) { + if (statusPacket.status === 'player_spawn') { + this.status = ClientStatus.Initialized + this.write('set_local_player_as_initialized', { runtime_entity_id: this.startGameData.runtime_entity_id }) + this.emit('spawn') + } + } + } + + _close() { + this.q = [] + this.q2 = [] + } + close () { - console.warn('Close not implemented!!') + this._close() + this.connection.close() + console.log('Closed!') } tryRencode (name, params, actual) { @@ -147,15 +168,12 @@ class Client extends Connection { case 'disconnect': // Client kicked this.onDisconnectRequest(des.data.params) break - // case 'crafting_data': - // fs.writeFileSync('crafting.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) - // break - // case 'start_game': - // fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) - // break - // case 'level_chunk': - // // fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) - // break + case 'start_game': + this.startGameData = pakData.params + break + case 'play_status': + this.onPlayStatus(pakData.params) + break default: // console.log('Sending to listeners') } diff --git a/src/connection.js b/src/connection.js index ba03549..7b39dad 100644 --- a/src/connection.js +++ b/src/connection.js @@ -7,7 +7,16 @@ const debug = require('debug')('minecraft-protocol') const SKIP_BATCH = ['level_chunk', 'client_cache_blob_status', 'client_cache_miss_response'] +const ClientStatus = { + Disconnected: 0, + Authenticating: 1, // Handshaking + Initializing: 2, // Authed, need to spawn + Initialized: 3 // play_status spawn sent by server, client responded with SetPlayerInit packet +} + class Connection extends EventEmitter { + state = ClientStatus.Disconnected + versionLessThan (version) { if (typeof version === 'string') { return Versions[version] < this.options.version @@ -112,6 +121,7 @@ class Connection extends EventEmitter { // TODO: Rename this to sendEncapsulated sendMCPE (buffer, immediate) { + if (this.connection.connected === false) return this.connection.sendReliable(buffer, immediate) } @@ -151,4 +161,4 @@ class Connection extends EventEmitter { } } -module.exports = { Connection } +module.exports = { ClientStatus, Connection } diff --git a/src/options.js b/src/options.js index 9d204e1..ec1127d 100644 --- a/src/options.js +++ b/src/options.js @@ -5,11 +5,16 @@ const CURRENT_VERSION = '1.16.201' const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 - version: CURRENT_VERSION + version: CURRENT_VERSION, + // client: If we should send SetPlayerInitialized to the server after getting play_status spawn. + // if this is disabled, no 'spawn' event will be emitted, you should manually set + // client.status to ClientStatus.Initialized after sending the init packet. + autoInitPlayer: true } const Versions = { - '1.16.210': 428, + // TODO + // '1.16.210': 428, '1.16.201': 422 } diff --git a/src/rak.js b/src/rak.js index c08fe83..0f44fac 100644 --- a/src/rak.js +++ b/src/rak.js @@ -14,6 +14,7 @@ try { class RakNativeClient extends EventEmitter { constructor (options) { super() + this.connected = false this.onConnected = () => { } this.onCloseConnection = () => { } this.onEncapsulated = () => { } @@ -23,8 +24,14 @@ class RakNativeClient extends EventEmitter { this.onEncapsulated(buffer, address) }) this.raknet.on('connected', () => { + this.connected = true this.onConnected() }) + + this.raknet.on('disconnected', ({ reason }) => { + this.connected = false + this.onCloseConnection(reason) + }) } async ping () { @@ -42,7 +49,15 @@ class RakNativeClient extends EventEmitter { this.raknet.connect() } + close() { + this.connected = false + setTimeout(() => { + this.raknet.close() + }, 40) + } + sendReliable (buffer, immediate) { + if (!this.connected) return const priority = immediate ? PacketPriority.IMMEDIATE_PRIORITY : PacketPriority.MEDIUM_PRIORITY return this.raknet.send(buffer, priority, PacketReliability.RELIABLE_ORDERED, 0) } @@ -83,6 +98,10 @@ class RakNativeServer extends EventEmitter { listen () { this.raknet.listen() } + + close() { + this.raknet.close() + } } class RakJsClient extends EventEmitter { diff --git a/src/relay.js b/src/relay.js index dbb15c5..ed78a09 100644 --- a/src/relay.js +++ b/src/relay.js @@ -106,6 +106,7 @@ class RelayPlayer extends Player { } this.flushUpQueue() // Send queued packets this.downInLog('Recv packet', packet) + // TODO: If we fail to parse a packet, proxy it raw and log an error const des = this.server.deserializer.parsePacketBuffer(packet) if (debugging) { // some packet encode/decode testing stuff @@ -150,7 +151,8 @@ class Relay extends Server { const client = new Client({ hostname: this.options.destination.hostname, port: this.options.destination.port, - encrypt: this.options.encrypt + encrypt: this.options.encrypt, + autoInitPlayer: false }) client.outLog = ds.upOutLog client.inLog = ds.upInLog diff --git a/src/serverPlayer.js b/src/serverPlayer.js index a699ec0..7455b35 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -1,4 +1,4 @@ -const { Connection } = require('./connection') +const { ClientStatus, Connection } = require('./connection') const fs = require('fs') const Options = require('./options') @@ -6,12 +6,6 @@ const { Encrypt } = require('./auth/encryption') const Login = require('./auth/login') const LoginVerify = require('./auth/loginVerify') -const ClientStatus = { - Authenticating: 0, - Initializing: 1, - Initialized: 2 -} - class Player extends Connection { constructor (server, connection) { super() diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index 5c67af1..d787cb9 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -7,6 +7,11 @@ */ const fs = require('fs') const { ProtoDefCompiler } = require('protodef').Compiler +const { join } = require('path') + +function getJSON (path) { + return JSON.parse(fs.readFileSync(path, 'utf-8')) +} // Parse the YML files and turn to JSON function genProtoSchema () { @@ -37,15 +42,15 @@ function genProtoSchema () { const t = `#Auto-generated from proto.yml, do not modify\n!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` fs.writeFileSync('./packet_map.yml', t) - compile('./proto.yml', 'protocol.json') + compile('./proto.yml', 'proto.json') return version } // Compile the ProtoDef JSON into JS function createProtocol (version) { const compiler = new ProtoDefCompiler() - const protocol = require(`../${version}/protocol.json`).types - compiler.addTypes(require('../../src/datatypes/compiler-minecraft')) + const protocol = getJSON(`../${version}/protocol.json`).types + compiler.addTypes(require('../src/datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) compiler.addTypesToCompile(protocol) @@ -57,11 +62,12 @@ function createProtocol (version) { return compiledProto } -function main () { +function main (ver = 'latest') { + process.chdir(join(__dirname, '/../data/', ver)) const version = genProtoSchema() - fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: require('./protocol.json') }, null, 2)) - fs.unlinkSync('./protocol.json') // remove temp file + fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: getJSON('./proto.json') }, null, 2)) + fs.unlinkSync('./proto.json') // remove temp file fs.unlinkSync('./packet_map.yml') // remove temp file console.log('Generating JS...') From 458136d877ca81d99e0355cb884e1341c66f6fc0 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 17 Mar 2021 18:04:14 -0400 Subject: [PATCH 123/458] Vanilla server tests, client offline mode (#49) * vanilla server launcher * update package.json * re-add babel to fix standard * fix ci * add buffer-equal * simple fixes * add offline client support * fix closing bugs, proper wait for server start * add test to mocha * change test timeout to 2 min * increase timeouts Co-authored-by: Romain Beaumont --- .gitignore | 3 +- data/provider.js | 2 +- package.json | 6 ++- src/auth/login.js | 70 ++++++++++++++----------- src/client.js | 35 +++++++------ src/client/auth.js | 18 +++++++ src/datatypes/util.js | 19 +++++-- src/options.js | 6 ++- src/rak.js | 4 +- src/serverPlayer.js | 12 ++++- test/vanilla.js | 62 ++++++++++++++++++++++ test/vanilla.test.js | 10 ++++ tools/startVanillaServer.js | 102 ++++++++++++++++++++++++++++++++++++ 13 files changed, 289 insertions(+), 60 deletions(-) create mode 100644 test/vanilla.js create mode 100644 test/vanilla.test.js create mode 100644 tools/startVanillaServer.js diff --git a/.gitignore b/.gitignore index 2f39796..6be9409 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ data/**/read.js data/**/write.js data/**/size.js samples/*.txt -samples/*.json \ No newline at end of file +samples/*.json +tools/bds* \ No newline at end of file diff --git a/data/provider.js b/data/provider.js index 098564a..3f51f02 100644 --- a/data/provider.js +++ b/data/provider.js @@ -15,7 +15,7 @@ function loadVersions () { } catch {} for (const file of files) { const rfile = file.replace(join(__dirname, '/', version) + '/', '') - fileMap[rfile] ??= [] + fileMap[rfile] = fileMap[rfile] ?? [] fileMap[rfile].push([Versions[version], file]) fileMap[rfile].sort().reverse() } diff --git a/package.json b/package.json index 9984792..9202b0b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "test": "mocha", "pretest": "npm run lint", "lint": "standard", + "vanillaServer": "node tools/startVanillaServer.js", "fix": "standard --fix" }, "keywords": [ @@ -29,15 +30,18 @@ "jsonwebtoken": "^8.5.1", "jsp-raknet": "github:extremeheat/raknet#client", "minecraft-folder-path": "^1.1.0", + "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", - "protodef": "github:extremeheat/node-protodef#compiler2", + "protodef": "^1.11.0", "raknet-native": "^0.1.0", "uuid-1345": "^1.0.2" }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", "babel-eslint": "^10.1.0", + "buffer-equal": "^1.0.0", "mocha": "^8.3.2", + "protodef-yaml": "^1.0.1", "standard": "^16.0.3" }, "standard": { diff --git a/src/auth/login.js b/src/auth/login.js index e414c5d..5d3ad49 100644 --- a/src/auth/login.js +++ b/src/auth/login.js @@ -7,16 +7,30 @@ const curve = 'secp384r1' module.exports = (client, server, options) => { const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') - client.createClientChain = (mojangKey) => { + client.createClientChain = (mojangKey, offline) => { mojangKey = mojangKey || require('./constants').PUBLIC_KEY const alice = client.ecdhKeyPair const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 const alicePEMPrivate = alicePEM.encodePrivateKey() - const token = JWT.sign({ - identityPublicKey: mojangKey, - certificateAuthority: true - }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + let token + if (offline) { + const payload = { + extraData: { + displayName: client.username, + identity: client.profile.uuid, + titleId: '89692877' + }, + certificateAuthority: true, + identityPublicKey: client.clientX509 + } + token = JWT.sign(payload, alicePEMPrivate, { algorithm: 'ES384', notBefore: 0, issuer: 'self', expiresIn: 60 * 60, header: { x5u: client.clientX509 } }) + } else { + token = JWT.sign({ + identityPublicKey: mojangKey, + certificateAuthority: true + }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + } client.clientIdentityChain = token client.createClientUserChain(alicePEMPrivate) @@ -24,46 +38,42 @@ module.exports = (client, server, options) => { client.createClientUserChain = (privateKey) => { let payload = { - ServerAddress: options.hostname, - ThirdPartyName: client.profile.name, - DeviceOS: client.session?.deviceOS || 1, - GameVersion: options.version || '1.16.201', - ClientRandomId: Date.now(), // TODO make biggeer - DeviceId: '2099de18-429a-465a-a49b-fc4710a17bb3', // TODO random - LanguageCode: 'en_GB', // TODO locale AnimatedImageData: [], - PersonaPieces: [], - PieceTintColours: [], - SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343701', - SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', - SkinData: 'AAAAAA==', - SkinResourcePatch: 'ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfMTI4eDEyOCIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfMTI4eDEyOF9wZXJzb25hLWUxOTk2NzJhOGMxYTg3ZTAtMCIsCiAgICAgICJhbmltYXRlZF9mYWNlIiA6ICJnZW9tZXRyeS5hbmltYXRlZF9mYWNlX3BlcnNvbmEtZTE5OTY3MmE4YzFhODdlMC0wIiwKICAgICAgImRlZmF1bHQiIDogImdlb21ldHJ5LnBlcnNvbmFfZTE5OTY3MmE4YzFhODdlMC0wIgogICB9Cn0K', - SkinGeometryData: skinGeom, - SkinImageHeight: 1, - SkinImageWidth: 1, ArmSize: 'wide', CapeData: '', CapeId: '', CapeImageHeight: 0, CapeImageWidth: 0, CapeOnClassicSkin: false, - PlatformOfflineId: '', - PlatformOnlineId: '', // chat - // a bunch of meaningless junk + ClientRandomId: 1, // TODO make biggeer CurrentInputMode: 1, DefaultInputMode: 1, + DeviceId: '2099de18-429a-465a-a49b-fc4710a17bb3', // TODO random DeviceModel: '', + DeviceOS: client.session?.deviceOS || 7, + GameVersion: options.version || '1.16.201', GuiScale: -1, - UIProfile: 0, - TenantId: '', - PremiumSkin: false, - PersonaSkin: false, + LanguageCode: 'en_GB', // TODO locale + PersonaPieces: [], + PersonaSkin: true, PieceTintColors: [], + PlatformOfflineId: '', + PlatformOnlineId: '', // chat + PremiumSkin: false, + SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343701', + ServerAddress: `${options.hostname}:${options.port}`, SkinAnimationData: '', + SkinColor: '#ffffcd96', + SkinData: 'AAAAAA==', + SkinGeometryData: skinGeom, + SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', + SkinImageHeight: 1, + SkinImageWidth: 1, + SkinResourcePatch: '', + ThirdPartyName: client.profile.name, ThirdPartyNameOnly: false, - SkinColor: '#ffffcd96' + UIProfile: 0 } - payload = require('./logPack.json') const customPayload = options.userData || {} payload = { ...payload, ...customPayload } diff --git a/src/client.js b/src/client.js index c9d94b4..d6c3493 100644 --- a/src/client.js +++ b/src/client.js @@ -1,6 +1,6 @@ const { ClientStatus, Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') -const { RakClient } = require('./Rak') +const { RakClient } = require('./rak') const { serialize } = require('./datatypes/util') const fs = require('fs') const debug = require('debug')('minecraft-protocol') @@ -14,6 +14,8 @@ const LoginVerify = require('./auth/loginVerify') const debugging = false class Client extends Connection { + connection + /** @param {{ version: number, hostname: string, port: number }} options */ constructor (options) { super() @@ -26,15 +28,19 @@ class Client extends Connection { Login(this, null, this.options) LoginVerify(this, null, this.options) - if (options.password) { - auth.authenticatePassword(this, options) + this.on('session', this.connect) + + if (options.offline) { + console.debug('offline mode, not authenticating', this.options) + auth.createOfflineSession(this, this.options) + } else if (options.password) { + auth.authenticatePassword(this, this.options) } else { - auth.authenticateDeviceCode(this, options) + auth.authenticateDeviceCode(this, this.options) } this.startGameData = {} - this.on('session', this.connect) this.startQueue() this.inLog = (...args) => debug('C ->', ...args) this.outLog = (...args) => debug('C <-', ...args) @@ -64,14 +70,14 @@ class Client extends Connection { this.connection = new RakClient({ useWorkers: true, hostname, port }) this.connection.onConnected = () => this.sendLogin() - this.connection.onCloseConnection = () => this._close() + this.connection.onCloseConnection = () => this.close() this.connection.onEncapsulated = this.onEncapsulated this.connection.connect() } sendLogin () { this.status = ClientStatus.Authenticating - this.createClientChain() + this.createClientChain(null, this.options.offline) const chain = [ this.clientIdentityChain, // JWT we generated for auth @@ -79,7 +85,6 @@ class Client extends Connection { ] const encodedChain = JSON.stringify({ chain }) - const bodyLength = this.clientUserChain.length + encodedChain.length + 8 debug('Auth chain', chain) @@ -100,8 +105,8 @@ class Client extends Connection { process.exit(1) // TODO: handle } - onPlayStatus(statusPacket) { - if (this.status == ClientStatus.Initializing && this.options.autoInitPlayer === true) { + onPlayStatus (statusPacket) { + if (this.status === ClientStatus.Initializing && this.options.autoInitPlayer === true) { if (statusPacket.status === 'player_spawn') { this.status = ClientStatus.Initialized this.write('set_local_player_as_initialized', { runtime_entity_id: this.startGameData.runtime_entity_id }) @@ -110,14 +115,12 @@ class Client extends Connection { } } - _close() { + close () { + clearInterval(this.loop) this.q = [] this.q2 = [] - } - - close () { - this._close() - this.connection.close() + this.connection?.close() + this.removeAllListeners() console.log('Closed!') } diff --git a/src/client/auth.js b/src/client/auth.js index f4d139f..2d8d30e 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -1,4 +1,5 @@ const { MsAuthFlow } = require('./authFlow.js') +const { uuidFrom } = require('../datatypes/util') /** * Obtains Minecaft profile data using a Minecraft access token and starts the join sequence @@ -27,6 +28,22 @@ async function postAuthenticate (client, options, chains) { client.emit('session', profile) } +/** + * Creates an offline session for the client + */ +function createOfflineSession (client, options) { + if (!options.username) throw Error('Must specify a valid username') + const profile = { + name: options.username, + uuid: uuidFrom(options.username), // random + xuid: 0 + } + client.profile = profile + client.username = profile.name + client.accessToken = [] // No extra JWTs, only send 1 client signed chain with all the data + client.emit('session', profile) +} + /** * Authenticates with Mincrosoft through user credentials, then * with Xbox Live, Minecraft, checks entitlements and returns profile @@ -61,6 +78,7 @@ async function authenticateDeviceCode (client, options) { } module.exports = { + createOfflineSession, authenticatePassword, authenticateDeviceCode } diff --git a/src/datatypes/util.js b/src/datatypes/util.js index 029df2b..4a14e31 100644 --- a/src/datatypes/util.js +++ b/src/datatypes/util.js @@ -1,4 +1,5 @@ const fs = require('fs') +const UUID = require('uuid-1345') function getFiles (dir) { let results = [] @@ -19,15 +20,23 @@ function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms)) } -function waitFor (cb, withTimeout) { - return Promise.race([ - new Promise((resolve) => cb(resolve)), - sleep(withTimeout) +async function waitFor (cb, withTimeout, onTimeout) { + let t + const ret = await Promise.race([ + new Promise(resolve => cb(resolve)), + new Promise(resolve => { t = setTimeout(() => resolve('timeout'), withTimeout) }) ]) + clearTimeout(t) + if (ret === 'timeout') onTimeout() + return ret } function serialize (obj = {}, fmt) { return JSON.stringify(obj, (k, v) => typeof v === 'bigint' ? v.toString() : v, fmt) } -module.exports = { getFiles, sleep, waitFor, serialize } +function uuidFrom (string) { + return UUID.v3({ namespace: '6ba7b811-9dad-11d1-80b4-00c04fd430c8', name: string }) +} + +module.exports = { getFiles, sleep, waitFor, serialize, uuidFrom } diff --git a/src/options.js b/src/options.js index ec1127d..cc068e6 100644 --- a/src/options.js +++ b/src/options.js @@ -7,9 +7,11 @@ const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 version: CURRENT_VERSION, // client: If we should send SetPlayerInitialized to the server after getting play_status spawn. - // if this is disabled, no 'spawn' event will be emitted, you should manually set + // if this is disabled, no 'spawn' event will be emitted, you should manually set // client.status to ClientStatus.Initialized after sending the init packet. - autoInitPlayer: true + autoInitPlayer: true, + // If true, do not authenticate with Xbox Live + offline: false } const Versions = { diff --git a/src/rak.js b/src/rak.js index 0f44fac..e4a203d 100644 --- a/src/rak.js +++ b/src/rak.js @@ -49,7 +49,7 @@ class RakNativeClient extends EventEmitter { this.raknet.connect() } - close() { + close () { this.connected = false setTimeout(() => { this.raknet.close() @@ -99,7 +99,7 @@ class RakNativeServer extends EventEmitter { this.raknet.listen() } - close() { + close () { this.raknet.close() } } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 7455b35..70abf8a 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -71,7 +71,7 @@ class Player extends Connection { */ sendDisconnectStatus (playStatus) { this.write('play_status', { status: playStatus }) - this.connection.close() + this.close() } /** @@ -82,7 +82,7 @@ class Player extends Connection { hide_disconnect_screen: hide, message: reason }) - this.connection.close() + this.close() } // After sending Server to Client Handshake, this handles the client's @@ -95,6 +95,14 @@ class Player extends Connection { this.emit('join') } + close () { + this.q = [] + this.q2 = [] + clearInterval(this.loop) + this.connection?.close() + this.removeAllListeners() + } + readPacket (packet) { // console.log('packet', packet) try { diff --git a/test/vanilla.js b/test/vanilla.js new file mode 100644 index 0000000..1a747ab --- /dev/null +++ b/test/vanilla.js @@ -0,0 +1,62 @@ +// process.env.DEBUG = 'minecraft-protocol raknet' +const vanillaServer = require('../tools/startVanillaServer') +const { Client } = require('../src/client') +const { waitFor } = require('../src/datatypes/util') + +async function test () { + // Start the server, wait for it to accept clients, throws on timeout + const handle = await vanillaServer.startServerAndWait('1.16.201', 1000 * 120) + console.log('Started server') + + const client = new Client({ + hostname: '127.0.0.1', + port: 19130, + username: 'Notch', + offline: true + }) + + console.log('Started client') + + let loop + + await waitFor((res) => { + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + + clearInterval(loop) + loop = setInterval(() => { + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: BigInt(Date.now()) }) + }, 200) + + console.log('Awaiting join') + + client.on('spawn', () => { + console.log('✔ Client has spawned') + client.close() + handle.kill() + res() + }) + }) + }, 1000 * 60, () => { + client.close() + handle.kill() + throw Error('❌ client timed out ') + }) + clearInterval(loop) +} + +if (!module.parent) test() +module.exports = { clientTest: test } diff --git a/test/vanilla.test.js b/test/vanilla.test.js new file mode 100644 index 0000000..36369bd --- /dev/null +++ b/test/vanilla.test.js @@ -0,0 +1,10 @@ +/* eslint-env jest */ + +const { clientTest } = require('./vanilla') + +describe('vanilla server test', function () { + this.timeout(120 * 1000) + it('client spawns', async () => { + await clientTest() + }) +}) \ No newline at end of file diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js new file mode 100644 index 0000000..83856f4 --- /dev/null +++ b/tools/startVanillaServer.js @@ -0,0 +1,102 @@ +const http = require('https') +const fs = require('fs') +const cp = require('child_process') +const debug = require('debug')('minecraft-protocol') +const { getFiles, waitFor } = require('../src/datatypes/util') + +const head = (url) => new Promise((resolve, reject) => http.request(url, { method: 'HEAD' }, resolve).on('error', reject).end()) +const get = (url, out) => cp.execSync(`curl -o ${out} ${url}`) + +// Get the latest versions +// TODO: once we support multi-versions +function fetchLatestStable () { + get('https://raw.githubusercontent.com/minecraft-linux/mcpelauncher-versiondb/master/versions.json', 'versions.json') + const versions = JSON.parse(fs.readFileSync('./versions.json')) + const latest = versions[versions.length - 1] + return latest.version_name +} + +// Download + extract vanilla server and enter the directory +async function download (os, version) { + process.chdir(__dirname) + const verStr = version.split('.').slice(0, 3).join('.') + const dir = 'bds-' + version + + if (fs.existsSync(dir) && getFiles(dir).length) { + process.chdir('bds-' + version) // Enter server folder + return verStr + } + try { fs.mkdirSync(dir) } catch { } + + process.chdir('bds-' + version) // Enter server folder + const url = (os, version) => `https://minecraft.azureedge.net/bin-${os}/bedrock-server-${version}.zip` + + let found = false + + for (let i = 0; i < 8; i++) { // Check for the latest server build for version (major.minor.patch.BUILD) + const u = url(os, `${verStr}.${String(i).padStart(2, '0')}`) + debug('Opening', u) + const ret = await head(u) + if (ret.statusCode === 200) { + found = u + debug('Found server', ret.statusCode) + break + } + } + if (!found) throw Error('did not find server bin for ' + os + ' ' + version) + console.info('🔻 Downloading', found) + get(found, 'bds.zip') + console.info('⚡ Unzipping') + // Unzip server + if (process.platform === 'linux') cp.execSync('unzip bds.zip') + else cp.execSync('tar -xf bds.zip') + return verStr +} + +// Setup the server +function configure () { + let config = fs.readFileSync('./server.properties', 'utf-8') + config += '\nlevel-generator=2\nserver-port=19130\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator\nonline-mode=false' + fs.writeFileSync('./server.properties', config) +} + +function run (inheritStdout = true) { + const exe = process.platform === 'win32' ? 'bedrock_server.exe' : './bedrock_server' + return cp.spawn(exe, inheritStdout ? { stdio: 'inherit' } : {}) +} + +// Run the server +async function startServer (version, onStart) { + const os = process.platform === 'win32' ? 'win' : process.platform + if (os !== 'win' && os !== 'linux') { + throw Error('unsupported os ' + os) + } + await download(os, version) + configure() + const handle = run(!onStart) + if (onStart) { + handle.stdout.on('data', data => data.includes('Server started.') ? onStart() : null) + handle.stdout.pipe(process.stdout) + handle.stderr.pipe(process.stdout) + } + return handle +} + +// Start the server and wait for it to be ready, with a timeout +async function startServerAndWait (version, withTimeout) { + let handle + await waitFor(async res => { + handle = await startServer(version, res) + }, withTimeout, () => { + handle?.kill() + throw new Error('Server did not start on time ' + withTimeout) + }) + return handle +} + +if (!module.parent) { + // if (process.argv.length < 3) throw Error('Missing version argument') + startServer(process.argv[2] || '1.16.201') +} + +module.exports = { fetchLatestStable, startServer, startServerAndWait } From e6cc00ef1600b5157aaeff949fbb4909c3becaa2 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sun, 21 Mar 2021 00:01:21 +0100 Subject: [PATCH 124/458] add npm install in publish.yml --- .github/workflows/publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 387db40..43e06e8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,6 +14,7 @@ jobs: uses: actions/setup-node@master with: node-version: 14.0.0 + - run: npm install - id: publish uses: JS-DevTools/npm-publish@v1 with: @@ -29,4 +30,4 @@ jobs: release_name: Release ${{ steps.publish.outputs.version }} body: ${{ steps.publish.outputs.version }} draft: false - prerelease: false \ No newline at end of file + prerelease: false From 9c36b71bf6e529a36a7092ef7535fc9dd37ed115 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 20 Mar 2021 23:13:14 +0000 Subject: [PATCH 125/458] finish renaming to bedrock-protocol --- README.md | 4 ++-- package.json | 8 ++++---- test/ecdh_key_exchange.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3c7e063..226cbbd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -pocket-minecraft-protocol [![NPM version](https://img.shields.io/npm/v/pocket-minecraft-protocol.svg)](http://npmjs.com/package/pocket-minecraft-protocol) [![Join the chat at https://gitter.im/PrismarineJS/pocket-minecraft-protocol](https://badges.gitter.im/PrismarineJS/pocket-minecraft-protocol.svg)](https://gitter.im/PrismarineJS/pocket-minecraft-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +bedrock-protocol [![NPM version](https://img.shields.io/npm/v/bedrock-protocol.svg)](http://npmjs.com/package/bedrock-protocol) [![Join the chat at https://gitter.im/PrismarineJS/bedrock-protocol](https://badges.gitter.im/PrismarineJS/bedrock-protocol.svg)](https://gitter.im/PrismarineJS/bedrock-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ========================= Not ready for prime time yet, check https://github.com/PrismarineJS/bedrock-protocol/projects/1 for progress @@ -15,7 +15,7 @@ Parse and serialize Minecraft: Pocket Edition packets ## Installation Simply run - npm install pocket-minecraft-protocol + npm install bedrock-protocol Then view our `examples` for inspiration! diff --git a/package.json b/package.json index 9202b0b..d7e514d 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "pocket-minecraft-protocol", + "name": "bedrock-protocol", "version": "3.0.0", "description": "Parse and serialize Minecraft Bedrock Edition packets", "main": "index.js", @@ -49,10 +49,10 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/mhsjlw/pocket-minecraft-protocol.git" + "url": "git+https://github.com/PrismarineJS/bedrock-protocol.git" }, "bugs": { - "url": "https://github.com/mhsjlw/pocket-minecraft-protocol/issues" + "url": "https://github.com/PrismarineJS/bedrock-protocol/issues" }, - "homepage": "https://github.com/mhsjlw/pocket-minecraft-protocol#readme" + "homepage": "https://github.com/PrismarineJS/bedrock-protocol#readme" } diff --git a/test/ecdh_key_exchange.js b/test/ecdh_key_exchange.js index a0e95b7..b49cf74 100644 --- a/test/ecdh_key_exchange.js +++ b/test/ecdh_key_exchange.js @@ -4,7 +4,7 @@ const assert=require("assert"); const bufferEqual=require("buffer-equal"); // based on https://s.yawk.at/VZSf and https://confluence.yawk.at/display/PEPROTOCOL/Encryption -// and https://github.com/mhsjlw/pocket-minecraft-protocol/issues/15 +// and https://github.com/PrismarineJS/bedrock-protocol/issues/15 describe("ecdh key exchange",() => { it("generate the secret",() => { From 37f7d3de9917b4e06e8e55ce8dc0657066e05b84 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 20 Mar 2021 23:15:35 +0000 Subject: [PATCH 126/458] fix badges --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 226cbbd..3773432 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ -bedrock-protocol [![NPM version](https://img.shields.io/npm/v/bedrock-protocol.svg)](http://npmjs.com/package/bedrock-protocol) [![Join the chat at https://gitter.im/PrismarineJS/bedrock-protocol](https://badges.gitter.im/PrismarineJS/bedrock-protocol.svg)](https://gitter.im/PrismarineJS/bedrock-protocol?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -========================= +# bedrock-protocol +[![NPM version](https://img.shields.io/npm/v/bedrock-protocol.svg)](http://npmjs.com/package/bedrock-protocol) +[![Build Status](https://github.com/PrismarineJS/bedrock-protocol/workflows/CI/badge.svg)](https://github.com/PrismarineJS/bedrock-protocol/actions?query=workflow%3A%22CI%22) +[![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8) +[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/bedrock-protocol) Not ready for prime time yet, check https://github.com/PrismarineJS/bedrock-protocol/projects/1 for progress From 6b7138695e234c702eba2956d7fcc043db664642 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 21 Mar 2021 07:54:04 -0400 Subject: [PATCH 127/458] 1.16.210 update --- data/1.16.210/protocol.json | 7553 +++++++++++++++++++++++++++ data/latest/proto.yml | 237 +- data/latest/types.yaml | 369 +- package.json | 2 +- src/auth/login.js | 4 + src/datatypes/compiler-minecraft.js | 34 +- src/options.js | 5 +- test/vanilla.js | 4 +- test/vanilla.test.js | 5 +- 9 files changed, 8075 insertions(+), 138 deletions(-) create mode 100644 data/1.16.210/protocol.json diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json new file mode 100644 index 0000000..2121295 --- /dev/null +++ b/data/1.16.210/protocol.json @@ -0,0 +1,7553 @@ +{ + "types": { + "varint32": "varint", + "bool": "native", + "zigzag32": "native", + "zigzag64": "native", + "uuid": "native", + "byterot": "native", + "MapInfo": "native", + "nbt": "native", + "BehaviourPackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + } + ] + ] + } + ], + "TexturePackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "rtx_enabled", + "type": "bool" + } + ] + ] + } + ], + "ResourcePackIdVersions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "ResourcePackIds": [ + "array", + { + "countType": "li16", + "type": "string" + } + ], + "Experiment": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "enabled", + "type": "bool" + } + ] + ], + "Experiments": [ + "array", + { + "countType": "li32", + "type": "Experiment" + } + ], + "GameMode": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "survival", + "1": "creative", + "2": "adventure", + "3": "survival_spectator", + "4": "creative_spectator", + "5": "fallback" + } + } + ], + "GameRule": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "bool", + "2": "int", + "3": "float" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "bool": "bool", + "int": "zigzag32", + "float": "lf32" + }, + "default": "void" + } + ] + } + ] + ], + "GameRules": [ + "array", + { + "countType": "varint", + "type": "GameRule" + } + ], + "Blob": [ + "container", + [ + { + "name": "hash", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "BlockPalette": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "state", + "type": "nbt" + } + ] + ] + } + ], + "Itemstates": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "runtime_id", + "type": "li16" + }, + { + "name": "component_based", + "type": "bool" + } + ] + ] + } + ], + "Item": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "auxiliary_value", + "type": "zigzag32" + }, + { + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "false", + "65535": "true" + } + } + ] + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "true": [ + "container", + [ + { + "name": "version", + "type": "u8" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "zigzag32", + "type": "string" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "zigzag32", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "355": [ + "container", + [ + { + "name": "blocking_tick", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "vec3i": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "vec3u": [ + "container", + [ + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + } + ] + ], + "vec3f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "vec2f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "MetadataDictionary": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "key", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "flags", + "1": "health", + "2": "variant", + "3": "color", + "4": "nametag", + "5": "owner_eid", + "6": "target_eid", + "7": "air", + "8": "potion_color", + "9": "potion_ambient", + "10": "jump_duration", + "11": "hurt_time", + "12": "hurt_direction", + "13": "paddle_time_left", + "14": "paddle_time_right", + "15": "experience_value", + "16": "minecart_display_block", + "17": "minecart_display_offset", + "18": "minecart_has_display", + "20": "old_swell", + "21": "swell_dir", + "22": "charge_amount", + "23": "enderman_held_runtime_id", + "24": "entity_age", + "26": "player_flags", + "27": "player_index", + "28": "player_bed_position", + "29": "fireball_power_x", + "30": "fireball_power_y", + "31": "fireball_power_z", + "32": "aux_power", + "33": "fish_x", + "34": "fish_z", + "35": "fish_angle", + "36": "potion_aux_value", + "37": "lead_holder_eid", + "38": "scale", + "39": "interactive_tag", + "40": "npc_skin_id", + "41": "url_tag", + "42": "max_airdata_max_air", + "43": "mark_variant", + "44": "container_type", + "45": "container_base_size", + "46": "container_extra_slots_per_strength", + "47": "block_target", + "48": "wither_invulnerable_ticks", + "49": "wither_target_1", + "50": "wither_target_2", + "51": "wither_target_3", + "52": "aerial_attack", + "53": "boundingbox_width", + "54": "boundingbox_height", + "55": "fuse_length", + "56": "rider_seat_position", + "57": "rider_rotation_locked", + "58": "rider_max_rotation", + "59": "rider_min_rotation", + "60": "rider_rotation_offset", + "61": "area_effect_cloud_radius", + "62": "area_effect_cloud_waiting", + "63": "area_effect_cloud_particle_id", + "64": "shulker_peek_id", + "65": "shulker_attach_face", + "66": "shulker_attached", + "67": "shulker_attach_pos", + "68": "trading_player_eid", + "69": "trading_career", + "70": "has_command_block", + "71": "command_block_command", + "72": "command_block_last_output", + "73": "command_block_track_output", + "74": "controlling_rider_seat_number", + "75": "strength", + "76": "max_strength", + "77": "spell_casting_color", + "78": "limited_life", + "79": "armor_stand_pose_index", + "80": "ender_crystal_time_offset", + "81": "always_show_nametag", + "82": "color_2", + "83": "name_author", + "84": "score_tag", + "85": "balloon_attached_entity", + "86": "pufferfish_size", + "87": "bubble_time", + "88": "agent", + "89": "sitting_amount", + "90": "sitting_amount_previous", + "91": "eating_counter", + "92": "flags_extended", + "93": "laying_amount", + "94": "laying_amount_previous", + "95": "duration", + "96": "spawn_time", + "97": "change_rate", + "98": "change_on_pickup", + "99": "pickup_count", + "100": "interact_text", + "101": "trade_tier", + "102": "max_trade_tier", + "103": "trade_experience", + "104": "skin_id", + "105": "spawning_frames", + "106": "command_block_tick_delay", + "107": "command_block_execute_on_first_tick", + "108": "ambient_sound_interval", + "109": "ambient_sound_interval_range", + "110": "ambient_sound_event_name", + "111": "fall_damage_multiplier", + "112": "name_raw_text", + "113": "can_ride_target", + "114": "low_tier_cured_discount", + "115": "high_tier_cured_discount", + "116": "nearby_cured_discount", + "117": "nearby_cured_discount_timestamp", + "118": "hitbox", + "119": "is_buoyant", + "120": "buoyancy_data", + "121": "goat_horn_count" + } + } + ] + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "byte", + "1": "short", + "2": "int", + "3": "float", + "4": "string", + "5": "compound", + "6": "vec3i", + "7": "long", + "8": "vec3f" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "key", + "fields": { + "flags": "MetadataFlags1", + "flags_extended": "MetadataFlags2" + }, + "default": [ + "switch", + { + "compareTo": "type", + "fields": { + "byte": "i8", + "short": "li16", + "int": "zigzag32", + "float": "lf32", + "string": "string", + "compound": "nbt", + "vec3i": "vec3i", + "long": "zigzag64", + "vec3f": "vec3f" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ], + "Link": [ + "container", + [ + { + "name": "ridden_entity_id", + "type": "zigzag64" + }, + { + "name": "rider_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "immediate", + "type": "bool" + }, + { + "name": "rider_initiated", + "type": "bool" + } + ] + ], + "Links": [ + "array", + { + "countType": "varint", + "type": "Link" + } + ], + "EntityAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "min", + "type": "lf32" + }, + { + "name": "value", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + } + ] + ] + } + ], + "Rotation": [ + "container", + [ + { + "name": "yaw", + "type": "byterot" + }, + { + "name": "pitch", + "type": "byterot" + }, + { + "name": "head_yaw", + "type": "byterot" + } + ] + ], + "BlockCoordinates": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "PlayerAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "min", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + }, + { + "name": "current", + "type": "lf32" + }, + { + "name": "default", + "type": "lf32" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "Transaction": [ + "container", + [ + { + "name": "legacy_request_id", + "type": "zigzag32" + }, + { + "name": "legacy_transactions", + "type": [ + "switch", + { + "compareTo": "legacy_request_id", + "fields": { + "0": "void" + }, + "default": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "changed_slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_id", + "type": "u8" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + }, + { + "name": "transaction_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "inventory_mismatch", + "2": "item_use", + "3": "item_use_on_entity", + "4": "item_release" + } + } + ] + }, + { + "name": "network_ids", + "type": "bool" + }, + { + "name": "inventory_actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "source_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "container", + "1": "global", + "2": "world_interaction", + "3": "creative", + "100": "craft_slot", + "99999": "craft" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "container": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "creative": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "world_interaction": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "craft": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "craft_slot": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + }, + { + "name": "new_item_stack_id", + "type": [ + "switch", + { + "compareTo": "../network_ids", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + { + "name": "transaction_data", + "type": [ + "switch", + { + "compareTo": "transaction_type", + "fields": { + "normal": "void", + "inventory_mismatch": "void", + "item_use": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "click_block", + "1": "click_air", + "2": "break_block" + } + } + ] + }, + { + "name": "block_position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "varint" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + }, + { + "name": "block_runtime_id", + "type": "varint" + } + ] + ], + "item_use_on_entity": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "interact", + "1": "attack" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + } + ] + ], + "item_release": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "release", + "1": "consume" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "head_pos", + "type": "vec3f" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "ItemStack": [ + "container", + [ + { + "name": "runtime_id", + "type": "zigzag32" + }, + { + "name": "item", + "type": "Item" + } + ] + ], + "ItemStacks": [ + "array", + { + "countType": "varint", + "type": "ItemStack" + } + ], + "RecipeIngredient": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "network_data", + "type": "zigzag32" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ], + "PotionTypeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "input_item_meta", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "ingredient_meta", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + }, + { + "name": "output_item_meta", + "type": "zigzag32" + } + ] + ] + } + ], + "PotionContainerChangeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + } + ] + ] + } + ], + "Recipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "shapeless", + "1": "shaped", + "2": "furnace", + "3": "furnace_with_metadata", + "4": "multi", + "5": "shulker_box", + "6": "shapeless_chemistry", + "7": "shaped_chemistry" + } + } + ] + }, + { + "name": "recipe", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "shapeless": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "shulker_box": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "shapeless_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "shaped": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "shaped_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "furnace": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "output", + "type": "Item" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "furnace_with_metadata": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "input_meta", + "type": "zigzag32" + }, + { + "name": "output", + "type": "Item" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "multi": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ], + "SkinImage": [ + "container", + [ + { + "name": "width", + "type": "li32" + }, + { + "name": "height", + "type": "li32" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "Skin": [ + "container", + [ + { + "name": "skin_id", + "type": "string" + }, + { + "name": "skin_resource_pack", + "type": "string" + }, + { + "name": "skin_data", + "type": "SkinImage" + }, + { + "name": "animations", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "skin_image", + "type": "SkinImage" + }, + { + "name": "animation_type", + "type": "li32" + }, + { + "name": "animation_frames", + "type": "lf32" + }, + { + "name": "expression_type", + "type": "lf32" + } + ] + ] + } + ] + }, + { + "name": "cape_data", + "type": "SkinImage" + }, + { + "name": "geometry_data", + "type": "string" + }, + { + "name": "animation_data", + "type": "string" + }, + { + "name": "premium", + "type": "string" + }, + { + "name": "persona", + "type": "bool" + }, + { + "name": "cape_on_classic", + "type": "bool" + }, + { + "name": "cape_id", + "type": "string" + }, + { + "name": "full_skin_id", + "type": "string" + }, + { + "name": "arm_size", + "type": "string" + }, + { + "name": "skin_color", + "type": "string" + }, + { + "name": "personal_pieces", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_id", + "type": "string" + }, + { + "name": "piece_type", + "type": "string" + }, + { + "name": "pack_id", + "type": "string" + }, + { + "name": "is_default_piece", + "type": "bool" + }, + { + "name": "product_id", + "type": "string" + } + ] + ] + } + ] + }, + { + "name": "piece_tint_colors", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_type", + "type": "string" + }, + { + "name": "colors", + "type": [ + "array", + { + "countType": "li32", + "type": "string" + } + ] + } + ] + ] + } + ] + } + ] + ], + "PlayerRecords": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "remove" + } + } + ] + }, + { + "name": "records_count", + "type": "varint" + }, + { + "name": "records", + "type": [ + "array", + { + "count": "records_count", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "xbox_user_id", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "build_platform", + "type": "li32" + }, + { + "name": "skin_data", + "type": "Skin" + }, + { + "name": "is_teacher", + "type": "bool" + }, + { + "name": "is_host", + "type": "bool" + } + ] + ], + "remove": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + }, + { + "name": "verified", + "type": [ + "array", + { + "count": "records_count", + "type": "bool" + } + ] + } + ] + ], + "ScoreEntries": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "change", + "1": "remove" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "remove": [ + "container", + [ + { + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": "zigzag64", + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "custom_name", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "fake_player": "string" + }, + "default": "void" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "ScoreboardIdentityEntries": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "TYPE_REGISTER_IDENTITY", + "1": "TYPE_CLEAR_IDENTITY" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "TYPE_REGISTER_IDENTITY": "zigzag64" + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "Enchant": [ + "container", + [ + { + "name": "id", + "type": "u8" + }, + { + "name": "level", + "type": "u8" + } + ] + ], + "EnchantOptions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "cost", + "type": "varint" + }, + { + "name": "slot_flags", + "type": "li32" + }, + { + "name": "equip_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "held_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "self_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "name", + "type": "string" + }, + { + "name": "option_id", + "type": "zigzag32" + } + ] + ] + } + ], + "StackRequestSlotInfo": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "slot_id", + "type": "u8" + }, + { + "name": "stack_id", + "type": "zigzag32" + } + ] + ], + "ItemStackRequests": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "request_id", + "type": "zigzag32" + }, + { + "name": "actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "take", + "1": "place", + "2": "swap", + "3": "drop", + "4": "destroy", + "5": "consume", + "6": "create", + "7": "lab_table_combine", + "8": "beacon_payment", + "9": "mine_block", + "10": "craft_recipe", + "11": "craft_recipe_auto", + "12": "craft_creative", + "13": "optional", + "14": "non_implemented", + "15": "results_deprecated" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type_id", + "fields": { + "take": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "place": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "swap": [ + "container", + [ + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "drop": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "randomly", + "type": "bool" + } + ] + ], + "destroy": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "consume": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "create": [ + "container", + [ + { + "name": "result_slot_id", + "type": "u8" + } + ] + ], + "beacon_payment": [ + "container", + [ + { + "name": "primary_effect", + "type": "zigzag32" + }, + { + "name": "secondary_effect", + "type": "zigzag32" + } + ] + ], + "mine_block": [ + "container", + [ + { + "name": "unknown1", + "type": "zigzag32" + }, + { + "name": "predicted_durability", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "craft_recipe": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_recipe_auto": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_creative": [ + "container", + [ + { + "name": "creative_item_network_id", + "type": "varint32" + } + ] + ], + "optional": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + }, + { + "name": "filtered_string_index", + "type": "li32" + } + ] + ], + "non_implemented": "void", + "results_deprecated": [ + "container", + [ + { + "name": "result_items", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "times_crafted", + "type": "u8" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + { + "name": "custom_names", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ], + "ItemStackResponses": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "ok", + "1": "error" + } + } + ] + }, + { + "name": "request_id", + "type": "varint32" + }, + { + "name": "containers", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot", + "type": "u8" + }, + { + "name": "hotbar_slot", + "type": "u8" + }, + { + "name": "count", + "type": "u8" + }, + { + "name": "item_stack_id", + "type": "varint32" + }, + { + "name": "custom_name", + "type": "string" + }, + { + "name": "durability_correction", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ], + "ItemComponentList": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + } + ], + "CommandOrigin": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "player", + "1": "block", + "2": "minecart_block", + "3": "dev_console", + "4": "test", + "5": "automation_player", + "6": "client_automation", + "7": "dedicated_server", + "8": "entity", + "9": "virtual", + "10": "game_argument", + "11": "entity_server" + } + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "request_id", + "type": "string" + }, + { + "name": "player_entity_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "dev_console": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ], + "test": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "WindowID": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], + "WindowType": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "container", + "1": "workbench", + "2": "furnace", + "3": "enchantment", + "4": "brewing_stand", + "5": "anvil", + "6": "dispenser", + "7": "dropper", + "8": "hopper", + "9": "cauldron", + "10": "minecart_chest", + "11": "minecart_hopper", + "12": "horse", + "13": "beacon", + "14": "structure_editor", + "15": "trading", + "16": "command_block", + "17": "jukebox", + "18": "armor", + "19": "hand", + "20": "compound_creator", + "21": "element_constructor", + "22": "material_reducer", + "23": "lab_table", + "24": "loom", + "25": "lectern", + "26": "grindstone", + "27": "blast_furnace", + "28": "smoker", + "29": "stonecutter", + "30": "cartography", + "31": "hud", + "32": "jigsaw_editor", + "33": "smithing_table" + } + } + ], + "ContainerSlotType": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "anvil_input", + "1": "anvil_material", + "2": "anvil_result", + "3": "smithing_table_input", + "4": "smithing_table_material", + "5": "smithing_table_result", + "6": "armor", + "7": "container", + "8": "beacon_payment", + "9": "brewing_input", + "10": "brewing_result", + "11": "brewing_fuel", + "12": "hotbar_and_inventory", + "13": "crafting_input", + "14": "crafting_output", + "15": "recipe_construction", + "16": "recipe_nature", + "17": "recipe_items", + "18": "recipe_search", + "19": "recipe_search_bar", + "20": "recipe_equipment", + "21": "enchanting_input", + "22": "enchanting_lapis", + "23": "furnace_fuel", + "24": "furnace_ingredient", + "25": "furnace_output", + "26": "horse_equip", + "27": "hotbar", + "28": "inventory", + "29": "shulker", + "30": "trade_ingredient1", + "31": "trade_ingredient2", + "32": "trade_result", + "33": "offhand", + "34": "compcreate_input", + "35": "compcreate_output", + "36": "elemconstruct_output", + "37": "matreduce_input", + "38": "matreduce_output", + "39": "labtable_input", + "40": "loom_input", + "41": "loom_dye", + "42": "loom_material", + "43": "loom_result", + "44": "blast_furnace_ingredient", + "45": "smoker_ingredient", + "46": "trade2_ingredient1", + "47": "trade2_ingredient2", + "48": "trade2_result", + "49": "grindstone_input", + "50": "grindstone_additional", + "51": "grindstone_result", + "52": "stonecutter_input", + "53": "stonecutter_result", + "54": "cartography_input", + "55": "cartography_additional", + "56": "cartography_result", + "57": "barrel", + "58": "cursor", + "59": "creative_output" + } + } + ], + "LegacyEntityType": [ + "mapper", + { + "type": "li32", + "mappings": { + "10": "chicken", + "11": "cow", + "12": "pig", + "13": "sheep", + "14": "wolf", + "15": "villager", + "16": "mooshroom", + "17": "squid", + "18": "rabbit", + "19": "bat", + "20": "iron_golem", + "21": "snow_golem", + "22": "ocelot", + "23": "horse", + "24": "donkey", + "25": "mule", + "26": "skeleton_horse", + "27": "zombie_horse", + "28": "polar_bear", + "29": "llama", + "30": "parrot", + "31": "dolphin", + "32": "zombie", + "33": "creeper", + "34": "skeleton", + "35": "spider", + "36": "zombie_pigman", + "37": "slime", + "38": "enderman", + "39": "silverfish", + "40": "cave_spider", + "41": "ghast", + "42": "magma_cube", + "43": "blaze", + "44": "zombie_villager", + "45": "witch", + "46": "stray", + "47": "husk", + "48": "wither_skeleton", + "49": "guardian", + "50": "elder_guardian", + "51": "npc", + "52": "wither", + "53": "ender_dragon", + "54": "shulker", + "55": "endermite", + "56": "agent", + "57": "vindicator", + "58": "phantom", + "61": "armor_stand", + "62": "tripod_camera", + "63": "player", + "64": "item", + "65": "tnt", + "66": "falling_block", + "67": "moving_block", + "68": "xp_bottle", + "69": "xp_orb", + "70": "eye_of_ender_signal", + "71": "ender_crystal", + "72": "fireworks_rocket", + "73": "thrown_trident", + "74": "turtle", + "75": "cat", + "76": "shulker_bullet", + "77": "fishing_hook", + "78": "chalkboard", + "79": "dragon_fireball", + "80": "arrow", + "81": "snowball", + "82": "egg", + "83": "painting", + "84": "minecart", + "85": "fireball", + "86": "splash_potion", + "87": "ender_pearl", + "88": "leash_knot", + "89": "wither_skull", + "90": "boat", + "91": "wither_skull_dangerous", + "93": "lightning_bolt", + "94": "small_fireball", + "95": "area_effect_cloud", + "96": "hopper_minecart", + "97": "tnt_minecart", + "98": "chest_minecart", + "100": "command_block_minecart", + "101": "lingering_potion", + "102": "llama_spit", + "103": "evocation_fang", + "104": "evocation_illager", + "105": "vex", + "106": "ice_bomb", + "107": "balloon", + "108": "pufferfish", + "109": "salmon", + "110": "drowned", + "111": "tropicalfish", + "112": "cod", + "113": "panda" + } + } + ], + "mcpe_packet": [ + "container", + [ + { + "name": "name", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "login", + "2": "play_status", + "3": "server_to_client_handshake", + "4": "client_to_server_handshake", + "5": "disconnect", + "6": "resource_packs_info", + "7": "resource_pack_stack", + "8": "resource_pack_client_response", + "9": "text", + "10": "set_time", + "11": "start_game", + "12": "add_player", + "13": "add_entity", + "14": "remove_entity", + "15": "add_item_entity", + "17": "take_item_entity", + "18": "move_entity", + "19": "move_player", + "20": "rider_jump", + "21": "update_block", + "22": "add_painting", + "23": "tick_sync", + "24": "level_sound_event_old", + "25": "level_event", + "26": "block_event", + "27": "entity_event", + "28": "mob_effect", + "29": "update_attributes", + "30": "inventory_transaction", + "31": "mob_equipment", + "32": "mob_armor_equipment", + "33": "interact", + "34": "block_pick_request", + "35": "entity_pick_request", + "36": "player_action", + "38": "hurt_armor", + "39": "set_entity_data", + "40": "set_entity_motion", + "41": "set_entity_link", + "42": "set_health", + "43": "set_spawn_position", + "44": "animate", + "45": "respawn", + "46": "container_open", + "47": "container_close", + "48": "player_hotbar", + "49": "inventory_content", + "50": "inventory_slot", + "51": "container_set_data", + "52": "crafting_data", + "53": "crafting_event", + "54": "gui_data_pick_item", + "55": "adventure_settings", + "56": "block_entity_data", + "57": "player_input", + "58": "level_chunk", + "59": "set_commands_enabled", + "60": "set_difficulty", + "61": "change_dimension", + "62": "set_player_game_type", + "63": "player_list", + "64": "simple_event", + "65": "event", + "66": "spawn_experience_orb", + "67": "clientbound_map_item_data", + "68": "map_info_request", + "69": "request_chunk_radius", + "70": "chunk_radius_update", + "71": "item_frame_drop_item", + "72": "game_rules_changed", + "73": "camera", + "74": "boss_event", + "75": "show_credits", + "76": "available_commands", + "77": "command_request", + "78": "command_block_update", + "79": "command_output", + "80": "update_trade", + "81": "update_equipment", + "82": "resource_pack_data_info", + "83": "resource_pack_chunk_data", + "84": "resource_pack_chunk_request", + "85": "transfer", + "86": "play_sound", + "87": "stop_sound", + "88": "set_title", + "89": "add_behavior_tree", + "90": "structure_block_update", + "91": "show_store_offer", + "92": "purchase_receipt", + "93": "player_skin", + "94": "sub_client_login", + "95": "initiate_web_socket_connection", + "96": "set_last_hurt_by", + "97": "book_edit", + "98": "npc_request", + "99": "photo_transfer", + "100": "modal_form_request", + "101": "modal_form_response", + "102": "server_settings_request", + "103": "server_settings_response", + "104": "show_profile", + "105": "set_default_game_type", + "106": "remove_objective", + "107": "set_display_objective", + "108": "set_score", + "109": "lab_table", + "110": "update_block_synced", + "111": "move_entity_delta", + "112": "set_scoreboard_identity", + "113": "set_local_player_as_initialized", + "114": "update_soft_enum", + "115": "network_stack_latency", + "117": "script_custom_event", + "118": "spawn_particle_effect", + "119": "available_entity_identifiers", + "120": "level_sound_event_v2", + "121": "network_chunk_publisher_update", + "122": "biome_definition_list", + "123": "level_sound_event", + "124": "level_event_generic", + "125": "lectern_update", + "126": "video_stream_connect", + "127": "add_ecs_entity", + "128": "remove_ecs_entity", + "129": "client_cache_status", + "130": "on_screen_texture_animation", + "131": "map_create_locked_copy", + "132": "structure_template_data_export_request", + "133": "structure_template_data_export_response", + "134": "update_block_properties", + "135": "client_cache_blob_status", + "136": "client_cache_miss_response", + "137": "education_settings", + "139": "multiplayer_settings", + "140": "settings_command", + "141": "anvil_damage", + "142": "completed_using_item", + "143": "network_settings", + "144": "player_auth_input", + "145": "creative_content", + "146": "player_enchant_options", + "147": "item_stack_request", + "148": "item_stack_response", + "149": "player_armor_damage", + "151": "update_player_game_type", + "153": "position_tracking_db_broadcast", + "154": "position_tracking_db_request", + "156": "packet_violation_warning", + "157": "motion_prediction_hints", + "158": "animate_entity", + "159": "camera_shake", + "160": "player_fog", + "161": "correct_player_move_prediction", + "162": "item_component", + "163": "filter_text_packet", + "164": "debug_renderer" + } + } + ] + }, + { + "name": "params", + "type": [ + "switch", + { + "compareTo": "name", + "fields": { + "login": "packet_login", + "play_status": "packet_play_status", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", + "disconnect": "packet_disconnect", + "resource_packs_info": "packet_resource_packs_info", + "resource_pack_stack": "packet_resource_pack_stack", + "resource_pack_client_response": "packet_resource_pack_client_response", + "text": "packet_text", + "set_time": "packet_set_time", + "start_game": "packet_start_game", + "add_player": "packet_add_player", + "add_entity": "packet_add_entity", + "remove_entity": "packet_remove_entity", + "add_item_entity": "packet_add_item_entity", + "take_item_entity": "packet_take_item_entity", + "move_entity": "packet_move_entity", + "move_player": "packet_move_player", + "rider_jump": "packet_rider_jump", + "update_block": "packet_update_block", + "add_painting": "packet_add_painting", + "tick_sync": "packet_tick_sync", + "level_sound_event_old": "packet_level_sound_event_old", + "level_event": "packet_level_event", + "block_event": "packet_block_event", + "entity_event": "packet_entity_event", + "mob_effect": "packet_mob_effect", + "update_attributes": "packet_update_attributes", + "inventory_transaction": "packet_inventory_transaction", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", + "interact": "packet_interact", + "block_pick_request": "packet_block_pick_request", + "entity_pick_request": "packet_entity_pick_request", + "player_action": "packet_player_action", + "hurt_armor": "packet_hurt_armor", + "set_entity_data": "packet_set_entity_data", + "set_entity_motion": "packet_set_entity_motion", + "set_entity_link": "packet_set_entity_link", + "set_health": "packet_set_health", + "set_spawn_position": "packet_set_spawn_position", + "animate": "packet_animate", + "respawn": "packet_respawn", + "container_open": "packet_container_open", + "container_close": "packet_container_close", + "player_hotbar": "packet_player_hotbar", + "inventory_content": "packet_inventory_content", + "inventory_slot": "packet_inventory_slot", + "container_set_data": "packet_container_set_data", + "crafting_data": "packet_crafting_data", + "crafting_event": "packet_crafting_event", + "gui_data_pick_item": "packet_gui_data_pick_item", + "adventure_settings": "packet_adventure_settings", + "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", + "level_chunk": "packet_level_chunk", + "set_commands_enabled": "packet_set_commands_enabled", + "set_difficulty": "packet_set_difficulty", + "change_dimension": "packet_change_dimension", + "set_player_game_type": "packet_set_player_game_type", + "player_list": "packet_player_list", + "simple_event": "packet_simple_event", + "event": "packet_event", + "spawn_experience_orb": "packet_spawn_experience_orb", + "clientbound_map_item_data": "packet_clientbound_map_item_data", + "map_info_request": "packet_map_info_request", + "request_chunk_radius": "packet_request_chunk_radius", + "chunk_radius_update": "packet_chunk_radius_update", + "item_frame_drop_item": "packet_item_frame_drop_item", + "game_rules_changed": "packet_game_rules_changed", + "camera": "packet_camera", + "boss_event": "packet_boss_event", + "show_credits": "packet_show_credits", + "available_commands": "packet_available_commands", + "command_request": "packet_command_request", + "command_block_update": "packet_command_block_update", + "command_output": "packet_command_output", + "update_trade": "packet_update_trade", + "update_equipment": "packet_update_equipment", + "resource_pack_data_info": "packet_resource_pack_data_info", + "resource_pack_chunk_data": "packet_resource_pack_chunk_data", + "resource_pack_chunk_request": "packet_resource_pack_chunk_request", + "transfer": "packet_transfer", + "play_sound": "packet_play_sound", + "stop_sound": "packet_stop_sound", + "set_title": "packet_set_title", + "add_behavior_tree": "packet_add_behavior_tree", + "structure_block_update": "packet_structure_block_update", + "show_store_offer": "packet_show_store_offer", + "purchase_receipt": "packet_purchase_receipt", + "player_skin": "packet_player_skin", + "sub_client_login": "packet_sub_client_login", + "initiate_web_socket_connection": "packet_initiate_web_socket_connection", + "set_last_hurt_by": "packet_set_last_hurt_by", + "book_edit": "packet_book_edit", + "npc_request": "packet_npc_request", + "photo_transfer": "packet_photo_transfer", + "modal_form_request": "packet_modal_form_request", + "modal_form_response": "packet_modal_form_response", + "server_settings_request": "packet_server_settings_request", + "server_settings_response": "packet_server_settings_response", + "show_profile": "packet_show_profile", + "set_default_game_type": "packet_set_default_game_type", + "remove_objective": "packet_remove_objective", + "set_display_objective": "packet_set_display_objective", + "set_score": "packet_set_score", + "lab_table": "packet_lab_table", + "update_block_synced": "packet_update_block_synced", + "move_entity_delta": "packet_move_entity_delta", + "set_scoreboard_identity": "packet_set_scoreboard_identity", + "set_local_player_as_initialized": "packet_set_local_player_as_initialized", + "update_soft_enum": "packet_update_soft_enum", + "network_stack_latency": "packet_network_stack_latency", + "script_custom_event": "packet_script_custom_event", + "spawn_particle_effect": "packet_spawn_particle_effect", + "available_entity_identifiers": "packet_available_entity_identifiers", + "level_sound_event_v2": "packet_level_sound_event_v2", + "network_chunk_publisher_update": "packet_network_chunk_publisher_update", + "biome_definition_list": "packet_biome_definition_list", + "level_sound_event": "packet_level_sound_event", + "level_event_generic": "packet_level_event_generic", + "lectern_update": "packet_lectern_update", + "video_stream_connect": "packet_video_stream_connect", + "add_ecs_entity": "packet_add_ecs_entity", + "remove_ecs_entity": "packet_remove_ecs_entity", + "client_cache_status": "packet_client_cache_status", + "on_screen_texture_animation": "packet_on_screen_texture_animation", + "map_create_locked_copy": "packet_map_create_locked_copy", + "structure_template_data_export_request": "packet_structure_template_data_export_request", + "structure_template_data_export_response": "packet_structure_template_data_export_response", + "update_block_properties": "packet_update_block_properties", + "client_cache_blob_status": "packet_client_cache_blob_status", + "client_cache_miss_response": "packet_client_cache_miss_response", + "education_settings": "packet_education_settings", + "multiplayer_settings": "packet_multiplayer_settings", + "settings_command": "packet_settings_command", + "anvil_damage": "packet_anvil_damage", + "completed_using_item": "packet_completed_using_item", + "network_settings": "packet_network_settings", + "player_auth_input": "packet_player_auth_input", + "creative_content": "packet_creative_content", + "player_enchant_options": "packet_player_enchant_options", + "item_stack_request": "packet_item_stack_request", + "item_stack_response": "packet_item_stack_response", + "player_armor_damage": "packet_player_armor_damage", + "update_player_game_type": "packet_update_player_game_type", + "position_tracking_db_request": "packet_position_tracking_db_request", + "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", + "packet_violation_warning": "packet_packet_violation_warning", + "motion_prediction_hints": "packet_motion_prediction_hints", + "animate_entity": "packet_animate_entity", + "camera_shake": "packet_camera_shake", + "player_fog": "packet_player_fog", + "correct_player_move_prediction": "packet_correct_player_move_prediction", + "item_component": "packet_item_component", + "filter_text_packet": "packet_filter_text_packet", + "debug_renderer": "packet_debug_renderer" + }, + "default": "void" + } + ] + } + ] + ], + "packet_login": [ + "container", + [ + { + "name": "protocol_version", + "type": "i32" + }, + { + "name": "payload_size", + "type": "varint" + }, + { + "name": "chain", + "type": "LittleString" + }, + { + "name": "client_data", + "type": "LittleString" + } + ] + ], + "packet_play_status": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "i32", + "mappings": { + "0": "login_success", + "1": "failed_client", + "2": "failed_spawn", + "3": "player_spawn", + "4": "failed_invalid_tenant", + "5": "failed_vanilla_edu", + "6": "failed_edu_vanilla", + "7": "failed_server_full" + } + } + ] + } + ] + ], + "packet_server_to_client_handshake": [ + "container", + [ + { + "name": "token", + "type": "string" + } + ] + ], + "packet_client_to_server_handshake": [ + "container", + [] + ], + "packet_disconnect": [ + "container", + [ + { + "name": "hide_disconnect_reason", + "type": "bool" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "packet_resource_packs_info": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "behaviour_packs", + "type": "BehaviourPackInfos" + }, + { + "name": "texture_packs", + "type": "TexturePackInfos" + } + ] + ], + "packet_resource_pack_stack": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behavior_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "resource_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + } + ] + ], + "packet_resource_pack_client_response": [ + "container", + [ + { + "name": "response_status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "refused", + "2": "send_packs", + "3": "have_all_packs", + "4": "completed" + } + } + ] + }, + { + "name": "resourcepackids", + "type": "ResourcePackIds" + } + ] + ], + "packet_text": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "raw", + "1": "chat", + "2": "translation", + "3": "popup", + "4": "jukebox_popup", + "5": "tip", + "6": "system", + "7": "whisper", + "8": "announcement", + "9": "json_whisper", + "10": "json" + } + } + ] + }, + { + "name": "needs_translation", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "chat": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "whisper": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "announcement": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "raw": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "tip": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "system": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json_whisper": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "translation": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "jukebox_popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "xuid", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + } + ] + ], + "packet_set_time": [ + "container", + [ + { + "name": "time", + "type": "zigzag32" + } + ] + ], + "packet_start_game": [ + "container", + [ + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "player_gamemode", + "type": "GameMode" + }, + { + "name": "player_position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "vec2f" + }, + { + "name": "seed", + "type": "zigzag32" + }, + { + "name": "biome_type", + "type": "li16" + }, + { + "name": "biome_name", + "type": "string" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "generator", + "type": "zigzag32" + }, + { + "name": "world_gamemode", + "type": "GameMode" + }, + { + "name": "difficulty", + "type": "zigzag32" + }, + { + "name": "spawn_position", + "type": "BlockCoordinates" + }, + { + "name": "achievements_disabled", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", + "type": "zigzag32" + }, + { + "name": "edu_offer", + "type": "zigzag32" + }, + { + "name": "edu_features_enabled", + "type": "bool" + }, + { + "name": "edu_product_uuid", + "type": "string" + }, + { + "name": "rain_level", + "type": "lf32" + }, + { + "name": "lightning_level", + "type": "lf32" + }, + { + "name": "has_confirmed_platform_locked_content", + "type": "bool" + }, + { + "name": "is_multiplayer", + "type": "bool" + }, + { + "name": "broadcast_to_lan", + "type": "bool" + }, + { + "name": "xbox_live_broadcast_mode", + "type": "varint" + }, + { + "name": "platform_broadcast_mode", + "type": "varint" + }, + { + "name": "enable_commands", + "type": "bool" + }, + { + "name": "is_texturepacks_required", + "type": "bool" + }, + { + "name": "gamerules", + "type": "GameRules" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + }, + { + "name": "bonus_chest", + "type": "bool" + }, + { + "name": "map_enabled", + "type": "bool" + }, + { + "name": "permission_level", + "type": "zigzag32" + }, + { + "name": "server_chunk_tick_range", + "type": "li32" + }, + { + "name": "has_locked_behavior_pack", + "type": "bool" + }, + { + "name": "has_locked_resource_pack", + "type": "bool" + }, + { + "name": "is_from_locked_world_template", + "type": "bool" + }, + { + "name": "msa_gamertags_only", + "type": "bool" + }, + { + "name": "is_from_world_template", + "type": "bool" + }, + { + "name": "is_world_template_option_locked", + "type": "bool" + }, + { + "name": "only_spawn_v1_villagers", + "type": "bool" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "limited_world_width", + "type": "li32" + }, + { + "name": "limited_world_length", + "type": "li32" + }, + { + "name": "is_new_nether", + "type": "bool" + }, + { + "name": "experimental_gameplay_override", + "type": "bool" + }, + { + "name": "level_id", + "type": "string" + }, + { + "name": "world_name", + "type": "string" + }, + { + "name": "premium_world_template_id", + "type": "string" + }, + { + "name": "is_trial", + "type": "bool" + }, + { + "name": "movement_authority", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "client", + "1": "server", + "2": "server_with_rewind" + } + } + ] + }, + { + "name": "rewind_history_size", + "type": "zigzag32" + }, + { + "name": "server_authoritative_block_breaking", + "type": "bool" + }, + { + "name": "current_tick", + "type": "li64" + }, + { + "name": "enchantment_seed", + "type": "zigzag32" + }, + { + "name": "block_palette", + "type": "BlockPalette" + }, + { + "name": "itemstates", + "type": "Itemstates" + }, + { + "name": "multiplayer_correlation_id", + "type": "string" + }, + { + "name": "server_authoritative_inventory", + "type": "bool" + } + ] + ], + "packet_add_player": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "flags", + "type": "varint" + }, + { + "name": "command_permission", + "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + }, + { + "name": "links", + "type": "Links" + }, + { + "name": "device_id", + "type": "string" + }, + { + "name": "device_os", + "type": "li32" + } + ] + ], + "packet_add_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "attributes", + "type": "EntityAttributes" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "links", + "type": "Links" + } + ] + ], + "packet_remove_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + } + ] + ], + "packet_add_item_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "is_from_fishing", + "type": "bool" + } + ] + ], + "packet_take_item_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "target", + "type": "varint" + } + ] + ], + "packet_move_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "Rotation" + } + ] + ], + "packet_move_player": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "mode", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "normal", + "1": "reset", + "2": "teleport", + "3": "rotation" + } + } + ] + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "ridden_runtime_id", + "type": "varint" + }, + { + "name": "teleport", + "type": [ + "switch", + { + "compareTo": "mode", + "fields": { + "teleport": [ + "container", + [ + { + "name": "cause", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "unknown", + "1": "projectile", + "2": "chorus_fruit", + "3": "command", + "4": "behavior" + } + } + ] + }, + { + "name": "source_entity_type", + "type": "LegacyEntityType" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_rider_jump": [ + "container", + [ + { + "name": "jump_strength", + "type": "zigzag32" + } + ] + ], + "packet_update_block": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + } + ] + ], + "packet_add_painting": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "direction", + "type": "zigzag32" + }, + { + "name": "title", + "type": "string" + } + ] + ], + "packet_tick_sync": [ + "container", + [ + { + "name": "request_time", + "type": "li64" + }, + { + "name": "response_time", + "type": "li64" + } + ] + ], + "packet_level_sound_event_old": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "zigzag32" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event": [ + "container", + [ + { + "name": "event", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "1000": "sound_click", + "1001": "sound_click_fail", + "1002": "sound_shoot", + "1003": "sound_door", + "1004": "sound_fizz", + "1005": "sound_ignite", + "1007": "sound_ghast", + "1008": "sound_ghast_shoot", + "1009": "sound_blaze_shoot", + "1010": "sound_door_bump", + "1012": "sound_door_crash", + "1018": "sound_enderman_teleport", + "1020": "sound_anvil_break", + "1021": "sound_anvil_use", + "1022": "sound_anvil_fall", + "1030": "sound_pop", + "1032": "sound_portal", + "1040": "sound_itemframe_add_item", + "1041": "sound_itemframe_remove", + "1042": "sound_itemframe_place", + "1043": "sound_itemframe_remove_item", + "1044": "sound_itemframe_rotate_item", + "1050": "sound_camera", + "1051": "sound_orb", + "1052": "sound_totem", + "1060": "sound_armor_stand_break", + "1061": "sound_armor_stand_hit", + "1062": "sound_armor_stand_fall", + "1063": "sound_armor_stand_place", + "2000": "particle_shoot", + "2001": "particle_destroy", + "2002": "particle_splash", + "2003": "particle_eye_despawn", + "2004": "particle_spawn", + "2006": "guardian_curse", + "2008": "particle_block_force_field", + "2009": "particle_projectile_hit", + "2013": "particle_enderman_teleport", + "2014": "particle_punch_block", + "3001": "start_rain", + "3002": "start_thunder", + "3003": "stop_rain", + "3004": "stop_thunder", + "3005": "pause_game", + "3006": "pause_game_no_screen", + "3007": "set_game_speed", + "3500": "redstone_trigger", + "3501": "cauldron_explode", + "3502": "cauldron_dye_armor", + "3503": "cauldron_clean_armor", + "3504": "cauldron_fill_potion", + "3505": "cauldron_take_potion", + "3506": "cauldron_fill_water", + "3507": "cauldron_take_water", + "3508": "cauldron_add_dye", + "3509": "cauldron_clean_banner", + "3600": "block_start_break", + "3601": "block_stop_break", + "4000": "set_data", + "9800": "players_sleeping", + "16384": "add_particle_mask" + } + } + ] + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_block_event": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "sound", + "1": "change_state" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_entity_event": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "event_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "jump", + "2": "hurt_animation", + "3": "death_animation", + "4": "arm_swing", + "5": "stop_attack", + "6": "tame_fail", + "7": "tame_success", + "8": "shake_wet", + "9": "use_item", + "10": "eat_grass_animation", + "11": "fish_hook_bubble", + "12": "fish_hook_position", + "13": "fish_hook_hook", + "14": "fish_hook_tease", + "15": "squid_ink_cloud", + "16": "zombie_villager_cure", + "18": "respawn", + "19": "iron_golem_offer_flower", + "20": "iron_golem_withdraw_flower", + "21": "love_particles", + "22": "villager_angry", + "23": "villager_happy", + "24": "witch_spell_particles", + "25": "firework_particles", + "26": "in_love_particles", + "27": "silverfish_spawn_animation", + "28": "guardian_attack", + "29": "witch_drink_potion", + "30": "witch_throw_potion", + "31": "minecart_tnt_prime_fuse", + "32": "creeper_prime_fuse", + "33": "air_supply_expired", + "34": "player_add_xp_levels", + "35": "elder_guardian_curse", + "36": "agent_arm_swing", + "37": "ender_dragon_death", + "38": "dust_particles", + "39": "arrow_shake", + "57": "eating_item", + "60": "baby_animal_feed", + "61": "death_smoke_cloud", + "62": "complete_trade", + "63": "remove_leash", + "65": "consume_totem", + "66": "player_check_treasure_hunter_achievement", + "67": "entity_spawn", + "68": "dragon_puke", + "69": "item_entity_merge", + "70": "start_swim", + "71": "balloon_pop", + "72": "treasure_hunt", + "73": "agent_summon", + "74": "charged_crossbow", + "75": "fall" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_mob_effect": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "effect_id", + "type": "zigzag32" + }, + { + "name": "amplifier", + "type": "zigzag32" + }, + { + "name": "particles", + "type": "bool" + }, + { + "name": "duration", + "type": "zigzag32" + } + ] + ], + "packet_update_attributes": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "attributes", + "type": "PlayerAttributes" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_inventory_transaction": [ + "container", + [ + { + "name": "transaction", + "type": "Transaction" + } + ] + ], + "packet_mob_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "selected_slot", + "type": "u8" + }, + { + "name": "windows_id", + "type": "WindowID" + } + ] + ], + "packet_mob_armor_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "helmet", + "type": "Item" + }, + { + "name": "chestplate", + "type": "Item" + }, + { + "name": "leggings", + "type": "Item" + }, + { + "name": "boots", + "type": "Item" + } + ] + ], + "packet_interact": [ + "container", + [ + { + "name": "action_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "3": "leave_vehicle", + "4": "mouse_over_entity", + "6": "open_inventory" + } + } + ] + }, + { + "name": "target_runtime_entity_id", + "type": "varint" + }, + { + "name": "position", + "type": [ + "switch", + { + "compareTo": "action_id", + "fields": { + "mouse_over_entity": "vec3f", + "leave_vehicle": "vec3f" + }, + "default": "void" + } + ] + } + ] + ], + "packet_block_pick_request": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "add_user_data", + "type": "bool" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_entity_pick_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "lu64" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_player_action": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "action", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "start_break", + "1": "abort_break", + "2": "stop_break", + "3": "get_updated_block", + "4": "drop_item", + "5": "start_sleeping", + "6": "stop_sleeping", + "7": "respawn", + "8": "jump", + "9": "start_sprint", + "10": "stop_sprint", + "11": "start_sneak", + "12": "stop_sneak", + "13": "creative_player_destroy_block", + "14": "dimension_change_ack", + "15": "start_glide", + "16": "stop_glide", + "17": "build_denied", + "18": "crack_break", + "19": "change_skin", + "20": "set_enchatnment_seed", + "21": "swimming", + "22": "stop_swimming", + "23": "start_spin_attack", + "24": "stop_spin_attack", + "25": "ineract_block", + "26": "predict_break", + "27": "continue_break" + } + } + ] + }, + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "packet_hurt_armor": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_entity_data": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "tick", + "type": "varint" + } + ] + ], + "packet_set_entity_motion": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "velocity", + "type": "vec3f" + } + ] + ], + "packet_set_entity_link": [ + "container", + [ + { + "name": "link", + "type": "Link" + } + ] + ], + "packet_set_health": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_spawn_position": [ + "container", + [ + { + "name": "spawn_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "player", + "1": "world" + } + } + ] + }, + { + "name": "player_position", + "type": "BlockCoordinates" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "world_position", + "type": "BlockCoordinates" + } + ] + ], + "packet_animate": [ + "container", + [ + { + "name": "action_id", + "type": "zigzag32" + }, + { + "name": "runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_respawn": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "state", + "type": "u8" + }, + { + "name": "runtime_entity_id", + "type": "varint" + } + ] + ], + "packet_container_open": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "runtime_entity_id", + "type": "zigzag64" + } + ] + ], + "packet_container_close": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "server", + "type": "bool" + } + ] + ], + "packet_player_hotbar": [ + "container", + [ + { + "name": "selected_slot", + "type": "varint" + }, + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "select_slot", + "type": "bool" + } + ] + ], + "packet_inventory_content": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + }, + { + "name": "input", + "type": "ItemStacks" + } + ] + ], + "packet_inventory_slot": [ + "container", + [ + { + "name": "window_id", + "type": "varint" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "item", + "type": "ItemStack" + } + ] + ], + "packet_container_set_data": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "property", + "type": "zigzag32" + }, + { + "name": "value", + "type": "zigzag32" + } + ] + ], + "packet_crafting_data": [ + "container", + [ + { + "name": "recipes", + "type": "Recipes" + }, + { + "name": "potion_type_recipes", + "type": "PotionTypeRecipes" + }, + { + "name": "potion_container_recipes", + "type": "PotionContainerChangeRecipes" + }, + { + "name": "is_clean", + "type": "bool" + } + ] + ], + "packet_crafting_event": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "recipe_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "inventory", + "1": "crafting", + "2": "workbench" + } + } + ] + }, + { + "name": "recipe_id", + "type": "uuid" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "result", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + } + ] + ], + "packet_gui_data_pick_item": [ + "container", + [] + ], + "packet_adventure_settings": [ + "container", + [ + { + "name": "flags", + "type": "AdventureFlags" + }, + { + "name": "command_permission", + "type": [ + "mapper", + { + "type": "varint32", + "mappings": { + "0": "normal", + "1": "operator", + "2": "host", + "3": "automation", + "4": "admin" + } + } + ] + }, + { + "name": "action_permissions", + "type": "ActionPermissions" + }, + { + "name": "permission_level", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "visitor", + "1": "member", + "2": "operator", + "3": "custom" + } + } + ] + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + } + ] + ], + "packet_block_entity_data": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_player_input": [ + "container", + [ + { + "name": "motion_x", + "type": "lf32" + }, + { + "name": "motion_z", + "type": "lf32" + }, + { + "name": "jumping", + "type": "bool" + }, + { + "name": "sneaking", + "type": "bool" + } + ] + ], + "packet_level_chunk": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "sub_chunk_count", + "type": "varint" + }, + { + "name": "cache_enabled", + "type": "bool" + }, + { + "name": "blobs", + "type": [ + "switch", + { + "compareTo": "cache_enabled", + "fields": { + "true": [ + "container", + [ + { + "name": "hashes", + "type": [ + "array", + { + "countType": "varint", + "type": "lu64" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_set_commands_enabled": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_set_difficulty": [ + "container", + [ + { + "name": "difficulty", + "type": "varint" + } + ] + ], + "packet_change_dimension": [ + "container", + [ + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "respawn", + "type": "bool" + } + ] + ], + "packet_set_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_player_list": [ + "container", + [ + { + "name": "records", + "type": "PlayerRecords" + } + ] + ], + "packet_simple_event": [ + "container", + [ + { + "name": "event_type", + "type": "lu16" + } + ] + ], + "packet_event": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint64" + }, + { + "name": "event_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "achievement_awarded", + "1": "entity_interact", + "2": "portal_built", + "3": "portal_used", + "4": "mob_killed", + "5": "cauldron_used", + "6": "player_death", + "7": "boss_killed", + "8": "agent_command", + "9": "agent_created", + "10": "banner_pattern_removed", + "11": "commaned_executed", + "12": "fish_bucketed", + "13": "mob_born", + "14": "pet_died", + "15": "cauldron_block_used", + "16": "composter_block_used", + "17": "bell_block_used", + "18": "actor_definition", + "19": "raid_update", + "20": "player_movement_anomaly", + "21": "player_moement_corrected", + "22": "honey_harvested", + "23": "target_block_hit", + "24": "piglin_barter" + } + } + ] + }, + { + "name": "use_player_id", + "type": "u8" + }, + { + "name": "event_data", + "type": "restBuffer" + } + ] + ], + "packet_spawn_experience_orb": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ], + "packet_clientbound_map_item_data": [ + "container", + [ + { + "name": "mapinfo", + "type": "MapInfo" + } + ] + ], + "packet_map_info_request": [ + "container", + [ + { + "name": "map_id", + "type": "zigzag64" + } + ] + ], + "packet_request_chunk_radius": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_chunk_radius_update": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_item_frame_drop_item": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + } + ] + ], + "packet_game_rules_changed": [ + "container", + [ + { + "name": "rules", + "type": "GameRules" + } + ] + ], + "packet_camera": [ + "container", + [ + { + "name": "camera_entity_unique_id", + "type": "zigzag64" + }, + { + "name": "target_player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_boss_event": [ + "container", + [ + { + "name": "boss_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "show_bar", + "1": "register_player", + "2": "hide_bar", + "3": "unregister_player", + "4": "set_bar_progress", + "5": "set_bar_title", + "6": "update_properties", + "7": "texture" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "register_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "unregister_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "show": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "bar_progress", + "type": "lf32" + } + ] + ], + "update_properties": [ + "container", + [ + { + "name": "darkness_factor", + "type": "li16" + } + ] + ], + "texture": [ + "container", + [ + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], + "set_bar_progress": [ + "container", + [ + { + "name": "bar_progress", + "type": "lf32" + } + ] + ], + "set_bar_title": [ + "container", + [ + { + "name": "title", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_show_credits": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "status", + "type": "zigzag32" + } + ] + ], + "packet_available_commands": [ + "container", + [ + { + "name": "values_len", + "type": "varint" + }, + { + "name": "_enum_type", + "type": [ + "enum_size_based_on_values_len" + ] + }, + { + "name": "enum_values", + "type": [ + "array", + { + "count": "values_len", + "type": "string" + } + ] + }, + { + "name": "suffixes", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + }, + { + "name": "enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "switch", + { + "compareTo": "../_enum_type", + "fields": { + "byte": "u8", + "short": "lu16", + "int": "lu32" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "command_data", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "description", + "type": "string" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "permission_level", + "type": "u8" + }, + { + "name": "alias", + "type": "li32" + }, + { + "name": "overloads", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "paramater_name", + "type": "string" + }, + { + "name": "value_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "1": "int", + "2": "float", + "3": "value", + "4": "wildcard_int", + "5": "operator", + "6": "target", + "16": "file_path", + "32": "string", + "40": "position", + "44": "message", + "46": "raw_text", + "50": "json", + "63": "command" + } + } + ] + }, + { + "name": "enum_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "16": "valid", + "32": "enum", + "256": "suffixed", + "1024": "soft_enum" + } + } + ] + }, + { + "name": "optional", + "type": "bool" + }, + { + "name": "options", + "type": "CommandFlags" + } + ] + ] + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "dynamic_enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "enum_constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "value_index", + "type": "li32" + }, + { + "name": "enum_index", + "type": "li32" + }, + { + "name": "constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "constraint", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "cheats_enabled" + } + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_command_request": [ + "container", + [ + { + "name": "command", + "type": "string" + }, + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "interval", + "type": "bool" + } + ] + ], + "packet_command_block_update": [ + "container", + [ + { + "name": "is_block", + "type": "bool" + } + ] + ], + "packet_command_output": [ + "container", + [ + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "output_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "last", + "2": "silent", + "3": "all", + "4": "data_set" + } + } + ] + }, + { + "name": "success_count", + "type": "varint" + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "success", + "type": "bool" + }, + { + "name": "message_id", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "data_set", + "type": [ + "switch", + { + "compareTo": "output_type", + "fields": { + "data_set": "string" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_trade": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "varint" + }, + { + "name": "trade_tier", + "type": "varint" + }, + { + "name": "villager_unique_id", + "type": "varint64" + }, + { + "name": "entity_unique_id", + "type": "varint64" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "new_trading_ui", + "type": "bool" + }, + { + "name": "economic_trades", + "type": "bool" + }, + { + "name": "offers", + "type": "nbt" + } + ] + ], + "packet_update_equipment": [ + "container", + [ + { + "name": "window_id", + "type": "u8" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "inventory", + "type": "nbt" + } + ] + ], + "packet_resource_pack_data_info": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "max_chunk_size", + "type": "lu32" + }, + { + "name": "chunk_count", + "type": "lu32" + }, + { + "name": "compressed_package_size", + "type": "lu64" + }, + { + "name": "hash", + "type": "ByteArray" + }, + { + "name": "is_premium", + "type": "bool" + }, + { + "name": "pack_type", + "type": "u8" + } + ] + ], + "packet_resource_pack_chunk_data": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + }, + { + "name": "progress", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_resource_pack_chunk_request": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + } + ] + ], + "packet_transfer": [ + "container", + [ + { + "name": "server_address", + "type": "string" + }, + { + "name": "port", + "type": "lu16" + } + ] + ], + "packet_play_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "volume", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + } + ] + ], + "packet_stop_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "stop_all", + "type": "bool" + } + ] + ], + "packet_set_title": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "clear", + "1": "reset", + "2": "set_title", + "3": "set_subtitle", + "4": "action_bar_message", + "5": "set_durations", + "6": "set_title_json", + "7": "set_subtitle_json", + "8": "action_bar_message_json" + } + } + ] + }, + { + "name": "text", + "type": "string" + }, + { + "name": "fade_in_time", + "type": "zigzag32" + }, + { + "name": "stay_time", + "type": "zigzag32" + }, + { + "name": "fade_out_time", + "type": "zigzag32" + } + ] + ], + "packet_add_behavior_tree": [ + "container", + [ + { + "name": "behaviortree", + "type": "string" + } + ] + ], + "packet_structure_block_update": [ + "container", + [] + ], + "packet_show_store_offer": [ + "container", + [ + { + "name": "unknown0", + "type": "string" + }, + { + "name": "unknown1", + "type": "bool" + } + ] + ], + "packet_purchase_receipt": [ + "container", + [] + ], + "packet_player_skin": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "skin", + "type": "Skin" + }, + { + "name": "skin_name", + "type": "string" + }, + { + "name": "old_skin_name", + "type": "string" + }, + { + "name": "is_verified", + "type": "bool" + } + ] + ], + "packet_sub_client_login": [ + "container", + [] + ], + "packet_initiate_web_socket_connection": [ + "container", + [ + { + "name": "server", + "type": "string" + } + ] + ], + "packet_set_last_hurt_by": [ + "container", + [ + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_book_edit": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "replace_page", + "1": "add_page", + "2": "delete_page", + "3": "swap_pages", + "4": "sign" + } + } + ] + }, + { + "name": "slot", + "type": "u8" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "replace_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "add_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "delete_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + } + ] + ], + "swap_pages": [ + "container", + [ + { + "name": "page1", + "type": "u8" + }, + { + "name": "page2", + "type": "u8" + } + ] + ], + "sign": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "author", + "type": "string" + }, + { + "name": "xuid", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_npc_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint" + }, + { + "name": "unknown0", + "type": "u8" + }, + { + "name": "unknown1", + "type": "string" + }, + { + "name": "unknown2", + "type": "u8" + } + ] + ], + "packet_photo_transfer": [ + "container", + [ + { + "name": "file_name", + "type": "string" + }, + { + "name": "image_data", + "type": "string" + }, + { + "name": "unknown2", + "type": "string" + } + ] + ], + "packet_modal_form_request": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_modal_form_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_server_settings_request": [ + "container", + [] + ], + "packet_server_settings_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_show_profile": [ + "container", + [ + { + "name": "xuid", + "type": "string" + } + ] + ], + "packet_set_default_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_remove_objective": [ + "container", + [ + { + "name": "objective_name", + "type": "string" + } + ] + ], + "packet_set_display_objective": [ + "container", + [ + { + "name": "display_slot", + "type": "string" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "criteria_name", + "type": "string" + }, + { + "name": "sort_order", + "type": "zigzag32" + } + ] + ], + "packet_set_score": [ + "container", + [ + { + "name": "entries", + "type": "ScoreEntries" + } + ] + ], + "packet_lab_table": [ + "container", + [ + { + "name": "useless_byte", + "type": "u8" + }, + { + "name": "lab_table_x", + "type": "varint" + }, + { + "name": "lab_table_y", + "type": "varint" + }, + { + "name": "lab_table_z", + "type": "varint" + }, + { + "name": "reaction_type", + "type": "u8" + } + ] + ], + "packet_update_block_synced": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + }, + { + "name": "entity_unique_id", + "type": "varint" + }, + { + "name": "transition_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "entity", + "1": "create", + "2": "destroy" + } + } + ] + } + ] + ], + "packet_move_entity_delta": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "flags", + "type": "DeltaMoveFlags" + }, + { + "name": "x", + "type": [ + "switch", + { + "compareTo": "flags.has_x", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "y", + "type": [ + "switch", + { + "compareTo": "flags.has_y", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "z", + "type": [ + "switch", + { + "compareTo": "flags.has_z", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "rot_x", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_x", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_y", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_y", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_z", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_z", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + } + ] + ], + "packet_set_scoreboard_identity": [ + "container", + [ + { + "name": "entries", + "type": "ScoreboardIdentityEntries" + } + ] + ], + "packet_set_local_player_as_initialized": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_update_soft_enum": [ + "container", + [] + ], + "packet_network_stack_latency": [ + "container", + [ + { + "name": "timestamp", + "type": "lu64" + }, + { + "name": "unknown_flag", + "type": "u8" + } + ] + ], + "packet_script_custom_event": [ + "container", + [ + { + "name": "event_name", + "type": "string" + }, + { + "name": "event_data", + "type": "string" + } + ] + ], + "packet_spawn_particle_effect": [ + "container", + [ + { + "name": "dimension_id", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "particle_name", + "type": "string" + } + ] + ], + "packet_available_entity_identifiers": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event_v2": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_network_chunk_publisher_update": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "radius", + "type": "varint" + } + ] + ], + "packet_biome_definition_list": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event": [ + "container", + [ + { + "name": "sound_id", + "type": "varint" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event_generic": [ + "container", + [ + { + "name": "event_id", + "type": "varint" + }, + { + "name": "nbt", + "type": "nbtLoop" + } + ] + ], + "packet_lectern_update": [ + "container", + [ + { + "name": "page", + "type": "u8" + }, + { + "name": "page_count", + "type": "u8" + }, + { + "name": "position", + "type": "vec3i" + }, + { + "name": "drop_book", + "type": "bool" + } + ] + ], + "packet_video_stream_connect": [ + "container", + [ + { + "name": "server_uri", + "type": "string" + }, + { + "name": "frame_send_frequency", + "type": "lf32" + }, + { + "name": "action", + "type": "u8" + }, + { + "name": "resolution_x", + "type": "li32" + }, + { + "name": "resolution_y", + "type": "li32" + } + ] + ], + "packet_add_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_remove_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_client_cache_status": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_on_screen_texture_animation": [ + "container", + [] + ], + "packet_map_create_locked_copy": [ + "container", + [] + ], + "packet_structure_template_data_export_request": [ + "container", + [] + ], + "packet_structure_template_data_export_response": [ + "container", + [] + ], + "packet_update_block_properties": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_client_cache_blob_status": [ + "container", + [ + { + "name": "misses", + "type": "varint" + }, + { + "name": "haves", + "type": "varint" + }, + { + "name": "missing", + "type": [ + "array", + { + "count": "misses", + "type": "lu64" + } + ] + }, + { + "name": "have", + "type": [ + "array", + { + "count": "haves", + "type": "lu64" + } + ] + } + ] + ], + "packet_client_cache_miss_response": [ + "container", + [ + { + "name": "blobs", + "type": [ + "array", + { + "countType": "varint", + "type": "Blob" + } + ] + } + ] + ], + "packet_education_settings": [ + "container", + [ + { + "name": "CodeBuilderDefaultURI", + "type": "string" + }, + { + "name": "CodeBuilderTitle", + "type": "string" + }, + { + "name": "CanResizeCodeBuilder", + "type": "bool" + }, + { + "name": "HasOverrideURI", + "type": "bool" + }, + { + "name": "OverrideURI", + "type": [ + "switch", + { + "compareTo": "HasOverrideURI", + "fields": { + "true": "string" + }, + "default": "void" + } + ] + }, + { + "name": "HasQuiz", + "type": "bool" + } + ] + ], + "packet_multiplayer_settings": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "enable_multiplayer", + "1": "disable_multiplayer", + "2": "refresh_join_code" + } + } + ] + } + ] + ], + "packet_settings_command": [ + "container", + [ + { + "name": "command_line", + "type": "string" + }, + { + "name": "suppress_output", + "type": "bool" + } + ] + ], + "packet_anvil_damage": [ + "container", + [ + { + "name": "damage", + "type": "u8" + }, + { + "name": "position", + "type": "BlockCoordinates" + } + ] + ], + "packet_completed_using_item": [ + "container", + [ + { + "name": "used_item_id", + "type": "li16" + }, + { + "name": "use_method", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "equip_armor", + "1": "eat", + "2": "attack", + "3": "consume", + "4": "throw", + "5": "shoot", + "6": "place", + "7": "fill_bottle", + "8": "fill_bucket", + "9": "pour_bucket", + "10": "use_tool", + "11": "interact", + "12": "retrieved", + "13": "dyed", + "14": "traded" + } + } + ] + } + ] + ], + "packet_network_settings": [ + "container", + [ + { + "name": "compression_threshold", + "type": "u16" + } + ] + ], + "packet_player_auth_input": [ + "container", + [ + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "move_vector", + "type": "vec2f" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "input_data", + "type": "InputFlag" + }, + { + "name": "input_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "mouse", + "1": "touch", + "2": "game_pad", + "3": "motion_controller" + } + } + ] + }, + { + "name": "play_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "teaser", + "2": "screen", + "3": "viewer", + "4": "reality", + "5": "placement", + "6": "living_room", + "7": "exit_level", + "8": "exit_level_living_room", + "9": "num_modes" + } + } + ] + }, + { + "name": "gaze_direction", + "type": [ + "switch", + { + "compareTo": "play_mode", + "fields": { + "reality": "vec3f" + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + }, + { + "name": "delta", + "type": "vec3f" + } + ] + ], + "packet_creative_content": [ + "container", + [ + { + "name": "items", + "type": "ItemStacks" + } + ] + ], + "packet_player_enchant_options": [ + "container", + [ + { + "name": "enchant_options", + "type": "EnchantOptions" + } + ] + ], + "packet_item_stack_request": [ + "container", + [ + { + "name": "requests", + "type": "ItemStackRequests" + } + ] + ], + "packet_item_stack_response": [ + "container", + [ + { + "name": "responses", + "type": "ItemStackResponses" + } + ] + ], + "packet_player_armor_damage": [ + "container", + [ + { + "name": "type", + "type": "ArmorDamageType" + }, + { + "name": "helmet_damage", + "type": [ + "switch", + { + "compareTo": "type.head", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "chestplate_damage", + "type": [ + "switch", + { + "compareTo": "type.chest", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "leggings_damage", + "type": [ + "switch", + { + "compareTo": "type.legs", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "boots_damage", + "type": [ + "switch", + { + "compareTo": "types.feet", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + }, + { + "name": "player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_position_tracking_db_request": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "query" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + } + ] + ], + "packet_position_tracking_db_broadcast": [ + "container", + [ + { + "name": "broadcast_action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "update", + "1": "destory", + "2": "not_found" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_packet_violation_warning": [ + "container", + [ + { + "name": "violation_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "malformed" + } + } + ] + }, + { + "name": "severity", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "warning", + "1": "final_warning", + "2": "terminating" + } + } + ] + }, + { + "name": "packet_id", + "type": "zigzag32" + }, + { + "name": "reason", + "type": "string" + } + ] + ], + "packet_motion_prediction_hints": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + } + ] + ], + "packet_animate_entity": [ + "container", + [ + { + "name": "animation", + "type": "string" + }, + { + "name": "next_state", + "type": "string" + }, + { + "name": "stop_condition", + "type": "string" + }, + { + "name": "controller", + "type": "string" + }, + { + "name": "blend_out_time", + "type": "lf32" + }, + { + "name": "runtime_entity_ids", + "type": [ + "array", + { + "countType": "varint", + "type": "varint64" + } + ] + } + ] + ], + "packet_camera_shake": [ + "container", + [ + { + "name": "intensity", + "type": "lf32" + }, + { + "name": "duration", + "type": "lf32" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "stop" + } + } + ] + } + ] + ], + "packet_player_fog": [ + "container", + [ + { + "name": "stack", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "packet_correct_player_move_prediction": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_item_component": [ + "container", + [ + { + "name": "entries", + "type": "ItemComponentList" + } + ] + ], + "packet_filter_text_packet": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "from_server", + "type": "bool" + } + ] + ], + "packet_debug_renderer": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "1": "clear", + "2": "add_cube" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "clear": "void", + "add_cube": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "red", + "type": "lf32" + }, + { + "name": "green", + "type": "lf32" + }, + { + "name": "blue", + "type": "lf32" + }, + { + "name": "alpha", + "type": "lf32" + }, + { + "name": "duration", + "type": "li64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "string": [ + "pstring", + { + "countType": "varint" + } + ], + "ByteArray": [ + "buffer", + { + "countType": "varint" + } + ], + "SignedByteArray": [ + "buffer", + { + "countType": "zigzag32" + } + ], + "LittleString": [ + "pstring", + { + "countType": "li32" + } + ], + "MetadataFlags1": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "shift": true, + "flags": { + "onfire": 0, + "sneaking": 1, + "riding": 2, + "sprinting": 3, + "action": 4, + "invisible": 5, + "tempted": 6, + "inlove": 7, + "saddled": 8, + "powered": 9, + "ignited": 10, + "baby": 11, + "converting": 12, + "critical": 13, + "can_show_nametag": 14, + "always_show_nametag": 15, + "no_ai": 16, + "silent": 17, + "wallclimbing": 18, + "can_climb": 19, + "swimmer": 20, + "can_fly": 21, + "walker": 22, + "resting": 23, + "sitting": 24, + "angry": 25, + "interested": 26, + "charged": 27, + "tamed": 28, + "orphaned": 29, + "leashed": 30, + "sheared": 31, + "gliding": 32, + "elder": 33, + "moving": 34, + "breathing": 35, + "chested": 36, + "stackable": 37, + "showbase": 38, + "rearing": 39, + "vibrating": 40, + "idling": 41, + "evoker_spell": 42, + "charge_attack": 43, + "wasd_controlled": 44, + "can_power_jump": 45, + "linger": 46, + "has_collision": 47, + "affected_by_gravity": 48, + "fire_immune": 49, + "dancing": 50, + "enchanted": 51, + "show_trident_rope": 52, + "container_private": 53, + "transforming": 54, + "spin_attack": 55, + "swimming": 56, + "bribed": 57, + "pregnant": 58, + "laying_egg": 59, + "rider_can_pick": 60, + "transition_sitting": 61, + "eating": 62, + "laying_down": 63 + } + } + ], + "MetadataFlags2": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "shift": true, + "flags": { + "sneezing": 64, + "trusting": 65, + "rolling": 66, + "scared": 67, + "in_scaffolding": 68, + "over_scaffolding": 69, + "fall_through_scaffolding": 70, + "blocking": 71, + "transition_blocking": 72, + "blocked_using_shield": 73, + "blocked_using_damaged_shield": 74, + "sleeping": 75, + "wants_to_wake": 76, + "trade_interest": 77, + "door_breaker": 78, + "breaking_obstruction": 79, + "door_opener": 80, + "illager_captain": 81, + "stunned": 82, + "roaring": 83, + "delayed_attacking": 84, + "avoiding_mobs": 85, + "avoiding_block": 86, + "facing_target_to_range_attack": 87, + "hidden_when_invisible": 88, + "is_in_ui": 89, + "stalking": 90, + "emoting": 91, + "celebrating": 92, + "admiring": 93, + "celebrating_special": 94 + } + } + ], + "UpdateBlockFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "neighbors": 1, + "network": 2, + "no_graphic": 4, + "unused": 8, + "priority": 16 + } + } + ], + "AdventureFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "world_immutable": 1, + "no_pvp": 2, + "auto_jump": 32, + "allow_flight": 64, + "no_clip": 128, + "world_builder": 256, + "flying": 512, + "muted": 1024 + } + } + ], + "ActionPermissions": [ + "bitflags", + { + "type": "varint", + "flags": { + "mine": 65537, + "doors_and_switches": 65538, + "open_containers": 65540, + "attack_players": 65544, + "attack_mobs": 65552, + "operator": 65568, + "teleport": 65664, + "build": 65792, + "default": 66048 + } + } + ], + "CommandFlags": [ + "bitfield", + [ + { + "name": "unused", + "size": 6, + "signed": false + }, + { + "name": "has_semantic_constraint", + "size": 1, + "signed": false + }, + { + "name": "collapse_enum", + "size": 1, + "signed": false + } + ] + ], + "DeltaMoveFlags": [ + "bitflags", + { + "type": "lu16", + "flags": { + "has_x": 1, + "has_y": 2, + "has_z": 4, + "has_rot_x": 8, + "has_rot_y": 16, + "has_rot_z": 32, + "on_ground": 64, + "teleport": 128, + "force_move": 256 + } + } + ], + "InputFlag": [ + "bitflags", + { + "type": "varint", + "flags": { + "ascend": 1, + "descend": 2, + "north_jump": 4, + "jump_down": 8, + "sprint_down": 16, + "change_height": 32, + "jumping": 64, + "auto_jumping_in_water": 128, + "sneaking": 256, + "sneak_down": 512, + "up": 1024, + "down": 2048, + "left": 4096, + "right": 8192, + "up_left": 16384, + "up_right": 32768, + "want_up": 65536, + "want_down": 131072, + "want_down_slow": 262144, + "want_up_slow": 524288, + "sprinting": 1048576, + "ascend_scaffolding": 2097152, + "descend_scaffolding": 4194304, + "sneak_toggle_down": 8388608, + "persist_sneak": 16777216, + "start_sprinting": 33554432, + "stop_sprinting": 67108864, + "start_sneaking": 134217728, + "stop_sneaking": 134217728, + "start_swimming": 268435456, + "stop_swimming": 536870912, + "start_jumping": 1073741824, + "start_gliding": 2147483648, + "stop_gliding": 4294967296, + "item_interact": 8589934592, + "block_action": 17179869184, + "item_stack_request": 34359738368 + } + } + ], + "ArmorDamageType": [ + "bitflags", + { + "type": "u8", + "flags": { + "head": 1, + "chest": 2, + "legs": 4, + "feet": 8 + } + } + ] + } +} \ No newline at end of file diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 6253c5a..74e75a5 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -1,7 +1,7 @@ # Created from MiNET and gophertunnel docs # The version below is the latest version this protocol schema was updated for. # The output protocol.json will be in the folder for the version -!version: 1.16.201 +!version: 1.16.210 # Some ProtoDef aliases string: ["pstring",{"countType":"varint"}] @@ -217,7 +217,7 @@ packet_start_game: player_gamemode: GameMode # The spawn position of the player in the world. In servers this is often the same as the # world's spawn position found below. - spawn: vec3f + player_position: vec3f # The pitch and yaw of the player rotation: vec2f # The seed used to generate the world. Unlike in Java edition, the seed is a 32bit Integer here. @@ -334,6 +334,13 @@ packet_start_game: # Specifies if the world was a trial world, meaning features are limited and there # is a time limit on the world. is_trial: bool + + # MovementType specifies the way the server handles player movement. Available options are + # packet.AuthoritativeMovementModeClient, packet.AuthoritativeMovementModeServer and + # packet.AuthoritativeMovementModeServerWithRewind, where server the server authoritative types result + # in the client sending PlayerAuthInput packets instead of MovePlayer packets and the rewind mode + # requires sending the tick of movement and several actions. + # # Specifies if the client or server is authoritative over the movement of the player, # meaning it controls the movement of it. ## https://github.com/pmmp/PocketMine-MP/blob/a43b46a93cb127f037c879b5d8c29cda251dd60c/src/pocketmine/network/mcpe/protocol/types/PlayerMovementType.php#L26 @@ -341,7 +348,16 @@ packet_start_game: 0: client 1: server # PlayerAuthInputPacket + a bunch of junk that solves a nonexisting problem - 2: server_v2_rewind + 2: server_with_rewind + # RewindHistorySize is the amount of history to keep at maximum if MovementType is + # packet.AuthoritativeMovementModeServerWithRewind. + rewind_history_size: zigzag32 + # ServerAuthoritativeBlockBreaking specifies if block breaking should be sent through + # packet.PlayerAuthInput or not. This field is somewhat redundant as it is always enabled if + # MovementType is packet.AuthoritativeMovementModeServer or + # packet.AuthoritativeMovementModeServerWithRewind + server_authoritative_block_breaking: bool + # The total time in ticks that has elapsed since the start of the world. current_tick: li64 # The seed used to seed the random used to produce enchantments in the enchantment table. @@ -508,13 +524,36 @@ packet_rider_jump: !bound: both jump_strength: zigzag32 +# UpdateBlock is sent by the server to update a block client-side, without resending the entire chunk that +# the block is located in. It is particularly useful for small modifications like block breaking/placing. packet_update_block: !id: 0x15 !bound: client - coordinates: BlockCoordinates + # Position is the block position at which a block is updated. + position: BlockCoordinates + # NewBlockRuntimeID is the runtime ID of the block that is placed at Position after sending the packet + # to the client. block_runtime_id: varint - block_priority: varint - storage: varint + # Flags is a combination of flags that specify the way the block is updated client-side. It is a + # combination of the flags above, but typically sending only the BlockUpdateNetwork flag is sufficient. + flags: UpdateBlockFlags + # Layer is the world layer on which the block is updated. For most blocks, this is the first layer, as + # that layer is the default layer to place blocks on, but for blocks inside of each other, this differs. + layer: varint + + +UpdateBlockFlags: [ "bitflags", + { + "type": "varint", + "flags": { + "neighbors": 1, + "network": 2, + "no_graphic": 0b100, + "unused": 0b1000, + "priority": 0b10000, + } + } +] packet_add_painting: !id: 0x16 @@ -802,7 +841,7 @@ packet_player_action: 15: start_glide 16: stop_glide 17: build_denied - 18: continue_break + 18: crack_break 19: change_skin # no longer used 20: set_enchatnment_seed @@ -811,6 +850,8 @@ packet_player_action: 23: start_spin_attack 24: stop_spin_attack 25: ineract_block + 26: predict_break + 27: continue_break # BlockPosition is the position of the target block, if the action with the ActionType set concerned a # block. If that is not the case, the block position will be zero. position: BlockCoordinates @@ -1054,13 +1095,15 @@ ActionPermissions: [ "bitflags", { "type": "varint", "flags": { - "build_and_mine": 0x10001, + "mine": 0x10001, "doors_and_switches": 0x10002, "open_containers": 0x10004, "attack_players": 0x10008, "attack_mobs": 0x10010, "operator": 0x10020, "teleport": 0x10080, + "build": 0x10100, + "default": 0x10200 } } ] @@ -1171,7 +1214,14 @@ packet_event: 14: pet_died 15: cauldron_block_used 16: composter_block_used - 17: bell_block_used + 17: bell_block_used + 18: actor_definition + 19: raid_update + 20: player_movement_anomaly + 21: player_moement_corrected + 22: honey_harvested + 23: target_block_hit + 24: piglin_barter use_player_id: u8 event_data: restBuffer # Unknown data, TODO: add @@ -1317,13 +1367,13 @@ packet_available_commands: 4: wildcard_int 5: operator 6: target - 14: file_path - 29: string - 37: position - 41: message - 43: raw_text - 46: json - 53: command + 16: file_path + 32: string + 40: position + 44: message + 46: raw_text + 50: json + 63: command # In MC, this + prior field are combined to one 32bit bitfield enum_type: lu16 => 0x10: valid @@ -1388,9 +1438,12 @@ packet_command_output: # command request was from, such as the player itself or a websocket server. The client forwards the # messages in this packet to the right origin, depending on what is sent here. origin: CommandOrigin - # OutputType specifies the type of output that is sent. The OutputType sent by vanilla games appears to - # be 3, which seems to work. - output_type: i8 + # OutputType specifies the type of output that is sent. + output_type: i8 => + 1: last + 2: silent + 3: all + 4: data_set # SuccessCount is the amount of times that a command was executed successfully as a result of the command # that was requested. For servers, this is usually a rather meaningless fields, but for vanilla, this is # applicable for commands created with Functions. @@ -1410,6 +1463,9 @@ packet_command_output: # such as the position that a player was teleported to or the effect that was applied to an entity. # These parameters only apply for the Minecraft built-in command output. paramaters: string[]varint + data_set: output_type ? + if data_set: string + default: void # UpdateTrade is sent by the server to update the trades offered by a villager to a player. It is sent at the @@ -1516,13 +1572,34 @@ packet_stop_sound: name: string stop_all: bool +# SetTitle is sent by the server to make a title, subtitle or action bar shown to a player. It has several +# fields that allow setting the duration of the titles. packet_set_title: !id: 0x58 !bound: client - type: zigzag32 + # ActionType is the type of the action that should be executed upon the title of a player. It is one of + # the constants above and specifies the response of the client to the packet. + type: zigzag32 => + 0: clear + 1: reset + 2: set_title + 3: set_subtitle + 4: action_bar_message + 5: set_durations + 6: set_title_json + 7: set_subtitle_json + 8: action_bar_message_json + # Text is the text of the title, which has a different meaning depending on the ActionType that the + # packet has. The text is the text of a title, subtitle or action bar, depending on the type set. text: string + # FadeInDuration is the duration that the title takes to fade in on the screen of the player. It is + # measured in 20ths of a second (AKA in ticks). fade_in_time: zigzag32 + # RemainDuration is the duration that the title remains on the screen of the player. It is measured in + # 20ths of a second (AKA in ticks). stay_time: zigzag32 + # FadeOutDuration is the duration that the title takes to fade out of the screen of the player. It is + # measured in 20ths of a second (AKA in ticks). fade_out_time: zigzag32 packet_add_behavior_tree: @@ -1673,15 +1750,38 @@ packet_lab_table: lab_table_z: varint reaction_type: u8 +# UpdateBlockSynced is sent by the server to synchronise the falling of a falling block entity with the +# transitioning back and forth from and to a solid block. It is used to prevent the entity from flickering, +# and is used in places such as the pushing of blocks with pistons. packet_update_block_synced: !id: 0x6e !bound: client - coordinates: BlockCoordinates + # Position is the block position at which a block is updated. + position: BlockCoordinates + # NewBlockRuntimeID is the runtime ID of the block that is placed at Position after sending the packet + # to the client. block_runtime_id: varint - block_priority: varint - data_layer_id: varint - unknown0: varint - unknown1: varint + # Flags is a combination of flags that specify the way the block is updated client-side. It is a + # combination of the flags above, but typically sending only the BlockUpdateNetwork flag is sufficient. + flags: UpdateBlockFlags + # Layer is the world layer on which the block is updated. For most blocks, this is the first layer, as + # that layer is the default layer to place blocks on, but for blocks inside of each other, this differs. + layer: varint + # EntityUniqueID is the unique ID of the falling block entity that the block transitions to or that the + # entity transitions from. + # Note that for both possible values for TransitionType, the EntityUniqueID should point to the falling + # block entity involved. + entity_unique_id: varint + # TransitionType is the type of the transition that happened. It is either BlockToEntityTransition, when + # a block placed becomes a falling entity, or EntityToBlockTransition, when a falling entity hits the + # ground and becomes a solid block again. + transition_type: varint => + # For falling sand, when a sand turns to an entity + 0: entity + # When sand turns back to a new block + 1: create + 2: destroy + # MoveActorDelta is sent by the server to move an entity. The packet is specifically optimised to save as # much space as possible, by only writing non-zero fields. @@ -2055,34 +2155,47 @@ packet_player_auth_input: # as it can be calculated by the server itself. delta: vec3f + InputFlag: [ "bitflags", { "type": "varint", "flags": { - "ascend": 0b1, - "descend": 0b10, - "north_jump": 0b100, - "jump_down": 0b1000, - "sprint_down": 0b10000, - "change_height": 0b100000, - "jumping": 0b1000000, + "ascend": 0b1, + "descend": 0b10, + "north_jump": 0b100, + "jump_down": 0b1000, + "sprint_down": 0b10000, + "change_height": 0b100000, + "jumping": 0b1000000, "auto_jumping_in_water": 0b10000000, - "sneaking": 0b100000000, - "sneak_down": 0b1000000000, - "up": 0b10000000000, - "down": 0b100000000000, - "left": 0b1000000000000, - "right": 0b10000000000000, - "up_left": 0b100000000000000, - "up_right": 0b1000000000000000, - "want_up": 0b10000000000000000, - "want_down": 0b100000000000000000, - "want_down_slow": 0b1000000000000000000, - "want_up_slow": 0b10000000000000000000, - "sprinting": 0b100000000000000000000, + "sneaking": 0b100000000, + "sneak_down": 0b1000000000, + "up": 0b10000000000, + "down": 0b100000000000, + "left": 0b1000000000000, + "right": 0b10000000000000, + "up_left": 0b100000000000000, + "up_right": 0b1000000000000000, + "want_up": 0b10000000000000000, + "want_down": 0b100000000000000000, + "want_down_slow": 0b1000000000000000000, + "want_up_slow": 0b10000000000000000000, + "sprinting": 0b100000000000000000000, "ascend_scaffolding": 0b1000000000000000000000, "descend_scaffolding": 0b10000000000000000000000, - "sneak_toggle_down": 0b100000000000000000000000, - "persist_sneak": 0b1000000000000000000000000, + "sneak_toggle_down": 0b100000000000000000000000, + "persist_sneak": 0b1000000000000000000000000, + "start_sprinting": 0b10000000000000000000000000, + "stop_sprinting": 0b100000000000000000000000000, + "start_sneaking": 0b1000000000000000000000000000, + "stop_sneaking": 0b1000000000000000000000000000, + "start_swimming": 0b10000000000000000000000000000, + "stop_swimming": 0b100000000000000000000000000000, + "start_jumping": 0b1000000000000000000000000000000, + "start_gliding": 0b10000000000000000000000000000000, + "stop_gliding": 0b100000000000000000000000000000000, + "item_interact": 0b1000000000000000000000000000000000, + "block_action": 0b10000000000000000000000000000000000, + "item_stack_request": 0b100000000000000000000000000000000000 } }] @@ -2262,6 +2375,11 @@ packet_camera_shake: # Type is the type of shake, and is one of the constants listed above. The different type affects how # the shake looks in game. type: u8 + # Action is the action to be performed, and is one of the constants listed above. Currently the + # different actions will either add or stop shaking the client. + action: u8 => + 0: add + 1: stop # PlayerFog is sent by the server to render the different fogs in the Stack. The types of fog are controlled # by resource packs to change how they are rendered, and the ability to create custom fog. @@ -2308,3 +2426,28 @@ packet_filter_text_packet: # FromServer indicates if the packet was sent by the server or not. from_server: bool +# ClientBoundDebugRenderer is sent by the server to spawn an outlined cube on client-side. +packet_debug_renderer: + !id: 0xa4 + !bound: client + # Type is the type of action. It is one of the constants above. + type: li32 => + 1: clear + 2: add_cube + _: type ? + if clear: void + if add_cube: + # Text is the text that is displayed above the debug. + text: string + # Position is the position to spawn the debug on. + position: vec3f + # Red is the red value from the RGBA colour rendered on the debug. + red: lf32 + # Green is the green value from the RGBA colour rendered on the debug. + green: lf32 + # Blue is the blue value from the RGBA colour rendered on the debug. + blue: lf32 + # Alpha is the alpha value from the RGBA colour rendered on the debug. + alpha: lf32 + # Duration is how long the debug will last in the world for. It is measured in milliseconds. + duration: li64 \ No newline at end of file diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 6a8cecc..b7c08e1 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -117,7 +117,7 @@ vec2f: MetadataDictionary: []varint # https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/entity/Entity.php#L101 key: varint => - 0: index + 0: flags 1: health #int (minecart/boat) 2: variant #int 3: color #byte @@ -175,66 +175,68 @@ MetadataDictionary: []varint 57: rider_rotation_locked #byte 58: rider_max_rotation #float 59: rider_min_rotation #float - 60: area_effect_cloud_radius #float - 61: area_effect_cloud_waiting #int - 62: area_effect_cloud_particle_id #int - 63: shulker_peek_id #int - 64: shulker_attach_face #byte - 65: shulker_attached #short - 66: shulker_attach_pos - 67: trading_player_eid #long - 68: trading_career - 69: has_command_block - 70: command_block_command #string - 71: command_block_last_output #string - 72: command_block_track_output #byte - 73: controlling_rider_seat_number #byte - 74: strength #int - 75: max_strength #int - 76: spell_casting_color #int - 77: limited_life - 78: armor_stand_pose_index # int - 79: ender_crystal_time_offset # int - 80: always_show_nametag # byte - 81: color_2 # byte - 82: name_author - 83: score_tag #String - 84: balloon_attached_entity # long - 85: pufferfish_size - 86: bubble_time - 87: agent - 88: sitting_amount - 89: sitting_amount_previous - 90: eating_counter - 91: flags_extended - 92: laying_amount - 93: laying_amount_previous - 94: duration - 95: spawn_time - 96: change_rate - 97: change_on_pickup - 98: pickup_count - 99: interact_text - 100: trade_tier - 101: max_trade_tier - 102: trade_experience - 103: skin_id - 104: spawning_frames - 105: command_block_tick_delay - 106: command_block_execute_on_first_tick - 107: ambient_sound_interval - 108: ambient_sound_interval_range - 109: ambient_sound_event_name - 110: fall_damage_multiplier - 111: name_raw_text - 112: can_ride_target - 113: low_tier_cured_discount - 114: high_tier_cured_discount - 115: nearby_cured_discount - 116: nearby_cured_discount_timestamp - 117: hitbox - 118: is_buoyant - 119: buoyancy_data + 60: rider_rotation_offset + 61: area_effect_cloud_radius #float + 62: area_effect_cloud_waiting #int + 63: area_effect_cloud_particle_id #int + 64: shulker_peek_id #int + 65: shulker_attach_face #byte + 66: shulker_attached #short + 67: shulker_attach_pos + 68: trading_player_eid #long + 69: trading_career + 70: has_command_block + 71: command_block_command #string + 72: command_block_last_output #string + 73: command_block_track_output #byte + 74: controlling_rider_seat_number #byte + 75: strength #int + 76: max_strength #int + 77: spell_casting_color #int + 78: limited_life + 79: armor_stand_pose_index # int + 80: ender_crystal_time_offset # int + 81: always_show_nametag # byte + 82: color_2 # byte + 83: name_author + 84: score_tag #String + 85: balloon_attached_entity # long + 86: pufferfish_size + 87: bubble_time + 88: agent + 89: sitting_amount + 90: sitting_amount_previous + 91: eating_counter + 92: flags_extended + 93: laying_amount + 94: laying_amount_previous + 95: duration + 96: spawn_time + 97: change_rate + 98: change_on_pickup + 99: pickup_count + 100: interact_text + 101: trade_tier + 102: max_trade_tier + 103: trade_experience + 104: skin_id + 105: spawning_frames + 106: command_block_tick_delay + 107: command_block_execute_on_first_tick + 108: ambient_sound_interval + 109: ambient_sound_interval_range + 110: ambient_sound_event_name + 111: fall_damage_multiplier + 112: name_raw_text + 113: can_ride_target + 114: low_tier_cured_discount + 115: high_tier_cured_discount + 116: nearby_cured_discount + 117: nearby_cured_discount_timestamp + 118: hitbox + 119: is_buoyant + 120: buoyancy_data + 121: goat_horn_count type: varint => 0: byte 1: short @@ -245,16 +247,126 @@ MetadataDictionary: []varint 6: vec3i 7: long 8: vec3f - value: type? - if byte: i8 - if short: li16 - if int: zigzag32 - if float: lf32 - if string: string - if compound: nbt - if vec3i: vec3i - if long: zigzag64 - if vec3f: vec3f + value: key ? + if flags: MetadataFlags1 + if flags_extended: MetadataFlags2 + default: type ? + if byte: i8 + if short: li16 + if int: zigzag32 + if float: lf32 + if string: string + if compound: nbt + if vec3i: vec3i + if long: zigzag64 + if vec3f: vec3f + +MetadataFlags1: [ "bitflags", { + "type": "zigzag64", "big": true, "shift": true, + "flags": { + "onfire": 0, + "sneaking": 1, + "riding": 2, + "sprinting": 3, + "action": 4, + "invisible": 5, + "tempted": 6, + "inlove": 7, + "saddled": 8, + "powered": 9, + "ignited": 10, + "baby": 11, + "converting": 12, + "critical": 13, + "can_show_nametag": 14, + "always_show_nametag": 15, + "no_ai": 16, + "silent": 17, + "wallclimbing": 18, + "can_climb": 19, + "swimmer": 20, + "can_fly": 21, + "walker": 22, + "resting": 23, + "sitting": 24, + "angry": 25, + "interested": 26, + "charged": 27, + "tamed": 28, + "orphaned": 29, + "leashed": 30, + "sheared": 31, + "gliding": 32, + "elder": 33, + "moving": 34, + "breathing": 35, + "chested": 36, + "stackable": 37, + "showbase": 38, + "rearing": 39, + "vibrating": 40, + "idling": 41, + "evoker_spell": 42, + "charge_attack": 43, + "wasd_controlled": 44, + "can_power_jump": 45, + "linger": 46, + "has_collision": 47, + "affected_by_gravity": 48, + "fire_immune": 49, + "dancing": 50, + "enchanted": 51, + "show_trident_rope": 52, # tridents show an animated rope when enchanted with loyalty after they are thrown and return to their owner. to be combined with data_owner_eid + "container_private": 53, #inventory is private, doesn't drop contents when killed if true + "transforming": 54, + "spin_attack": 55, + "swimming": 56, + "bribed": 57, #dolphins have this set when they go to find treasure for the player + "pregnant": 58, + "laying_egg": 59, + "rider_can_pick": 60, #??? + "transition_sitting": 61, + "eating": 62, + "laying_down": 63, + } +}] + +MetadataFlags2: [ "bitflags", { + "type": "zigzag64","big": true, "shift": true, + "flags": { + "sneezing": 64, + "trusting": 65, + "rolling": 66, + "scared": 67, + "in_scaffolding": 68, + "over_scaffolding": 69, + "fall_through_scaffolding": 70, + "blocking": 71, #shield + "transition_blocking": 72, + "blocked_using_shield": 73, + "blocked_using_damaged_shield": 74, + "sleeping": 75, + "wants_to_wake": 76, + "trade_interest": 77, + "door_breaker": 78, #... + "breaking_obstruction": 79, + "door_opener": 80, #... + "illager_captain": 81, + "stunned": 82, + "roaring": 83, + "delayed_attacking": 84, + "avoiding_mobs": 85, + "avoiding_block": 86, + "facing_target_to_range_attack": 87, + "hidden_when_invisible": 88, #?????????????????? + "is_in_ui": 89, + "stalking": 90, + "emoting": 91, + "celebrating": 92, + "admiring": 93, + "celebrating_special": 94, + } +}] Link: ridden_entity_id: zigzag64 @@ -632,29 +744,31 @@ ItemStackRequests: []varint # BeaconPaymentStackRequestAction is sent by the client when it submits an item to enable effects from a # beacon. These items will have been moved into the beacon item slot in advance. 8: beacon_payment + # MineBlockStackRequestAction is sent by the client when it breaks a block. + 9: mine_block # CraftRecipeStackRequestAction is sent by the client the moment it begins crafting an item. This is the # first action sent, before the Consume and Create item stack request actions. # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as # crafting, where the old item is consumed. - 9: craft_recipe + 10: craft_recipe # AutoCraftRecipeStackRequestAction is sent by the client similarly to the CraftRecipeStackRequestAction. The # only difference is that the recipe is automatically created and crafted by shift clicking the recipe book. - 10: craft_recipe_auto #recipe book? + 11: craft_recipe_auto #recipe book? # CraftCreativeStackRequestAction is sent by the client when it takes an item out fo the creative inventory. # The item is thus not really crafted, but instantly created. - 11: craft_creative + 12: craft_creative # CraftRecipeOptionalStackRequestAction is sent when using an anvil. When this action is sent, the # CustomNames field in the respective stack request is non-empty and contains the name of the item created # using the anvil. - 12: optional + 13: optional # CraftNonImplementedStackRequestAction is an action sent for inventory actions that aren't yet implemented # in the new system. These include, for example, anvils. - 13: non_implemented #anvils aren't fully implemented yet + 14: non_implemented #anvils aren't fully implemented yet # CraftResultsDeprecatedStackRequestAction is an additional, deprecated packet sent by the client after # crafting. It holds the final results and the amount of times the recipe was crafted. It shouldn't be used. # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as # crafting, where the old item is consumed. - 14: results_deprecated + 15: results_deprecated _: type_id ? if take or place: count: u8 @@ -687,6 +801,15 @@ ItemStackRequests: []varint # PrimaryEffect and SecondaryEffect are the effects that were selected from the beacon. primary_effect: zigzag32 secondary_effect: zigzag32 + if mine_block: + # // Unknown1 ... TODO: Find out what this is for + unknown1: zigzag32 + # PredictedDurability is the durability of the item that the client assumes to be present at the time + predicted_durability: zigzag32 + # StackNetworkID is the unique stack ID that the client assumes to be present at the time. The server + # must check if these IDs match. If they do not match, servers should reject the stack request that the + # action holding this info was in. + network_id: zigzag32 if craft_recipe or craft_recipe_auto: # RecipeNetworkID is the network ID of the recipe that is about to be crafted. This network ID matches # one of the recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as @@ -710,17 +833,43 @@ ItemStackRequests: []varint # * Used for the server to determine which strings should be filtered. Used in anvils to verify a renamed item. custom_names: string[]varint +# ItemStackResponse is a response to an individual ItemStackRequest. ItemStackResponses: []varint - result: u8 + # Status specifies if the request with the RequestID below was successful. If this is the case, the + # ContainerInfo below will have information on what slots ended up changing. If not, the container info + # will be empty. + # A non-0 status means an error occurred and will result in the action being reverted. + status: u8 => + 0: ok + 1: error + # RequestID is the unique ID of the request that this response is in reaction to. If rejected, the client + # will undo the actions from the request with this ID. request_id: varint32 + # ContainerInfo holds information on the containers that had their contents changed as a result of the + # request. containers: []varint - container_id: u8 + # ContainerID is the container ID of the container that the slots that follow are in. For the main + # inventory, this value seems to be 0x1b. For the cursor, this value seems to be 0x3a. For the crafting + # grid, this value seems to be 0x0d. + # * actually, this is ContainerSlotType - used by the inventory system that specifies the type of slot + slot_type: ContainerSlotType + # SlotInfo holds information on what item stack should be present in specific slots in the container. slots: []varint + # Slot and HotbarSlot seem to be the same value every time: The slot that was actually changed. I'm not + # sure if these slots ever differ. slot: u8 hotbar_slot: u8 + # Count is the total count of the item stack. This count will be shown client-side after the response is + # sent to the client. count: u8 + # StackNetworkID is the network ID of the new stack at a specific slot. item_stack_id: varint32 + # CustomName is the custom name of the item stack. It is used in relation to text filtering. custom_name: string + # DurabilityCorrection is the current durability of the item stack. This durability will be shown + # client-side after the response is sent to the client. + durability_correction: zigzag32 + ItemComponentList: []varint # Name is the name of the item, which is a name like 'minecraft:stick'. @@ -827,6 +976,68 @@ WindowType: u8 => 32: jigsaw_editor 33: smithing_table +ContainerSlotType: u8 => + - anvil_input + - anvil_material + - anvil_result + - smithing_table_input + - smithing_table_material + - smithing_table_result + - armor + - container + - beacon_payment + - brewing_input + - brewing_result + - brewing_fuel + - hotbar_and_inventory + - crafting_input + - crafting_output + - recipe_construction + - recipe_nature + - recipe_items + - recipe_search + - recipe_search_bar + - recipe_equipment + - enchanting_input + - enchanting_lapis + - furnace_fuel + - furnace_ingredient + - furnace_output + - horse_equip + - hotbar + - inventory + - shulker + - trade_ingredient1 + - trade_ingredient2 + - trade_result + - offhand + - compcreate_input + - compcreate_output + - elemconstruct_output + - matreduce_input + - matreduce_output + - labtable_input + - loom_input + - loom_dye + - loom_material + - loom_result + - blast_furnace_ingredient + - smoker_ingredient + - trade2_ingredient1 + - trade2_ingredient2 + - trade2_result + - grindstone_input + - grindstone_additional + - grindstone_result + - stonecutter_input + - stonecutter_result + - cartography_input + - cartography_additional + - cartography_result + - barrel + - cursor + - creative_output + # TODO: remove? LegacyEntityType: li32 => 10: chicken diff --git a/package.json b/package.json index d7e514d..2971a3f 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "babel-eslint": "^10.1.0", "buffer-equal": "^1.0.0", "mocha": "^8.3.2", - "protodef-yaml": "^1.0.1", + "protodef-yaml": "^1.0.2", "standard": "^16.0.3" }, "standard": { diff --git a/src/auth/login.js b/src/auth/login.js index 5d3ad49..55c7ef9 100644 --- a/src/auth/login.js +++ b/src/auth/login.js @@ -59,6 +59,10 @@ module.exports = (client, server, options) => { PieceTintColors: [], PlatformOfflineId: '', PlatformOnlineId: '', // chat + // PlayFabID is the PlayFab ID produced for the skin. PlayFab is the company that hosts the Marketplace, + // skins and other related features from the game. This ID is the ID of the skin used to store the skin + // inside of PlayFab. + PlayFabId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', // 1.16.210 PremiumSkin: false, SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343701', ServerAddress: `${options.hostname}:${options.port}`, diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index b5fda57..91c8b0b 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -80,34 +80,58 @@ SizeOf.nbt = ['native', minecraft.nbt[2]] * Bits */ -Read.bitflags = ['parametrizable', (compiler, { type, flags }) => { +Read.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { + if (shift) { + let i = 0 + for (const key in flags) { + const val = flags[key] + flags[key] = val << i++ + } + } return compiler.wrapCode(` const { value: _value, size } = ${compiler.callType(type, 'offset')} const value = { _value } const flags = ${JSON.stringify(flags)} for (const key in flags) { - value[key] = (_value & flags[key]) == flags[key] + const v = ${big ? `BigInt(flags[key])` : 'flags[key]'} + value[key] = (_value & v) == v } return { value, size } `.trim()) }] -Write.bitflags = ['parametrizable', (compiler, { type, flags }) => { +Write.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { + if (shift) { + let i = 0 + for (const key in flags) { + const val = flags[key] + flags[key] = val << i++ + } + } return compiler.wrapCode(` const flags = ${JSON.stringify(flags)} let val = value._value for (const key in flags) { - if (value[key]) val |= flags[key] + const v = ${big ? `BigInt(flags[key])` : 'flags[key]'} + if (value[key]) val |= v } return (ctx.${type})(val, buffer, offset) `.trim()) }] -SizeOf.bitflags = ['parametrizable', (compiler, { type, flags }) => { +SizeOf.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { + if (shift) { + let i = 0 + for (const key in flags) { + const val = flags[key] + flags[key] = val << i++ + } + } return compiler.wrapCode(` const flags = ${JSON.stringify(flags)} let val = value._value for (const key in flags) { + const v = ${big ? `BigInt(flags[key])` : 'flags[key]'} if (value[key]) val |= flags[key] } return (ctx.${type})(val) diff --git a/src/options.js b/src/options.js index cc068e6..4e35042 100644 --- a/src/options.js +++ b/src/options.js @@ -1,7 +1,7 @@ // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson -const CURRENT_VERSION = '1.16.201' +const CURRENT_VERSION = '1.16.210' const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 @@ -15,8 +15,7 @@ const defaultOptions = { } const Versions = { - // TODO - // '1.16.210': 428, + '1.16.210': 428, '1.16.201': 422 } diff --git a/test/vanilla.js b/test/vanilla.js index 1a747ab..658ae78 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -3,9 +3,9 @@ const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') const { waitFor } = require('../src/datatypes/util') -async function test () { +async function test (version) { // Start the server, wait for it to accept clients, throws on timeout - const handle = await vanillaServer.startServerAndWait('1.16.201', 1000 * 120) + const handle = await vanillaServer.startServerAndWait(version, 1000 * 120) console.log('Started server') const client = new Client({ diff --git a/test/vanilla.test.js b/test/vanilla.test.js index 36369bd..32a656a 100644 --- a/test/vanilla.test.js +++ b/test/vanilla.test.js @@ -1,10 +1,13 @@ /* eslint-env jest */ const { clientTest } = require('./vanilla') +const { Versions } = require('../src/options') describe('vanilla server test', function () { this.timeout(120 * 1000) it('client spawns', async () => { - await clientTest() + for (const version in Versions) { + await clientTest(version) + } }) }) \ No newline at end of file From 514a84fd19a6e9f89abed284b7b9a6be9227ecf7 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 21 Mar 2021 16:03:24 -0400 Subject: [PATCH 128/458] 1.16.210 fix --- data/latest/proto.yml | 2 +- data/latest/types.yaml | 1 + src/options.js | 10 +++++----- test/vanilla.js | 1 + test/vanilla.test.js | 13 +++++++------ 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 74e75a5..bc026ba 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -2155,7 +2155,7 @@ packet_player_auth_input: # as it can be calculated by the server itself. delta: vec3f - +#TODO: update to use the new `shift` option in bitflags InputFlag: [ "bitflags", { "type": "varint", "flags": { diff --git a/data/latest/types.yaml b/data/latest/types.yaml index b7c08e1..c99030e 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -607,6 +607,7 @@ SkinImage: Skin: skin_id: string + play_fab_id: string skin_resource_pack: string skin_data: SkinImage animations: []li32 diff --git a/src/options.js b/src/options.js index 4e35042..6e64d09 100644 --- a/src/options.js +++ b/src/options.js @@ -3,6 +3,11 @@ const MIN_VERSION = '1.16.201' // Currently supported verson const CURRENT_VERSION = '1.16.210' +const Versions = { + '1.16.210': 428, + '1.16.201': 422 +} + const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 version: CURRENT_VERSION, @@ -14,9 +19,4 @@ const defaultOptions = { offline: false } -const Versions = { - '1.16.210': 428, - '1.16.201': 422 -} - module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } diff --git a/test/vanilla.js b/test/vanilla.js index 658ae78..1088396 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -12,6 +12,7 @@ async function test (version) { hostname: '127.0.0.1', port: 19130, username: 'Notch', + version, offline: true }) diff --git a/test/vanilla.test.js b/test/vanilla.test.js index 32a656a..d820a5b 100644 --- a/test/vanilla.test.js +++ b/test/vanilla.test.js @@ -3,11 +3,12 @@ const { clientTest } = require('./vanilla') const { Versions } = require('../src/options') -describe('vanilla server test', function () { +describe ('vanilla server test', function () { this.timeout(120 * 1000) - it('client spawns', async () => { - for (const version in Versions) { - await clientTest(version) - } - }) + + for (const version in Versions) { + it('client spawns ' + version, async () => { + await clientTest(version) + }) + } }) \ No newline at end of file From 597453100f23bff9e905a28f359918449ee4c541 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 21 Mar 2021 16:09:30 -0400 Subject: [PATCH 129/458] serializer: absolute path imports --- data/1.16.210/protocol.json | 4 ++++ src/transforms/serializer.js | 13 +++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 2121295..251b0c0 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -1542,6 +1542,10 @@ "name": "skin_id", "type": "string" }, + { + "name": "play_fab_id", + "type": "string" + }, { "name": "skin_resource_pack", "type": "string" diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index bbaac1a..d31b0dc 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,12 +1,13 @@ const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler const { FullPacketParser, Serializer } = require('protodef') +const { join } = require('path') // Compiles the ProtoDef schema at runtime function createProtocol (version) { - const protocol = require(`../../data/${version}/protocol.json`).types + const protocol = require(join(__dirname, `../../data/${version}/protocol.json`)).types const compiler = new ProtoDefCompiler() compiler.addTypesToCompile(protocol) - compiler.addTypes(require('../datatypes/compiler-minecraft')) + compiler.addTypes(require(join(__dirname, '../datatypes/compiler-minecraft'))) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) const compiledProto = compiler.compileProtoDefSync() @@ -16,7 +17,7 @@ function createProtocol (version) { // Loads already generated read/write/sizeof code function getProtocol (version) { const compiler = new ProtoDefCompiler() - compiler.addTypes(require('../datatypes/compiler-minecraft')) + compiler.addTypes(require(join(__dirname, '../datatypes/compiler-minecraft'))) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) const compile = (compiler, file) => { @@ -26,9 +27,9 @@ function getProtocol (version) { } return new CompiledProtodef( - compile(compiler.sizeOfCompiler, `../../data/${version}/size.js`), - compile(compiler.writeCompiler, `../../data/${version}/write.js`), - compile(compiler.readCompiler, `../../data/${version}/read.js`) + compile(compiler.sizeOfCompiler, join(__dirname, `../../data/${version}/size.js`)), + compile(compiler.writeCompiler, join(__dirname, `../../data/${version}/write.js`)), + compile(compiler.readCompiler, join(__dirname, `../../data/${version}/read.js`)) ) } From b569cb63533a03a2ab4a1a31e9e362815072bd15 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 21 Mar 2021 19:34:51 -0400 Subject: [PATCH 130/458] update build script --- tools/compileProtocol.js | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index d787cb9..fabb0db 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -7,6 +7,7 @@ */ const fs = require('fs') const { ProtoDefCompiler } = require('protodef').Compiler +const { Versions } = require('../src/options') const { join } = require('path') function getJSON (path) { @@ -47,31 +48,43 @@ function genProtoSchema () { } // Compile the ProtoDef JSON into JS -function createProtocol (version) { +function createProtocol () { const compiler = new ProtoDefCompiler() - const protocol = getJSON(`../${version}/protocol.json`).types + const protocol = getJSON('./protocol.json').types compiler.addTypes(require('../src/datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) compiler.addTypesToCompile(protocol) - fs.writeFileSync(`../${version}/read.js`, 'module.exports = ' + compiler.readCompiler.generate()) - fs.writeFileSync(`../${version}/write.js`, 'module.exports = ' + compiler.writeCompiler.generate()) - fs.writeFileSync(`../${version}/size.js`, 'module.exports = ' + compiler.sizeOfCompiler.generate()) + fs.writeFileSync('./read.js', 'module.exports = ' + compiler.readCompiler.generate()) + fs.writeFileSync('./write.js', 'module.exports = ' + compiler.writeCompiler.generate()) + fs.writeFileSync('./size.js', 'module.exports = ' + compiler.sizeOfCompiler.generate()) const compiledProto = compiler.compileProtoDefSync() return compiledProto } -function main (ver = 'latest') { - process.chdir(join(__dirname, '/../data/', ver)) +function copyLatest () { + process.chdir(join(__dirname, '/../data/latest')) const version = genProtoSchema() - fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: getJSON('./proto.json') }, null, 2)) fs.unlinkSync('./proto.json') // remove temp file fs.unlinkSync('./packet_map.yml') // remove temp file - - console.log('Generating JS...') - createProtocol(version) + return version } -main() +function main (ver = 'latest') { + if (ver === 'latest') ver = copyLatest() + process.chdir(join(__dirname, '/../data/', ver)) + console.log('Generating JS...', ver) + createProtocol(ver) +} + +// If no argument, build everything +if (!process.argv[2]) { + copyLatest() + for (const version in Versions) { + main(version) + } +} else { // build the specified version + main(process.argv[2]) +} From 6803d742e6d7557e76dc53e48a4a8808c1a2bbdf Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 22 Mar 2021 04:21:06 -0400 Subject: [PATCH 131/458] player input, transaction, bitflag updates --- data/1.16.210/protocol.json | 1253 +++++++++++++++------------ data/latest/proto.yml | 149 ++-- data/latest/types.yaml | 377 ++++---- src/datatypes/compiler-minecraft.js | 62 +- 4 files changed, 1033 insertions(+), 808 deletions(-) diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 251b0c0..9aa256f 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -744,80 +744,62 @@ ] } ], - "Transaction": [ + "TransactionUseItem": [ "container", [ { - "name": "legacy_request_id", - "type": "zigzag32" - }, - { - "name": "legacy_transactions", - "type": [ - "switch", - { - "compareTo": "legacy_request_id", - "fields": { - "0": "void" - }, - "default": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "changed_slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_id", - "type": "u8" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - }, - { - "name": "transaction_type", + "name": "action_type", "type": [ "mapper", { "type": "varint", "mappings": { - "0": "normal", - "1": "inventory_mismatch", - "2": "item_use", - "3": "item_use_on_entity", - "4": "item_release" + "0": "click_block", + "1": "click_air", + "2": "break_block" } } ] }, + { + "name": "block_position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "varint" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + }, + { + "name": "block_runtime_id", + "type": "varint" + } + ] + ], + "TransactionActions": [ + "container", + [ { "name": "network_ids", "type": "bool" }, { - "name": "inventory_actions", + "name": "actions", "type": [ "array", { @@ -928,6 +910,89 @@ ] } ] + } + ] + ], + "TransactionLegacy": [ + "container", + [ + { + "name": "legacy_request_id", + "type": "zigzag32" + }, + { + "name": "legacy_transactions", + "type": [ + "switch", + { + "compareTo": "legacy_request_id", + "fields": { + "0": "void" + }, + "default": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "changed_slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_id", + "type": "u8" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + } + ] + ], + "Transaction": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "transaction_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "inventory_mismatch", + "2": "item_use", + "3": "item_use_on_entity", + "4": "item_release" + } + } + ] + }, + { + "name": "actions", + "type": "TransactionActions" }, { "name": "transaction_data", @@ -938,53 +1003,7 @@ "fields": { "normal": "void", "inventory_mismatch": "void", - "item_use": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "click_block", - "1": "click_air", - "2": "break_block" - } - } - ] - }, - { - "name": "block_position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "hotbar_slot", - "type": "varint" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - }, - { - "name": "block_runtime_id", - "type": "varint" - } - ] - ], + "item_use": "TransactionUseItem", "item_use_on_entity": [ "container", [ @@ -2009,6 +2028,42 @@ ] } ], + "Action": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "start_break", + "1": "abort_break", + "2": "stop_break", + "3": "get_updated_block", + "4": "drop_item", + "5": "start_sleeping", + "6": "stop_sleeping", + "7": "respawn", + "8": "jump", + "9": "start_sprint", + "10": "stop_sprint", + "11": "start_sneak", + "12": "stop_sneak", + "13": "creative_player_destroy_block", + "14": "dimension_change_ack", + "15": "start_glide", + "16": "stop_glide", + "17": "build_denied", + "18": "crack_break", + "19": "change_skin", + "20": "set_enchatnment_seed", + "21": "swimming", + "22": "stop_swimming", + "23": "start_spin_attack", + "24": "stop_spin_attack", + "25": "ineract_block", + "26": "predict_break", + "27": "continue_break" + } + } + ], "StackRequestSlotInfo": [ "container", [ @@ -2026,272 +2081,266 @@ } ] ], - "ItemStackRequests": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ + "ItemStackRequest": [ + "container", + [ + { + "name": "request_id", + "type": "zigzag32" + }, + { + "name": "actions", + "type": [ + "array", { - "name": "request_id", - "type": "zigzag32" - }, - { - "name": "actions", + "countType": "varint", "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ + "container", + [ + { + "name": "type_id", + "type": [ + "mapper", { - "name": "type_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "take", - "1": "place", - "2": "swap", - "3": "drop", - "4": "destroy", - "5": "consume", - "6": "create", - "7": "lab_table_combine", - "8": "beacon_payment", - "9": "mine_block", - "10": "craft_recipe", - "11": "craft_recipe_auto", - "12": "craft_creative", - "13": "optional", - "14": "non_implemented", - "15": "results_deprecated" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type_id", - "fields": { - "take": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "place": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "swap": [ - "container", - [ - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "drop": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "randomly", - "type": "bool" - } - ] - ], - "destroy": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "consume": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "create": [ - "container", - [ - { - "name": "result_slot_id", - "type": "u8" - } - ] - ], - "beacon_payment": [ - "container", - [ - { - "name": "primary_effect", - "type": "zigzag32" - }, - { - "name": "secondary_effect", - "type": "zigzag32" - } - ] - ], - "mine_block": [ - "container", - [ - { - "name": "unknown1", - "type": "zigzag32" - }, - { - "name": "predicted_durability", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "craft_recipe": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_recipe_auto": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_creative": [ - "container", - [ - { - "name": "creative_item_network_id", - "type": "varint32" - } - ] - ], - "optional": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - }, - { - "name": "filtered_string_index", - "type": "li32" - } - ] - ], - "non_implemented": "void", - "results_deprecated": [ - "container", - [ - { - "name": "result_items", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "times_crafted", - "type": "u8" - } - ] - ] - }, - "default": "void" - } - ] + "type": "u8", + "mappings": { + "0": "take", + "1": "place", + "2": "swap", + "3": "drop", + "4": "destroy", + "5": "consume", + "6": "create", + "7": "lab_table_combine", + "8": "beacon_payment", + "9": "mine_block", + "10": "craft_recipe", + "11": "craft_recipe_auto", + "12": "craft_creative", + "13": "optional", + "14": "non_implemented", + "15": "results_deprecated" + } } ] - ] - } - ] - }, - { - "name": "custom_names", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type_id", + "fields": { + "take": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "place": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "swap": [ + "container", + [ + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "drop": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "randomly", + "type": "bool" + } + ] + ], + "destroy": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "consume": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "create": [ + "container", + [ + { + "name": "result_slot_id", + "type": "u8" + } + ] + ], + "beacon_payment": [ + "container", + [ + { + "name": "primary_effect", + "type": "zigzag32" + }, + { + "name": "secondary_effect", + "type": "zigzag32" + } + ] + ], + "mine_block": [ + "container", + [ + { + "name": "unknown1", + "type": "zigzag32" + }, + { + "name": "predicted_durability", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "craft_recipe": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_recipe_auto": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_creative": [ + "container", + [ + { + "name": "creative_item_network_id", + "type": "varint32" + } + ] + ], + "optional": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + }, + { + "name": "filtered_string_index", + "type": "li32" + } + ] + ], + "non_implemented": "void", + "results_deprecated": [ + "container", + [ + { + "name": "result_items", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "times_crafted", + "type": "u8" + } + ] + ] + }, + "default": "void" + } + ] + } + ] ] } ] - ] - } + }, + { + "name": "custom_names", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] ], "ItemStackResponses": [ "array", @@ -4481,42 +4530,7 @@ }, { "name": "action", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "start_break", - "1": "abort_break", - "2": "stop_break", - "3": "get_updated_block", - "4": "drop_item", - "5": "start_sleeping", - "6": "stop_sleeping", - "7": "respawn", - "8": "jump", - "9": "start_sprint", - "10": "stop_sprint", - "11": "start_sneak", - "12": "stop_sneak", - "13": "creative_player_destroy_block", - "14": "dimension_change_ack", - "15": "start_glide", - "16": "stop_glide", - "17": "build_denied", - "18": "crack_break", - "19": "change_skin", - "20": "set_enchatnment_seed", - "21": "swimming", - "22": "stop_swimming", - "23": "start_spin_attack", - "24": "stop_spin_attack", - "25": "ineract_block", - "26": "predict_break", - "27": "continue_break" - } - } - ] + "type": "Action" }, { "name": "position", @@ -6821,10 +6835,11 @@ { "type": "varint", "mappings": { - "0": "mouse", - "1": "touch", - "2": "game_pad", - "3": "motion_controller" + "0": "unknown", + "1": "mouse", + "2": "touch", + "3": "game_pad", + "4": "motion_controller" } } ] @@ -6870,6 +6885,152 @@ { "name": "delta", "type": "vec3f" + }, + { + "name": "transaction", + "type": [ + "switch", + { + "compareTo": "input_data.item_interact", + "fields": { + "true": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "actions", + "type": "TransactionActions" + }, + { + "name": "data", + "type": "TransactionUseItem" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "item_stack_request", + "type": [ + "switch", + { + "compareTo": "input_data.item_stack_request", + "fields": { + "true": "ItemStackRequest" + }, + "default": "void" + } + ] + }, + { + "name": "block_action", + "type": [ + "switch", + { + "compareTo": "input_data.block_action", + "fields": { + "true": [ + "array", + { + "countType": "zigzag32", + "type": [ + "container", + [ + { + "name": "action", + "type": "Action" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "action", + "fields": { + "start_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "abort_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "crack_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "predict_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "continue_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + "default": "void" + } + ] } ] ], @@ -6896,7 +7057,13 @@ [ { "name": "requests", - "type": "ItemStackRequests" + "type": [ + "array", + { + "countType": "varint", + "type": "ItemStackRequest" + } + ] } ] ], @@ -7304,72 +7471,72 @@ "type": "zigzag64", "big": true, "shift": true, - "flags": { - "onfire": 0, - "sneaking": 1, - "riding": 2, - "sprinting": 3, - "action": 4, - "invisible": 5, - "tempted": 6, - "inlove": 7, - "saddled": 8, - "powered": 9, - "ignited": 10, - "baby": 11, - "converting": 12, - "critical": 13, - "can_show_nametag": 14, - "always_show_nametag": 15, - "no_ai": 16, - "silent": 17, - "wallclimbing": 18, - "can_climb": 19, - "swimmer": 20, - "can_fly": 21, - "walker": 22, - "resting": 23, - "sitting": 24, - "angry": 25, - "interested": 26, - "charged": 27, - "tamed": 28, - "orphaned": 29, - "leashed": 30, - "sheared": 31, - "gliding": 32, - "elder": 33, - "moving": 34, - "breathing": 35, - "chested": 36, - "stackable": 37, - "showbase": 38, - "rearing": 39, - "vibrating": 40, - "idling": 41, - "evoker_spell": 42, - "charge_attack": 43, - "wasd_controlled": 44, - "can_power_jump": 45, - "linger": 46, - "has_collision": 47, - "affected_by_gravity": 48, - "fire_immune": 49, - "dancing": 50, - "enchanted": 51, - "show_trident_rope": 52, - "container_private": 53, - "transforming": 54, - "spin_attack": 55, - "swimming": 56, - "bribed": 57, - "pregnant": 58, - "laying_egg": 59, - "rider_can_pick": 60, - "transition_sitting": 61, - "eating": 62, - "laying_down": 63 - } + "flags": [ + "onfire", + "sneaking", + "riding", + "sprinting", + "action", + "invisible", + "tempted", + "inlove", + "saddled", + "powered", + "ignited", + "baby", + "converting", + "critical", + "can_show_nametag", + "always_show_nametag", + "no_ai", + "silent", + "wallclimbing", + "can_climb", + "swimmer", + "can_fly", + "walker", + "resting", + "sitting", + "angry", + "interested", + "charged", + "tamed", + "orphaned", + "leashed", + "sheared", + "gliding", + "elder", + "moving", + "breathing", + "chested", + "stackable", + "showbase", + "rearing", + "vibrating", + "idling", + "evoker_spell", + "charge_attack", + "wasd_controlled", + "can_power_jump", + "linger", + "has_collision", + "affected_by_gravity", + "fire_immune", + "dancing", + "enchanted", + "show_trident_rope", + "container_private", + "transforming", + "spin_attack", + "swimming", + "bribed", + "pregnant", + "laying_egg", + "rider_can_pick", + "transition_sitting", + "eating", + "laying_down" + ] } ], "MetadataFlags2": [ @@ -7377,40 +7544,39 @@ { "type": "zigzag64", "big": true, - "shift": true, - "flags": { - "sneezing": 64, - "trusting": 65, - "rolling": 66, - "scared": 67, - "in_scaffolding": 68, - "over_scaffolding": 69, - "fall_through_scaffolding": 70, - "blocking": 71, - "transition_blocking": 72, - "blocked_using_shield": 73, - "blocked_using_damaged_shield": 74, - "sleeping": 75, - "wants_to_wake": 76, - "trade_interest": 77, - "door_breaker": 78, - "breaking_obstruction": 79, - "door_opener": 80, - "illager_captain": 81, - "stunned": 82, - "roaring": 83, - "delayed_attacking": 84, - "avoiding_mobs": 85, - "avoiding_block": 86, - "facing_target_to_range_attack": 87, - "hidden_when_invisible": 88, - "is_in_ui": 89, - "stalking": 90, - "emoting": 91, - "celebrating": 92, - "admiring": 93, - "celebrating_special": 94 - } + "flags": [ + "sneezing", + "trusting", + "rolling", + "scared", + "in_scaffolding", + "over_scaffolding", + "fall_through_scaffolding", + "blocking", + "transition_blocking", + "blocked_using_shield", + "blocked_using_damaged_shield", + "sleeping", + "wants_to_wake", + "trade_interest", + "door_breaker", + "breaking_obstruction", + "door_opener", + "illager_captain", + "stunned", + "roaring", + "delayed_attacking", + "avoiding_mobs", + "avoiding_block", + "facing_target_to_range_attack", + "hidden_when_invisible", + "is_in_ui", + "stalking", + "emoting", + "celebrating", + "admiring", + "celebrating_special" + ] } ], "UpdateBlockFlags": [ @@ -7499,46 +7665,47 @@ "InputFlag": [ "bitflags", { - "type": "varint", - "flags": { - "ascend": 1, - "descend": 2, - "north_jump": 4, - "jump_down": 8, - "sprint_down": 16, - "change_height": 32, - "jumping": 64, - "auto_jumping_in_water": 128, - "sneaking": 256, - "sneak_down": 512, - "up": 1024, - "down": 2048, - "left": 4096, - "right": 8192, - "up_left": 16384, - "up_right": 32768, - "want_up": 65536, - "want_down": 131072, - "want_down_slow": 262144, - "want_up_slow": 524288, - "sprinting": 1048576, - "ascend_scaffolding": 2097152, - "descend_scaffolding": 4194304, - "sneak_toggle_down": 8388608, - "persist_sneak": 16777216, - "start_sprinting": 33554432, - "stop_sprinting": 67108864, - "start_sneaking": 134217728, - "stop_sneaking": 134217728, - "start_swimming": 268435456, - "stop_swimming": 536870912, - "start_jumping": 1073741824, - "start_gliding": 2147483648, - "stop_gliding": 4294967296, - "item_interact": 8589934592, - "block_action": 17179869184, - "item_stack_request": 34359738368 - } + "type": "varint64", + "big": true, + "flags": [ + "ascend", + "descend", + "north_jump", + "jump_down", + "sprint_down", + "change_height", + "jumping", + "auto_jumping_in_water", + "sneaking", + "sneak_down", + "up", + "down", + "left", + "right", + "up_left", + "up_right", + "want_up", + "want_down", + "want_down_slow", + "want_up_slow", + "sprinting", + "ascend_scaffolding", + "descend_scaffolding", + "sneak_toggle_down", + "persist_sneak", + "start_sprinting", + "stop_sprinting", + "start_sneaking", + "stop_sneaking", + "start_swimming", + "stop_swimming", + "start_jumping", + "start_gliding", + "stop_gliding", + "item_interact", + "block_action", + "item_stack_request" + ] } ], "ArmorDamageType": [ diff --git a/data/latest/proto.yml b/data/latest/proto.yml index bc026ba..f24b5fb 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -753,6 +753,10 @@ packet_update_attributes: attributes: PlayerAttributes tick: varint64 +# InventoryTransaction is a packet sent by the client. It essentially exists out of multiple sub-packets, +# each of which have something to do with the inventory in one way or another. Some of these sub-packets +# directly relate to the inventory, others relate to interaction with the world, that could potentially +# result in a change in the inventory. packet_inventory_transaction: !id: 0x1e !bound: both @@ -821,37 +825,7 @@ packet_player_action: runtime_entity_id: varint # ActionType is the ID of the action that was executed by the player. It is one of the constants that may # be found above. - action: zigzag32 => - 0: start_break - 1: abort_break - 2: stop_break - 3: get_updated_block - 4: drop_item - 5: start_sleeping - 6: stop_sleeping - 7: respawn - 8: jump - 9: start_sprint - 10: stop_sprint - 11: start_sneak - 12: stop_sneak - 13: creative_player_destroy_block - # sent when spawning in a different dimension to tell the server we spawned - 14: dimension_change_ack - 15: start_glide - 16: stop_glide - 17: build_denied - 18: crack_break - 19: change_skin - # no longer used - 20: set_enchatnment_seed - 21: swimming - 22: stop_swimming - 23: start_spin_attack - 24: stop_spin_attack - 25: ineract_block - 26: predict_break - 27: continue_break + action: Action # BlockPosition is the position of the target block, if the action with the ActionType set concerned a # block. If that is not the case, the block position will be zero. position: BlockCoordinates @@ -2127,10 +2101,11 @@ packet_player_auth_input: # InputMode specifies the way that the client inputs data to the screen. It is one of the constants that # may be found above. input_mode: varint => - 0: mouse - 1: touch - 2: game_pad - 3: motion_controller + 0: unknown + 1: mouse + 2: touch + 3: game_pad + 4: motion_controller # PlayMode specifies the way that the player is playing. The values it holds, which are rather random, # may be found above. play_mode: varint => @@ -2154,49 +2129,67 @@ packet_player_auth_input: # Delta was the delta between the old and the new position. There isn't any practical use for this field # as it can be calculated by the server itself. delta: vec3f + transaction: input_data.item_interact ? + if true: + legacy: TransactionLegacy + actions: TransactionActions + data: TransactionUseItem + item_stack_request: input_data.item_stack_request ? + if true: ItemStackRequest + block_action: input_data.block_action ? + if true: []zigzag32 + action: Action + _: action? + if start_break or abort_break or crack_break or predict_break or continue_break: + # BlockPosition is the position of the target block, if the action with the ActionType set concerned a + # block. If that is not the case, the block position will be zero. + position: BlockCoordinates + # BlockFace is the face of the target block that was touched. If the action with the ActionType set + # concerned a block. If not, the face is always 0. + face: zigzag32 #TODO: update to use the new `shift` option in bitflags InputFlag: [ "bitflags", { - "type": "varint", - "flags": { - "ascend": 0b1, - "descend": 0b10, - "north_jump": 0b100, - "jump_down": 0b1000, - "sprint_down": 0b10000, - "change_height": 0b100000, - "jumping": 0b1000000, - "auto_jumping_in_water": 0b10000000, - "sneaking": 0b100000000, - "sneak_down": 0b1000000000, - "up": 0b10000000000, - "down": 0b100000000000, - "left": 0b1000000000000, - "right": 0b10000000000000, - "up_left": 0b100000000000000, - "up_right": 0b1000000000000000, - "want_up": 0b10000000000000000, - "want_down": 0b100000000000000000, - "want_down_slow": 0b1000000000000000000, - "want_up_slow": 0b10000000000000000000, - "sprinting": 0b100000000000000000000, - "ascend_scaffolding": 0b1000000000000000000000, - "descend_scaffolding": 0b10000000000000000000000, - "sneak_toggle_down": 0b100000000000000000000000, - "persist_sneak": 0b1000000000000000000000000, - "start_sprinting": 0b10000000000000000000000000, - "stop_sprinting": 0b100000000000000000000000000, - "start_sneaking": 0b1000000000000000000000000000, - "stop_sneaking": 0b1000000000000000000000000000, - "start_swimming": 0b10000000000000000000000000000, - "stop_swimming": 0b100000000000000000000000000000, - "start_jumping": 0b1000000000000000000000000000000, - "start_gliding": 0b10000000000000000000000000000000, - "stop_gliding": 0b100000000000000000000000000000000, - "item_interact": 0b1000000000000000000000000000000000, - "block_action": 0b10000000000000000000000000000000000, - "item_stack_request": 0b100000000000000000000000000000000000 - } + "type": "varint64", "big": true, + "flags": [ + "ascend", + "descend", + "north_jump", + "jump_down", + "sprint_down", + "change_height", + "jumping", + "auto_jumping_in_water", + "sneaking", + "sneak_down", + "up", + "down", + "left", + "right", + "up_left", + "up_right", + "want_up", + "want_down", + "want_down_slow", + "want_up_slow", + "sprinting", + "ascend_scaffolding", + "descend_scaffolding", + "sneak_toggle_down", + "persist_sneak", + "start_sprinting", + "stop_sprinting", + "start_sneaking", + "stop_sneaking", + "start_swimming", + "stop_swimming", + "start_jumping", + "start_gliding", + "stop_gliding", + "item_interact", + "block_action", + "item_stack_request" + ] }] packet_creative_content: @@ -2209,10 +2202,14 @@ packet_player_enchant_options: !bound: client enchant_options: EnchantOptions +# ItemStackRequest is sent by the client to change item stacks in an inventory. It is essentially a +# replacement of the InventoryTransaction packet added in 1.16 for inventory specific actions, such as moving +# items around or crafting. The InventoryTransaction packet is still used for actions such as placing blocks +# and interacting with entities. packet_item_stack_request: !id: 0x93 !bound: server - requests: ItemStackRequests + requests: ItemStackRequest[]varint packet_item_stack_response: !id: 0x94 diff --git a/data/latest/types.yaml b/data/latest/types.yaml index c99030e..1c613d3 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -262,110 +262,112 @@ MetadataDictionary: []varint if vec3f: vec3f MetadataFlags1: [ "bitflags", { - "type": "zigzag64", "big": true, "shift": true, - "flags": { - "onfire": 0, - "sneaking": 1, - "riding": 2, - "sprinting": 3, - "action": 4, - "invisible": 5, - "tempted": 6, - "inlove": 7, - "saddled": 8, - "powered": 9, - "ignited": 10, - "baby": 11, - "converting": 12, - "critical": 13, - "can_show_nametag": 14, - "always_show_nametag": 15, - "no_ai": 16, - "silent": 17, - "wallclimbing": 18, - "can_climb": 19, - "swimmer": 20, - "can_fly": 21, - "walker": 22, - "resting": 23, - "sitting": 24, - "angry": 25, - "interested": 26, - "charged": 27, - "tamed": 28, - "orphaned": 29, - "leashed": 30, - "sheared": 31, - "gliding": 32, - "elder": 33, - "moving": 34, - "breathing": 35, - "chested": 36, - "stackable": 37, - "showbase": 38, - "rearing": 39, - "vibrating": 40, - "idling": 41, - "evoker_spell": 42, - "charge_attack": 43, - "wasd_controlled": 44, - "can_power_jump": 45, - "linger": 46, - "has_collision": 47, - "affected_by_gravity": 48, - "fire_immune": 49, - "dancing": 50, - "enchanted": 51, - "show_trident_rope": 52, # tridents show an animated rope when enchanted with loyalty after they are thrown and return to their owner. to be combined with data_owner_eid - "container_private": 53, #inventory is private, doesn't drop contents when killed if true - "transforming": 54, - "spin_attack": 55, - "swimming": 56, - "bribed": 57, #dolphins have this set when they go to find treasure for the player - "pregnant": 58, - "laying_egg": 59, - "rider_can_pick": 60, #??? - "transition_sitting": 61, - "eating": 62, - "laying_down": 63, - } + "type": "zigzag64", + "big": true, + "flags": [ + "onfire", + "sneaking", + "riding", + "sprinting", + "action", + "invisible", + "tempted", + "inlove", + "saddled", + "powered", + "ignited", + "baby", + "converting", + "critical", + "can_show_nametag", + "always_show_nametag", + "no_ai", + "silent", + "wallclimbing", + "can_climb", + "swimmer", + "can_fly", + "walker", + "resting", + "sitting", + "angry", + "interested", + "charged", + "tamed", + "orphaned", + "leashed", + "sheared", + "gliding", + "elder", + "moving", + "breathing", + "chested", + "stackable", + "showbase", + "rearing", + "vibrating", + "idling", + "evoker_spell", + "charge_attack", + "wasd_controlled", + "can_power_jump", + "linger", + "has_collision", + "affected_by_gravity", + "fire_immune", + "dancing", + "enchanted", + "show_trident_rope", # tridents show an animated rope when enchanted with loyalty after they are thrown and return to their owner. to be combined with data_owner_eid + "container_private", #inventory is private, doesn't drop contents when killed if true + "transforming", + "spin_attack", + "swimming", + "bribed", #dolphins have this set when they go to find treasure for the player + "pregnant", + "laying_egg", + "rider_can_pick", #??? + "transition_sitting", + "eating", + "laying_down" + ] }] MetadataFlags2: [ "bitflags", { - "type": "zigzag64","big": true, "shift": true, - "flags": { - "sneezing": 64, - "trusting": 65, - "rolling": 66, - "scared": 67, - "in_scaffolding": 68, - "over_scaffolding": 69, - "fall_through_scaffolding": 70, - "blocking": 71, #shield - "transition_blocking": 72, - "blocked_using_shield": 73, - "blocked_using_damaged_shield": 74, - "sleeping": 75, - "wants_to_wake": 76, - "trade_interest": 77, - "door_breaker": 78, #... - "breaking_obstruction": 79, - "door_opener": 80, #... - "illager_captain": 81, - "stunned": 82, - "roaring": 83, - "delayed_attacking": 84, - "avoiding_mobs": 85, - "avoiding_block": 86, - "facing_target_to_range_attack": 87, - "hidden_when_invisible": 88, #?????????????????? - "is_in_ui": 89, - "stalking": 90, - "emoting": 91, - "celebrating": 92, - "admiring": 93, - "celebrating_special": 94, - } + "type": "zigzag64", + "big": true, + "flags": [ + "sneezing", + "trusting", + "rolling", + "scared", + "in_scaffolding", + "over_scaffolding", + "fall_through_scaffolding", + "blocking", #shield + "transition_blocking", + "blocked_using_shield", + "blocked_using_damaged_shield", + "sleeping", + "wants_to_wake", + "trade_interest", + "door_breaker", #... + "breaking_obstruction", + "door_opener", #... + "illager_captain", + "stunned", + "roaring", + "delayed_attacking", + "avoiding_mobs", + "avoiding_block", + "facing_target_to_range_attack", + "hidden_when_invisible", #?????????????????? + "is_in_ui", + "stalking", + "emoting", + "celebrating", + "admiring", + "celebrating_special" + ] }] Link: @@ -400,31 +402,44 @@ PlayerAttributes: []varint default: lf32 name: string -Transaction: - # LegacyRequestID is an ID that is only non-zero at times when sent by the client. The server should - # always send 0 for this. When this field is not 0, the LegacySetItemSlots slice below will have values - # in it. - # LegacyRequestID ties in with the ItemStackResponse packet. If this field is non-0, the server should - # respond with an ItemStackResponse packet. Some inventory actions such as dropping an item out of the - # hotbar are still one using this packet, and the ItemStackResponse packet needs to tie in with it. - legacy_request_id: zigzag32 - # `legacy_transactions` are only present if the LegacyRequestID is non-zero. These item slots inform the - # server of the slots that were changed during the inventory transaction, and the server should send - # back an ItemStackResponse packet with these slots present in it. (Or false with no slots, if rejected.) - legacy_transactions: legacy_request_id? - if 0: void - default: []varint - container_id: u8 - changed_slots: []varint - slot_id: u8 - transaction_type: varint => - 0: normal - 1: inventory_mismatch - 2: item_use - 3: item_use_on_entity - 4: item_release +# UseItemTransactionData represents an inventory transaction data object sent when the client uses an item on +# a block. Also used in PlayerAuthoritativeInput packet +TransactionUseItem: + # ActionType is the type of the UseItem inventory transaction. It is one of the action types found above, + # and specifies the way the player interacted with the block. + action_type: varint => + 0: click_block + 1: click_air + 2: break_block + # BlockPosition is the position of the block that was interacted with. This is only really a correct + # block position if ActionType is not UseItemActionClickAir. + block_position: BlockCoordinates + # BlockFace is the face of the block that was interacted with. When clicking the block, it is the face + # clicked. When breaking the block, it is the face that was last being hit until the block broke. + face: varint + # HotBarSlot is the hot bar slot that the player was holding while clicking the block. It should be used + # to ensure that the hot bar slot and held item are correctly synchronised with the server. + hotbar_slot: varint + # HeldItem is the item that was held to interact with the block. The server should check if this item + # is actually present in the HotBarSlot. + held_item: Item + # Position is the position of the player at the time of interaction. For clicking a block, this is the + # position at that time, whereas for breaking the block it is the position at the time of breaking. + player_pos: vec3f + # ClickedPosition is the position that was clicked relative to the block's base coordinate. It can be + # used to find out exactly where a player clicked the block. + click_pos: vec3f + # BlockRuntimeID is the runtime ID of the block that was clicked. It may be used by the server to verify + # that the player's world client-side is synchronised with the server's. + block_runtime_id: varint + +# Actions is a list of actions that took place, that form the inventory transaction together. Each of +# these actions hold one slot in which one item was changed to another. In general, the combination of +# all of these actions results in a balanced inventory transaction. This should be checked to ensure that +# no items are cheated into the inventory. +TransactionActions: network_ids: bool - inventory_actions: []varint + actions: []varint source_type: varint => 0: container 1: global @@ -444,40 +459,47 @@ Transaction: old_item: Item new_item: Item new_item_stack_id: ../network_ids? - if true: zigzag32 + if true: zigzag32 default: void + +# The Minecraft bedrock inventory system was refactored, but not all inventory actions use the new packet. +# This data structure holds actions that have not been updated to the new system. +TransactionLegacy: + # LegacyRequestID is an ID that is only non-zero at times when sent by the client. The server should + # always send 0 for this. When this field is not 0, the LegacySetItemSlots slice below will have values + # in it. + # LegacyRequestID ties in with the ItemStackResponse packet. If this field is non-0, the server should + # respond with an ItemStackResponse packet. Some inventory actions such as dropping an item out of the + # hotbar are still one using this packet, and the ItemStackResponse packet needs to tie in with it. + legacy_request_id: zigzag32 + # `legacy_transactions` are only present if the LegacyRequestID is non-zero. These item slots inform the + # server of the slots that were changed during the inventory transaction, and the server should send + # back an ItemStackResponse packet with these slots present in it. (Or false with no slots, if rejected.) + legacy_transactions: legacy_request_id? + if 0: void + default: []varint + container_id: u8 + changed_slots: []varint + slot_id: u8 + +Transaction: + # Old transaction system data + legacy: TransactionLegacy + # What type of transaction took place + transaction_type: varint => + 0: normal + 1: inventory_mismatch + 2: item_use + 3: item_use_on_entity + 4: item_release + # The list of inventory internal actions in this packet, e.g. inventory GUI actions + actions: TransactionActions + # Extra data if an intenal inventory transaction did not take place, e.g. use of an item transaction_data: transaction_type? if normal or inventory_mismatch: void # UseItemTransactionData represents an inventory transaction data object sent when the client uses an item on # a block. - if item_use: - # ActionType is the type of the UseItem inventory transaction. It is one of the action types found above, - # and specifies the way the player interacted with the block. - action_type: varint => - 0: click_block - 1: click_air - 2: break_block - # BlockPosition is the position of the block that was interacted with. This is only really a correct - # block position if ActionType is not UseItemActionClickAir. - block_position: BlockCoordinates - # BlockFace is the face of the block that was interacted with. When clicking the block, it is the face - # clicked. When breaking the block, it is the face that was last being hit until the block broke. - face: varint - # HotBarSlot is the hot bar slot that the player was holding while clicking the block. It should be used - # to ensure that the hot bar slot and held item are correctly synchronised with the server. - hotbar_slot: varint - # HeldItem is the item that was held to interact with the block. The server should check if this item - # is actually present in the HotBarSlot. - held_item: Item - # Position is the position of the player at the time of interaction. For clicking a block, this is the - # position at that time, whereas for breaking the block it is the position at the time of breaking. - player_pos: vec3f - # ClickedPosition is the position that was clicked relative to the block's base coordinate. It can be - # used to find out exactly where a player clicked the block. - click_pos: vec3f - # BlockRuntimeID is the runtime ID of the block that was clicked. It may be used by the server to verify - # that the player's world client-side is synchronised with the server's. - block_runtime_id: varint + if item_use: TransactionUseItem # UseItemOnEntityTransactionData represents an inventory transaction data object sent when the client uses # an item on an entity. if item_use_on_entity: @@ -698,15 +720,48 @@ EnchantOptions: []varint name: string option_id: zigzag32 +Action: zigzag32 => + 0: start_break + 1: abort_break + 2: stop_break + 3: get_updated_block + 4: drop_item + 5: start_sleeping + 6: stop_sleeping + 7: respawn + 8: jump + 9: start_sprint + 10: stop_sprint + 11: start_sneak + 12: stop_sneak + 13: creative_player_destroy_block + # sent when spawning in a different dimension to tell the server we spawned + 14: dimension_change_ack + 15: start_glide + 16: stop_glide + 17: build_denied + 18: crack_break + 19: change_skin + # no longer used + 20: set_enchatnment_seed + 21: swimming + 22: stop_swimming + 23: start_spin_attack + 24: stop_spin_attack + 25: ineract_block + 26: predict_break + 27: continue_break StackRequestSlotInfo: container_id: u8 slot_id: u8 stack_id: zigzag32 -# - -ItemStackRequests: []varint +# ItemStackRequest is sent by the client to change item stacks in an inventory. It is essentially a +# replacement of the InventoryTransaction packet added in 1.16 for inventory specific actions, such as moving +# items around or crafting. The InventoryTransaction packet is still used for actions such as placing blocks +# and interacting with entities. +ItemStackRequest: # RequestID is a unique ID for the request. This ID is used by the server to send a response for this # specific request in the ItemStackResponse packet. request_id: zigzag32 @@ -836,10 +891,10 @@ ItemStackRequests: []varint # ItemStackResponse is a response to an individual ItemStackRequest. ItemStackResponses: []varint - # Status specifies if the request with the RequestID below was successful. If this is the case, the - # ContainerInfo below will have information on what slots ended up changing. If not, the container info - # will be empty. - # A non-0 status means an error occurred and will result in the action being reverted. + # Status specifies if the request with the RequestID below was successful. If this is the case, the + # ContainerInfo below will have information on what slots ended up changing. If not, the container info + # will be empty. + # A non-0 status means an error occurred and will result in the action being reverted. status: u8 => 0: ok 1: error diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index 91c8b0b..dd3afe3 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -81,57 +81,63 @@ SizeOf.nbt = ['native', minecraft.nbt[2]] */ Read.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { - if (shift) { - let i = 0 - for (const key in flags) { - const val = flags[key] - flags[key] = val << i++ - } + let fstr = JSON.stringify(flags) + if (Array.isArray(flags)) { + fstr = '{' + flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) + fstr += '}' + } else if (shift) { + fstr = '{' + for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`; + fstr += '}' } return compiler.wrapCode(` const { value: _value, size } = ${compiler.callType(type, 'offset')} const value = { _value } - const flags = ${JSON.stringify(flags)} + const flags = ${fstr} for (const key in flags) { - const v = ${big ? `BigInt(flags[key])` : 'flags[key]'} - value[key] = (_value & v) == v + value[key] = (_value & flags[key]) == flags[key] } return { value, size } `.trim()) }] Write.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { - if (shift) { - let i = 0 - for (const key in flags) { - const val = flags[key] - flags[key] = val << i++ - } + let fstr = JSON.stringify(flags) + if (Array.isArray(flags)) { + fstr = '{' + flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) + fstr += '}' + } else if (shift) { + fstr = '{' + for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`; + fstr += '}' } return compiler.wrapCode(` - const flags = ${JSON.stringify(flags)} - let val = value._value + const flags = ${fstr} + let val = value._value ${big ? '|| 0n' : ''} for (const key in flags) { - const v = ${big ? `BigInt(flags[key])` : 'flags[key]'} - if (value[key]) val |= v + if (value[key]) val |= flags[key] } return (ctx.${type})(val, buffer, offset) `.trim()) }] SizeOf.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { - if (shift) { - let i = 0 - for (const key in flags) { - const val = flags[key] - flags[key] = val << i++ - } + let fstr = JSON.stringify(flags) + if (Array.isArray(flags)) { + fstr = '{' + flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) + fstr += '}' + } else if (shift) { + fstr = '{' + for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`; + fstr += '}' } return compiler.wrapCode(` - const flags = ${JSON.stringify(flags)} - let val = value._value + const flags = ${fstr} + let val = value._value ${big ? '|| 0n' : ''} for (const key in flags) { - const v = ${big ? `BigInt(flags[key])` : 'flags[key]'} if (value[key]) val |= flags[key] } return (ctx.${type})(val) From edcc3704266c71042577a66e6e9f169c733e861e Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 22 Mar 2021 15:07:25 -0400 Subject: [PATCH 132/458] Add index, .npmignore, connect timeout (#1) * add index and .npm ignore * add connect timeout * update protocol.json * Update ci.yml * Update ci.yml --- .github/workflows/ci.yml | 6 +++--- .npmignore | 1 + data/1.16.210/protocol.json | 1 - examples/clientTest.js | 2 +- index.js | 6 ++++++ package.json | 3 ++- src/client.js | 9 +++++++++ src/connection.js | 2 +- src/options.js | 4 +++- src/server.js | 6 +++--- src/serverPlayer.js | 7 ++++++- 11 files changed, 35 insertions(+), 12 deletions(-) create mode 100644 .npmignore create mode 100644 index.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8525e8..c565b62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ master ] + branches: [ '*', '!gh-pages' ] pull_request: - branches: [ master ] + branches: [ '*', '!gh-pages' ] jobs: build: @@ -22,4 +22,4 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm install - - run: npm test \ No newline at end of file + - run: npm test diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 9aa256f..fe48767 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -7470,7 +7470,6 @@ { "type": "zigzag64", "big": true, - "shift": true, "flags": [ "onfire", "sneaking", diff --git a/examples/clientTest.js b/examples/clientTest.js index a3d4b2b..157f450 100644 --- a/examples/clientTest.js +++ b/examples/clientTest.js @@ -1,5 +1,5 @@ process.env.DEBUG = 'minecraft-protocol raknet' -const { Client } = require('../src/client') +const { Client } = require('bedrock-protocol') async function test () { const client = new Client({ diff --git a/index.js b/index.js new file mode 100644 index 0000000..6169a77 --- /dev/null +++ b/index.js @@ -0,0 +1,6 @@ +module.exports = { + ...require('./src/client'), + ...require('./src/server'), + ...require('./src/serverPlayer'), + ...require('./src/relay') +} diff --git a/package.json b/package.json index 2971a3f..aec7b49 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,8 @@ "buffer-equal": "^1.0.0", "mocha": "^8.3.2", "protodef-yaml": "^1.0.2", - "standard": "^16.0.3" + "standard": "^16.0.3", + "bedrock-protocol": "file:." }, "standard": { "parser": "babel-eslint" diff --git a/src/client.js b/src/client.js index d6c3493..88c3a44 100644 --- a/src/client.js +++ b/src/client.js @@ -67,12 +67,20 @@ class Client extends Connection { connect = async (sessionData) => { const hostname = this.options.hostname const port = this.options.port + debug('[client] connecting to', hostname, port) this.connection = new RakClient({ useWorkers: true, hostname, port }) this.connection.onConnected = () => this.sendLogin() this.connection.onCloseConnection = () => this.close() this.connection.onEncapsulated = this.onEncapsulated this.connection.connect() + + this.connectTimer = setTimeout(() => { + if (this.status === ClientStatus.Disconnected) { + this.connection.close() + this.emit('error', 'connect timed out') + } + }, this.options.connectTimeout || 9000) } sendLogin () { @@ -117,6 +125,7 @@ class Client extends Connection { close () { clearInterval(this.loop) + clearTimeout(this.connectTimeout) this.q = [] this.q2 = [] this.connection?.close() diff --git a/src/connection.js b/src/connection.js index 7b39dad..95dd4e1 100644 --- a/src/connection.js +++ b/src/connection.js @@ -15,7 +15,7 @@ const ClientStatus = { } class Connection extends EventEmitter { - state = ClientStatus.Disconnected + status = ClientStatus.Disconnected versionLessThan (version) { if (typeof version === 'string') { diff --git a/src/options.js b/src/options.js index 6e64d09..1c9e978 100644 --- a/src/options.js +++ b/src/options.js @@ -16,7 +16,9 @@ const defaultOptions = { // client.status to ClientStatus.Initialized after sending the init packet. autoInitPlayer: true, // If true, do not authenticate with Xbox Live - offline: false + offline: false, + // Milliseconds to wait before aborting connection attempt + connectTimeout: 9000 } module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } diff --git a/src/server.js b/src/server.js index bb98d34..198effb 100644 --- a/src/server.js +++ b/src/server.js @@ -14,8 +14,8 @@ class Server extends EventEmitter { this.deserializer = createDeserializer(this.options.version) this.clients = {} this.clientCount = 0 - this.inLog = (...args) => console.debug('C -> S', ...args) - this.outLog = (...args) => console.debug('S -> C', ...args) + this.inLog = (...args) => debug('C -> S', ...args) + this.outLog = (...args) => debug('S -> C', ...args) } validateOptions () { @@ -38,7 +38,7 @@ class Server extends EventEmitter { } onCloseConnection = (inetAddr, reason) => { - debug('close connection', inetAddr, reason) + console.debug('close connection', inetAddr, reason) delete this.clients[inetAddr] this.clientCount-- } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 70abf8a..52b5588 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -62,6 +62,11 @@ class Player extends Connection { this.emit('server.client_handshake', { key }) // internal so we start encryption this.userData = userData.extraData + this.profile = { + name: userData.extraData?.displayName, + uuid: userData.extraData?.identity, + xuid: userData.extraData?.xuid + } this.version = clientVer } @@ -126,7 +131,7 @@ class Player extends Connection { this.onHandshake() break case 'set_local_player_as_initialized': - this.state = ClientStatus.Initialized + this.status = ClientStatus.Initialized // Emit the 'spawn' event this.emit('spawn') break From b079ebc6763154a78541d5c933ac854389293824 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 22 Mar 2021 23:23:01 -0400 Subject: [PATCH 133/458] Add server close --- src/client.js | 3 ++- src/connection.js | 8 ++++---- src/server.js | 15 +++++++++++++-- src/serverPlayer.js | 14 +++++++++----- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/client.js b/src/client.js index 88c3a44..47c5a60 100644 --- a/src/client.js +++ b/src/client.js @@ -14,6 +14,7 @@ const LoginVerify = require('./auth/loginVerify') const debugging = false class Client extends Connection { + // The RakNet connection connection /** @param {{ version: number, hostname: string, port: number }} options */ @@ -67,7 +68,7 @@ class Client extends Connection { connect = async (sessionData) => { const hostname = this.options.hostname const port = this.options.port - debug('[client] connecting to', hostname, port) + debug('[client] connecting to', hostname, port, sessionData) this.connection = new RakClient({ useWorkers: true, hostname, port }) this.connection.onConnected = () => this.sendLogin() diff --git a/src/connection.js b/src/connection.js index 95dd4e1..220013c 100644 --- a/src/connection.js +++ b/src/connection.js @@ -19,17 +19,17 @@ class Connection extends EventEmitter { versionLessThan (version) { if (typeof version === 'string') { - return Versions[version] < this.options.version + return Versions[version] < this.options.protocolVersion } else { - return version < this.options.version + return version < this.options.protocolVersion } } versionGreaterThan (version) { if (typeof version === 'string') { - return Versions[version] > this.options.version + return Versions[version] > this.options.protocolVersion } else { - return version > this.options.version + return version > this.options.protocolVersion } } diff --git a/src/server.js b/src/server.js index 198effb..2c5187c 100644 --- a/src/server.js +++ b/src/server.js @@ -12,6 +12,7 @@ class Server extends EventEmitter { this.validateOptions() this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) + /** @type {Object} */ this.clients = {} this.clientCount = 0 this.inLog = (...args) => debug('C -> S', ...args) @@ -34,7 +35,7 @@ class Server extends EventEmitter { const player = new Player(this, conn) this.clients[conn.address] = player this.clientCount++ - this.emit('connect', { client: player }) + this.emit('connect', player) } onCloseConnection = (inetAddr, reason) => { @@ -52,7 +53,7 @@ class Server extends EventEmitter { client.handle(buffer) } - async create (hostname = this.options.hostname, port = this.options.port) { + async listen (hostname = this.options.hostname, port = this.options.port) { this.raknet = new RakServer({ hostname, port }) await this.raknet.listen() console.debug('Listening on', hostname, port) @@ -60,6 +61,16 @@ class Server extends EventEmitter { this.raknet.onCloseConnection = this.onCloseConnection this.raknet.onEncapsulated = this.onEncapsulated } + + close (disconnectReason) { + for (const caddr in this.clients) { + const client = this.clients[caddr] + client.disconnect(disconnectReason) + } + this.raknet.close() + this.clients = {} + this.clientCount = 0 + } } module.exports = { Server } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 52b5588..49f7917 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -80,13 +80,17 @@ class Player extends Connection { } /** - * Disconnects a client after it has joined + * Disconnects a client */ disconnect (reason, hide = false) { - this.write('disconnect', { - hide_disconnect_screen: hide, - message: reason - }) + if ([ClientStatus.Authenticating, ClientStatus.Initializing].includes(this.status)) { + this.sendDisconnectStatus('failed_server_full') + } else { + this.write('disconnect', { + hide_disconnect_screen: hide, + message: reason + }) + } this.close() } From 184de537f52057a4f904c8eb7cefa8d205eef19c Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 23 Mar 2021 01:07:26 -0400 Subject: [PATCH 134/458] Remove old tests, lint tests --- .eslintignore | 1 - .gitignore | 4 +- test/checksum.js | 33 ----- test/decryption.js | 41 ------ test/ecdh_key_exchange.js | 43 ------ test/serialization.js | 296 -------------------------------------- test/vanilla.test.js | 4 +- 7 files changed, 3 insertions(+), 419 deletions(-) delete mode 100644 test/checksum.js delete mode 100644 test/decryption.js delete mode 100644 test/ecdh_key_exchange.js delete mode 100644 test/serialization.js diff --git a/.eslintignore b/.eslintignore index b59f7e3..e69de29 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +0,0 @@ -test/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6be9409..8bdb3f2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,8 @@ package-lock.json __* src/**/*.json # Runtime generated data -data/*/sample +data/**/sample data/**/read.js data/**/write.js data/**/size.js -samples/*.txt -samples/*.json tools/bds* \ No newline at end of file diff --git a/test/checksum.js b/test/checksum.js deleted file mode 100644 index 3a15dd4..0000000 --- a/test/checksum.js +++ /dev/null @@ -1,33 +0,0 @@ -const crypto=require("crypto"); -const assert=require("assert"); -const bufferEqual=require("buffer-equal"); - -function writeLI64(value, buffer, offset) { - buffer.writeInt32LE(value[0], offset+4); - buffer.writeInt32LE(value[1], offset); - return offset + 8; -} - -// based on https://s.yawk.at/QADm and https://confluence.yawk.at/display/PEPROTOCOL/Encryption -describe("checksum",() => { - it("generate hash and checksum",() => { - let packetPlaintext = new Buffer("3C00000008","hex"); - let sendCounter = [0,1]; - let secretKeyBytes = new Buffer("ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=","base64"); - - ///// - - let digest = crypto.createHash('sha256'); - // sendCounter to little-endian byte array - let counter=new Buffer(8); - writeLI64(sendCounter,counter,0); - digest.update(counter); - digest.update(packetPlaintext); - digest.update(secretKeyBytes); - let hash = digest.digest(); - assert(bufferEqual(hash, new Buffer("WkRtEcDHqlqesU6wdSnIz7cU3OCNKVMIsX3aXZMLRjQ=","base64")),hash.toString("base64")); - - let checksum = hash.slice(0,8); - assert(bufferEqual(checksum, new Buffer("5A446D11C0C7AA5A","hex"))); - }) -}); \ No newline at end of file diff --git a/test/decryption.js b/test/decryption.js deleted file mode 100644 index af898ee..0000000 --- a/test/decryption.js +++ /dev/null @@ -1,41 +0,0 @@ -const crypto=require("crypto"); -const assert=require("assert"); -const bufferEqual=require("buffer-equal"); - -// based on https://s.yawk.at/8W5U and https://confluence.yawk.at/display/PEPROTOCOL/Encryption -describe("decryption",() => { - let decipher; - before(() => { - - let secretKeyBytes = new Buffer("ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=","base64"); - - ///// - - let iv = secretKeyBytes.slice(0,16); - - assert(bufferEqual(iv, new Buffer("ZOBpyzki/M8UZv5tiBih0w==","base64"))); - - - decipher = crypto.createDecipheriv('aes-256-cfb8', secretKeyBytes, iv); - }); - - - it("decrypt 1",cb => { - let packet1Encrypted = new Buffer("4B4FCA0C2A4114155D67F8092154AAA5EF","hex"); - decipher.once('data', packet1Decrypted => { - assert(bufferEqual(packet1Decrypted, new Buffer("0400000000499602D2FC2FCB233F34D5DD", "hex"))); - cb(); - }); - decipher.write(packet1Encrypted); - }); - - - it("decrypt 2",cb => { - let packet2Encrypted = new Buffer("DF53B9764DB48252FA1AE3AEE4","hex"); - decipher.once('data', packet2Decrypted => { - assert(bufferEqual(packet2Decrypted,new Buffer("3C000000085A446D11C0C7AA5A","hex"))); - cb(); - }); - decipher.write(packet2Encrypted); - }) -}); \ No newline at end of file diff --git a/test/ecdh_key_exchange.js b/test/ecdh_key_exchange.js deleted file mode 100644 index b49cf74..0000000 --- a/test/ecdh_key_exchange.js +++ /dev/null @@ -1,43 +0,0 @@ -const crypto=require("crypto"); -var Ber = require('asn1').Ber; -const assert=require("assert"); -const bufferEqual=require("buffer-equal"); - -// based on https://s.yawk.at/VZSf and https://confluence.yawk.at/display/PEPROTOCOL/Encryption -// and https://github.com/PrismarineJS/bedrock-protocol/issues/15 -describe("ecdh key exchange",() => { - it("generate the secret",() => { - - const pubKeyStr = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDEKneqEvcqUqqFMM1HM1A4zWjJC+I8Y+aKzG5dl+6wNOHHQ4NmG2PEXRJYhujyodFH+wO0dEr4GM1WoaWog8xsYQ6mQJAC0eVpBM96spUB1eMN56+BwlJ4H3Qx4TAvAs"; - - var reader = new Ber.Reader(new Buffer(pubKeyStr, "base64")); - reader.readSequence(); - reader.readSequence(); - reader.readOID(); // Hey, I'm an elliptic curve - reader.readOID(); // This contains the curve type, could be useful - -// The first byte is unused, it contains the "number of unused bits in last octet" -// The pubKey should start at "04" which signifies it is an "uncompressed" public key. - var pubKey = new Buffer(reader.readString(Ber.BitString, true)).slice(1); - -// It'd be better to get this from the curve type OID - var server = crypto.createECDH('secp384r1'); -//server.generateKeys(); - server.setPrivateKey("oH53xXsdMRt6VbjlUUggn/QTcUQUqOHcvHl+U1jaGAUe8TP9H3XdKeoqSAKrKBGG", "base64"); - let secret = server.computeSecret(pubKey); - assert(bufferEqual(secret, new Buffer("sM5HvG6efG0RwRe7S+Er9ingxuVzC6HIXmQ1DITVkh4GmX7pboSzbLtaTTNKE8bJ", "base64"))); - - }); - - - it("create the secret key",() => { - let secret=new Buffer("sM5HvG6efG0RwRe7S+Er9ingxuVzC6HIXmQ1DITVkh4GmX7pboSzbLtaTTNKE8bJ", "base64"); - let hash = crypto.createHash('sha256'); - hash.update("SO SECRET VERY SECURE"); - hash.update(secret); - let secretKey = hash.digest(); - - let expected=new Buffer("PN/4NCtRswMTwfpOKRecbMncwxa91Fx4QSUlad46jrc","base64"); - assert(bufferEqual(secretKey,expected),secretKey.toString("base64")+"!="+expected.toString("base64")); - }) -}); \ No newline at end of file diff --git a/test/serialization.js b/test/serialization.js deleted file mode 100644 index bde8b37..0000000 --- a/test/serialization.js +++ /dev/null @@ -1,296 +0,0 @@ -const fs = require('fs') -const { createDeserializer, createSerializer } = require('../src/transforms/serializer') - -function test() { - const serializer = createSerializer() - const deserializer = createDeserializer() - - function write(name, params) { - const packet = serializer.createPacketBuffer({ name, params }) - console.log('Encoded', packet) - return packet - } - - function read(packet) { - const des = deserializer.parsePacketBuffer(packet) - return des - } - - async function creativeTest() { - let CreativeItems = require('../../data/creativeitems.json') - - let items = [] - let ids = 0 - for (var item of CreativeItems) { - let creativeitem = { runtime_id: items.length } - if (item.id != 0) { - const hasNbt = !!item.nbt_b64 - creativeitem.item = { - network_id: item.id, - auxiliary_value: item.damage || 0, - has_nbt: hasNbt, - nbt: { version: 1 }, - blocking_tick: 0, - can_destroy: [], - can_place_on: [] - } - if (hasNbt) { - let nbtBuf = Buffer.from(item.nbt_b64, 'base64') - let { result } = await NBT.parse(nbtBuf, 'little') - - const buf = NBT.writeUncompressed(result, 'littleVarint') - - console.log(nbtBuf, buf, JSON.stringify(result)) - - console.log('\n') - - let res2 = await NBT.parse(buf, 'littleVarint') - console.log(JSON.stringify(result), JSON.stringify(res2.result)) - console.assert(JSON.stringify(result) == JSON.stringify(res2.result), JSON.stringify(result), JSON.stringify(res2.result)) - - console.log('\n') - - creativeitem.item.nbt.nbt = result - } - } - - items.push(creativeitem) - console.log(JSON.stringify(creativeitem)) - // console.log(JSON.stringify(creativeitem)) - - var s = write('creative_content', { items: [creativeitem] }) - var d = read(s).data.params - - // console.log(JSON.stringify(d), JSON.stringify(s)) - // if (JSON.stringify(d) != JSON.stringify(creative_content)) throw 'mismatch' - } - } - - async function creativeTst() { - var creativeitem = { - "runtime_id": 1166, - "item": { - "network_id": 403, - "auxiliary_value": 0, - "has_nbt": true, - "nbt": { - "version": 1, - "nbt": { - "type": "compound", - "name": "", - "value": { - "ench": { - "type": "list", - "value": { - "type": "compound", - "value": [ - { - "id": { - "type": "short", - "value": 0 - }, - "lvl": { - "type": "short", - "value": 1 - } - } - ] - } - } - } - } - }, - "blocking_tick": 0, - "can_destroy": [], - "can_place_on": [] - } - } - - var s = write('creative_content', { items: [creativeitem] }) - var d = read(s).data.params - console.log(JSON.stringify(d)) - } - - async function availableCommands() { - var avaliable = { - enum_values: ['true', 'false'], - suffixes: ['L'], - enums: [ - { - name: 'Boolean', - values_len: 2, - values: [0, 1] - } - ], - command_data: [ - { - name: 'give', - description: 'Gives you items', - flags: 0, - permission_level: 0, - alias: -1, - overloads: [ - [ - { paramater_name: 'player id', paramater_type: 2, optional: false, flags: { "collapse_enum": 1 } } - ], - [ - { paramater_name: 'item id', paramater_type: 2, optional: false, flags: 0 }, - ] - ], - }, - { - name: 'xp', - description: 'Gives you xp', - flags: 0, permission_level: 0, alias: -1, - overloads: [ - [{ paramater_name: 'player id', paramater_type: 2, optional: false, flags: 0 }] - ] - } - ], - enum_constraints: [ - { - value_index: 2, enum_index: 3, constraints: [ - { constraint: 'cheats_enabled' } - ] - }, - ], - dynamic_enums: [ - { name: 'Hello', values: ['yolo', 'yee'] } - ] - } - - var s = write('available_commands', avaliable) - var d = read(s).data.params - console.log(JSON.stringify(d, null, 2)) - } - - async function avaliableCmd() { - const buffer = Buffer.from(fs.readFileSync('./serialization/available_commands.txt', 'utf8'), 'hex') - const readed = read(buffer) - const recipes = readed.data.params.enums - console.log('read', recipes) - fs.writeFileSync('commands.json', JSON.stringify(readed.data,null,2)) - } - - async function creativeTestNew() { - const json = require('../src/packets/creative_content.json') - const buf = write('creative_content', json) - - const des = read(buf) - fs.writeFileSync('cc.json', serialize(des.data.params, 2)) - console.log('Des', des) - } - - async function biomeDefinitions() { - const json = require('../src/packets/biome_definition_list.json') - const buf = write('biome_definition_list', json) - - const des = read(buf) - fs.writeFileSync('cc.json', serialize(des.data.params, 2)) - console.log('Des', des) - } - - async function playerList() { - const buf = Buffer.from('3f0001cc304faee0c9f37b41c80c39333e3f9cfdffffff5f0c546865496e766973696f6e58103235333534303837333838353837323000070000003f35656236356637332d616631312d343438652d383261612d3162376231363533313661642e706572736f6e612d653139393637326138633161383765302d30000100000001000000040000000000000000000000000000000000056e756c6c0a00000100003f35656236356637332d616631312d343438652d383261612d3162376231363533313661642e706572736f6e612d653139393637326138633161383765302d300477696465092366666666636439360000000000000000000000', 'hex') - const des = read(buf) - console.log(serialize(des.data.params, 2)) - } - - async function startGame() { - const s = '0bfdffffff5f090a32bc2144723d8342a1b99b420000000048ff21c3f6fafadb02000006706c61696e7300020002b006ffff010800c2b79505000000d48ca03e00000000000101060600001b12636f6d6d616e64626c6f636b6f757470757401010f646f6461796c696768746379636c6501010d646f656e7469747964726f707301010a646f666972657469636b010109646f6d6f626c6f6f7401010d646f6d6f62737061776e696e6701010b646f74696c6564726f707301010e646f776561746865726379636c6501010e64726f776e696e6764616d61676501010a66616c6c64616d61676501010a6669726564616d61676501010d6b656570696e76656e746f727901000b6d6f626772696566696e6701010370767001010f73686f77636f6f7264696e617465730100136e61747572616c726567656e65726174696f6e01010b746e746578706c6f64657301011373656e64636f6d6d616e64666565646261636b0101156d6178636f6d6d616e64636861696e6c656e67746802feff070a646f696e736f6d6e6961010114636f6d6d616e64626c6f636b73656e61626c656401010f72616e646f6d7469636b7370656564020212646f696d6d6564696174657265737061776e01001173686f7764656174686d6573736167657301011466756e6374696f6e636f6d6d616e646c696d697402a09c010b737061776e726164697573020a0873686f7774616773010100000000000000020400000000000001000000012a100000001000000000000d426564726f636b206c6576656c0d426564726f636b206c6576656c2430303030303030302d303030302d303030302d303030302d30303030303030303030303000026e5f520000000000e89280c209009207146d696e6563726166743a636f6f6b65645f636f640c0100166d696e6563726166743a7075727075725f626c6f636bc900000d6d696e6563726166743a626f772c0100146d696e6563726166743a656e645f627269636b73ce00000d6d696e6563726166743a61697262ff001c6d696e6563726166743a656e6465726d616e5f737061776e5f656767b80100196d696e6563726166743a6d757369635f646973635f77617264150200106d696e6563726166743a726162626974200100206d696e6563726166743a637265657065725f62616e6e65725f7061747465726e3c0200146d696e6563726166743a656c656d656e745f3235dcff00176d696e6563726166743a6d757368726f6f6d5f73746577040100286d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f736c6162e4fe00196d696e6563726166743a636f6f6b65645f706f726b63686f700701001b6d696e6563726166743a726176616765725f737061776e5f656767eb01001a6d696e6563726166743a73747269707065645f6f616b5f6c6f67f6ff000f6d696e6563726166743a6170706c65010100146d696e6563726166743a656c656d656e745f3530c3ff001a6d696e6563726166743a6d757369635f646973635f63686972700f0200226d696e6563726166743a707269736d6172696e655f627269636b735f737461697273fcff00176d696e6563726166743a636f6f6b65645f726162626974210100146d696e6563726166743a656c656d656e745f3334d3ff00176d696e6563726166743a71756172747a5f627269636b73d0fe00186d696e6563726166743a6974656d2e69726f6e5f646f6f724700000d6d696e6563726166743a636f64080100166d696e6563726166743a676f6c64656e5f6170706c65020100136d696e6563726166743a626f6f6b7368656c662f00001c6d696e6563726166743a676f6c64656e5f686f7273655f61726d6f720a02001e6d696e6563726166743a736d6f6f74685f71756172747a5f73746169727347ff00106d696e6563726166743a706f7461746f180100206d696e6563726166743a656e6368616e7465645f676f6c64656e5f6170706c65030100156d696e6563726166743a6e65746865725f73746172fc0100146d696e6563726166743a656c656d656e745f3135e6ff001c6d696e6563726166743a6974656d2e6461726b5f6f616b5f646f6f72c50000156d696e6563726166743a6c696768745f626c6f636b29ff00226d696e6563726166743a79656c6c6f775f676c617a65645f7465727261636f747461e000001c6d696e6563726166743a73746f6e655f627269636b5f7374616972736d0000106d696e6563726166743a706f7274616c5a0000146d696e6563726166743a676f6c645f696e676f74320100146d696e6563726166743a69726f6e5f696e676f74310100196d696e6563726166743a736c696d655f737061776e5f656767bb01000f6d696e6563726166743a7363757465320200106d696e6563726166743a636f6f6b69650f0100126d696e6563726166743a706f726b63686f70060100176d696e6563726166743a6469616d6f6e645f626c6f636b3900000f6d696e6563726166743a6272656164050100136d696e6563726166743a656c656d656e745f37eeff00166d696e6563726166743a69726f6e5f7069636b6178652901001c6d696e6563726166743a70696c6c616765725f737061776e5f656767e90100146d696e6563726166743a656c656d656e745f3237daff000e6d696e6563726166743a62656566110100196d696e6563726166743a626c617a655f737061776e5f656767c60100106d696e6563726166743a73616c6d6f6e090100226d696e6563726166743a73696c7665725f676c617a65645f7465727261636f747461e40000176d696e6563726166743a74726f706963616c5f666973680a0100156d696e6563726166743a636f636f615f6265616e739a0100156d696e6563726166743a776f6f64656e5f736c61629e0000146d696e6563726166743a656c656d656e745f3136e5ff00126d696e6563726166743a7472697077697265840000136d696e6563726166743a73746f6e655f6178653b01001c6d696e6563726166743a737461696e65645f676c6173735f70616e65a000000f6d696e6563726166743a616e76696c910000176d696e6563726166743a747261707065645f6368657374920000186d696e6563726166743a616e6369656e745f646562726973f1fe00146d696e6563726166743a707566666572666973680b0100106d696e6563726166743a6275636b6574680100176d696e6563726166743a636f6f6b65645f73616c6d6f6e0d0100146d696e6563726166743a656c656d656e745f3631b8ff00126d696e6563726166743a737061726b6c65724d0200156d696e6563726166743a7761727065645f646f6f725d0200146d696e6563726166743a64726965645f6b656c700e0100176d696e6563726166743a62656574726f6f745f736f75701e0100166d696e6563726166743a7265645f6d757368726f6f6d280000186d696e6563726166743a776f6f64656e5f7069636b617865360100176d696e6563726166743a6974656d2e63616d70666972652fff00156d696e6563726166743a6d656c6f6e5f736c696365100100136d696e6563726166743a6861795f626c6f636baa0000176d696e6563726166743a776f6f64656e5f73686f76656c350100186d696e6563726166743a6e617574696c75735f7368656c6c300200136d696e6563726166743a656c656d656e745f31f4ff001b6d696e6563726166743a73746f6e656375747465725f626c6f636b3bff00156d696e6563726166743a636f6f6b65645f62656566120100146d696e6563726166743a636f6d70617261746f72000200106d696e6563726166743a636172726f741701001b6d696e6563726166743a737472696465725f737061776e5f656767ed0100176d696e6563726166743a636f6d6d616e645f626c6f636b890000116d696e6563726166743a636869636b656e130100106d696e6563726166743a706f74696f6ea80100166d696e6563726166743a726f7474656e5f666c657368150100196d696e6563726166743a77697463685f737061776e5f656767c201000e6d696e6563726166743a64697274030000146d696e6563726166743a656c656d656e745f3632b7ff001b6d696e6563726166743a6461796c696768745f6465746563746f72970000146d696e6563726166743a736e6f775f6c617965724e0000156d696e6563726166743a7261626269745f666f6f740602001a6d696e6563726166743a6c696e676572696e675f706f74696f6e280200126d696e6563726166743a63616d7066697265420200106d696e6563726166743a736d6f6b65723aff00166d696e6563726166743a7761727065645f66656e6365fffe00186d696e6563726166743a636f6f6b65645f636869636b656e140100266d696e6563726166743a6c696768745f626c75655f676c617a65645f7465727261636f747461df0000156d696e6563726166743a73746f6e655f73776f7264380100146d696e6563726166743a7370696465725f657965160100196d696e6563726166743a686f7273655f737061776e5f656767c80100166d696e6563726166743a62616b65645f706f7461746f190100176d696e6563726166743a676f6c64656e5f636172726f741b0100176d696e6563726166743a7370727563655f7374616972738600001a6d696e6563726166743a706f69736f6e6f75735f706f7461746f1a0100146d696e6563726166743a656c656d656e745f3133e8ff00126d696e6563726166743a6f6273696469616e310000156d696e6563726166743a70756d706b696e5f7069651c0100196d696e6563726166743a6469616d6f6e645f7069636b6178653e0100116d696e6563726166743a6c616e7465726e30ff00146d696e6563726166743a69726f6e5f73776f7264330100166d696e6563726166743a736d6f6f74685f73746f6e6549ff00126d696e6563726166743a62656574726f6f741d01001a6d696e6563726166743a6d757369635f646973635f7374726164140200146d696e6563726166743a656c656d656e745f3433caff001a6d696e6563726166743a696e76697369626c65626564726f636b5f0000176d696e6563726166743a73776565745f626572726965731f0100156d696e6563726166743a7261626269745f73746577220100156d696e6563726166743a77686561745f73656564732301001b6d696e6563726166743a6974656d2e6372696d736f6e5f646f6f720cff000f6d696e6563726166743a6368657374360000176d696e6563726166743a70756d706b696e5f7365656473240100136d696e6563726166743a656c656d656e745f32f3ff00206d696e6563726166743a636f6d6d616e645f626c6f636b5f6d696e6563617274290200156d696e6563726166743a6d656c6f6e5f7365656473250100136d696e6563726166743a737061776e5f656767660200126d696e6563726166743a69726f6e5f6178652a0100156d696e6563726166743a6e65746865725f77617274260100186d696e6563726166743a62656574726f6f745f7365656473270100146d696e6563726166743a656c656d656e745f3335d2ff00156d696e6563726166743a656c656d656e745f3130348dff00156d696e6563726166743a69726f6e5f73686f76656c280100186d696e6563726166743a6772616e6974655f73746169727357ff00196d696e6563726166743a666c696e745f616e645f737465656c2b01001a6d696e6563726166743a7a6f676c696e5f737061776e5f656767f00100166d696e6563726166743a73746f6e655f73686f76656c390100156d696e6563726166743a6d656c6f6e5f626c6f636b6700000f6d696e6563726166743a6172726f772d01000e6d696e6563726166743a636f616c2e0100216d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c616232b50000126d696e6563726166743a63686172636f616c2f0100196d696e6563726166743a73747261795f737061776e5f656767cc0100116d696e6563726166743a636172726f74738d0000116d696e6563726166743a6469616d6f6e64300100166d696e6563726166743a776f6f64656e5f73776f7264340100196d696e6563726166743a6e65746865726974655f626f6f7473580200196d696e6563726166743a6d757369635f646973635f6d616c6c110200196d696e6563726166743a6461726b5f6f616b5f737461697273a40000146d696e6563726166743a776f6f64656e5f617865370100126d696e6563726166743a6661726d6c616e643c00001a6d696e6563726166743a6372696d736f6e5f74726170646f6f720aff00216d696e6563726166743a7a6f6d6269655f7069676d616e5f737061776e5f656767be0100176d696e6563726166743a73746f6e655f7069636b6178653a0100176d696e6563726166743a73616c6d6f6e5f6275636b65746d0100106d696e6563726166743a706c616e6b730500001a6d696e6563726166743a636861696e6d61696c5f68656c6d6574530100186d696e6563726166743a6469616d6f6e645f73686f76656c3d0100176d696e6563726166743a6469616d6f6e645f73776f72643c0100186d696e6563726166743a736d697468696e675f7461626c6536ff00156d696e6563726166743a6469616d6f6e645f6178653f01000f6d696e6563726166743a737469636b400100176d696e6563726166743a666c6f77696e675f77617465720800000e6d696e6563726166743a626f776c410100166d696e6563726166743a676f6c64656e5f73776f7264420100156d696e6563726166743a686f6e65795f626c6f636b24ff00176d696e6563726166743a676f6c64656e5f73686f76656c430100106d696e6563726166743a656c797472612a02001b6d696e6563726166743a6c69745f72656473746f6e655f6c616d707c0000186d696e6563726166743a676f6c64656e5f7069636b617865440100146d696e6563726166743a676f6c64656e5f617865450100146d696e6563726166743a656c656d656e745f3532c1ff00106d696e6563726166743a737472696e67460100216d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c61623458ff00116d696e6563726166743a66656174686572470100136d696e6563726166743a67756e706f776465724801001e6d696e6563726166743a736b756c6c5f62616e6e65725f7061747465726e3d0200176d696e6563726166743a6163616369615f737461697273a30000146d696e6563726166743a776f6f64656e5f686f65490100196d696e6563726166743a70616e64615f737061776e5f656767e70100136d696e6563726166743a73746f6e655f686f654a0100126d696e6563726166743a69726f6e5f686f654b0100146d696e6563726166743a656c656d656e745f38369fff00156d696e6563726166743a6469616d6f6e645f686f654c0100146d696e6563726166743a676f6c64656e5f686f654d0100156d696e6563726166743a6d6167656e74615f6479659601000f6d696e6563726166743a77686561744e0100186d696e6563726166743a6c6561746865725f68656c6d65744f01001c6d696e6563726166743a6c6561746865725f6368657374706c6174655001001a6d696e6563726166743a6c6561746865725f6c656767696e6773510100206d696e6563726166743a676c6973746572696e675f6d656c6f6e5f736c696365b00100136d696e6563726166743a6c6f646573746f6e6522ff00186d696e6563726166743a62726f776e5f6d757368726f6f6d270000176d696e6563726166743a6c6561746865725f626f6f7473520100156d696e6563726166743a656e645f67617465776179d100001e6d696e6563726166743a636861696e6d61696c5f6368657374706c617465540100176d696e6563726166743a6974656d2e62656574726f6f74f40000156d696e6563726166743a656c656d656e745f31303190ff001c6d696e6563726166743a636861696e6d61696c5f6c656767696e6773550100196d696e6563726166743a636861696e6d61696c5f626f6f7473560100136d696e6563726166743a736f756c5f73616e64580000156d696e6563726166743a69726f6e5f68656c6d6574570100126d696e6563726166743a736e6f7762616c6c740100146d696e6563726166743a656c656d656e745f3439c4ff00196d696e6563726166743a69726f6e5f6368657374706c617465580100106d696e6563726166743a62617272656c35ff00176d696e6563726166743a69726f6e5f6c656767696e6773590100146d696e6563726166743a69726f6e5f626f6f74735a0100216d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c61623359ff00136d696e6563726166743a656e6465725f657965af01001c6d696e6563726166743a6d757369635f646973635f70696773746570600200226d696e6563726166743a737469636b79706973746f6e61726d636f6c6c6973696f6e27ff00176d696e6563726166743a69726f6e5f74726170646f6f72a70000186d696e6563726166743a6469616d6f6e645f68656c6d65745b01001e6d696e6563726166743a73746f6e655f70726573737572655f706c6174654600001c6d696e6563726166743a6469616d6f6e645f6368657374706c6174655c01000e6d696e6563726166743a73616e640c0000276d696e6563726166743a6c696768745f77656967687465645f70726573737572655f706c617465930000106d696e6563726166743a706973746f6e2100001a6d696e6563726166743a6469616d6f6e645f6c656767696e67735d0100146d696e6563726166743a656c656d656e745f3330d7ff00176d696e6563726166743a6469616d6f6e645f626f6f74735e0100176d696e6563726166743a676f6c64656e5f68656c6d65745f0100146d696e6563726166743a656c656d656e745f3531c2ff001c6d696e6563726166743a646f75626c655f776f6f64656e5f736c61629d0000146d696e6563726166743a656c656d656e745f3834a1ff001c6d696e6563726166743a686172645f737461696e65645f676c617373fe00001b6d696e6563726166743a676f6c64656e5f6368657374706c617465600100146d696e6563726166743a7365616c616e7465726ea90000136d696e6563726166743a676c6f7773746f6e65590000196d696e6563726166743a676f6c64656e5f6c656767696e6773610100166d696e6563726166743a676f6c64656e5f626f6f7473620100106d696e6563726166743a736869656c646301001b6d696e6563726166743a6a756e676c655f66656e63655f67617465b90000166d696e6563726166743a666c6f77696e675f6c6176610a0000196d696e6563726166743a6167656e745f737061776e5f656767e50100106d696e6563726166743a636172706574ab00000f6d696e6563726166743a666c696e74640100126d696e6563726166743a7061696e74696e676501001a6d696e6563726166743a68656172745f6f665f7468655f736561310200226d696e6563726166743a6d6f7373795f636f62626c6573746f6e655f7374616972734dff00126d696e6563726166743a6f616b5f7369676e660100196d696e6563726166743a6d757369635f646973635f77616974170200146d696e6563726166743a656c656d656e745f3535beff00156d696e6563726166743a776f6f64656e5f646f6f72670100156d696e6563726166743a6d696c6b5f6275636b6574690100146d696e6563726166743a656c656d656e745f3734abff00166d696e6563726166743a77617465725f6275636b65746a01001b6d696e6563726166743a7368756c6b65725f737061776e5f656767d30100116d696e6563726166743a7265645f6479658a01000e6d696e6563726166743a626f6e659d0100236d696e6563726166743a6d6167656e74615f676c617a65645f7465727261636f747461de0000156d696e6563726166743a6c6176615f6275636b65746b01001e6d696e6563726166743a76696e64696361746f725f737061776e5f656767d80100146d696e6563726166743a636f645f6275636b65746c01001e6d696e6563726166743a74726f706963616c5f666973685f6275636b65746e0100136d696e6563726166743a656c656d656e745f36efff001b6d696e6563726166743a707566666572666973685f6275636b65746f0100196d696e6563726166743a636f6e63726574655f706f77646572ed0000126d696e6563726166743a6d696e6563617274700100106d696e6563726166743a736164646c657101001b6d696e6563726166743a6e65746865725f776172745f626c6f636bd60000156d696e6563726166743a656c656d656e745f31313681ff00176d696e6563726166743a6372696d736f6e5f726f6f747321ff00136d696e6563726166743a69726f6e5f646f6f72720100126d696e6563726166743a72656473746f6e65730100226d696e6563726166743a656c6465725f677561726469616e5f737061776e5f656767d50100126d696e6563726166743a63726f7373626f77350200186d696e6563726166743a616374697661746f725f7261696c7e0000126d696e6563726166743a6f616b5f626f6174750100146d696e6563726166743a656c656d656e745f393794ff00146d696e6563726166743a62697263685f626f6174760100146d696e6563726166743a707269736d6172696e65a80000216d696e6563726166743a706f6c69736865645f6772616e6974655f73746169727354ff00156d696e6563726166743a6a756e676c655f626f61747701001e6d696e6563726166743a73696c766572666973685f737061776e5f656767b90100196d696e6563726166743a6368656d69737472795f7461626c65ee0000156d696e6563726166743a7370727563655f626f6174780100146d696e6563726166743a656c656d656e745f3236dbff00156d696e6563726166743a6163616369615f626f6174790100176d696e6563726166743a6461726b5f6f616b5f626f61747a0100126d696e6563726166743a69726f6e5f6f72650f0000166d696e6563726166743a7772697474656e5f626f6f6bf50100116d696e6563726166743a6c6561746865727b01000e6d696e6563726166743a6b656c707c0100156d696e6563726166743a676f6c645f6e7567676574a701000f6d696e6563726166743a627269636b7d0100136d696e6563726166743a636c61795f62616c6c7e0100146d696e6563726166743a73756761725f63616e657f0100156d696e6563726166743a6c69745f70756d706b696e5b0000196d696e6563726166743a6e65746865726974655f696e676f744f02000f6d696e6563726166743a7061706572800100146d696e6563726166743a656c656d656e745f3233deff000f6d696e6563726166743a636f72616c7dff000e6d696e6563726166743a626f6f6b810100146d696e6563726166743a656e645f706f7274616c770000116d696e6563726166743a74726964656e74180200146d696e6563726166743a736c696d655f62616c6c820100186d696e6563726166743a63686573745f6d696e65636172748301000d6d696e6563726166743a656767840100176d696e6563726166743a636f775f737061776e5f656767b20100196d696e6563726166743a6d757369635f646973635f7374616c130200196d696e6563726166743a6e65746865726974655f73776f7264500200146d696e6563726166743a6974656d2e7265656473530000116d696e6563726166743a636f6d70617373850100186d696e6563726166743a6372696d736f6e5f73746169727302ff00156d696e6563726166743a66697368696e675f726f64860100136d696e6563726166743a726573657276656436ff0000196d696e6563726166743a616e6465736974655f73746169727355ff000f6d696e6563726166743a636c6f636b8701001a6d696e6563726166743a6f63656c6f745f737061776e5f656767c10100176d696e6563726166743a7370727563655f627574746f6e70ff00176d696e6563726166743a7265645f73616e6473746f6e65b30000186d696e6563726166743a676c6f7773746f6e655f64757374880100136d696e6563726166743a626c61636b5f647965890100136d696e6563726166743a677265656e5f6479658b0100156d696e6563726166743a7368756c6b65725f626f78da00000e6d696e6563726166743a64656e79d30000176d696e6563726166743a6265655f737061776e5f656767ec0100136d696e6563726166743a62726f776e5f6479658c0100126d696e6563726166743a626c75655f6479658d01000f6d696e6563726166743a6672616d65f701001b6d696e6563726166743a62726577696e677374616e64626c6f636b750000136d696e6563726166743a6974656d2e63616b655c0000146d696e6563726166743a707572706c655f6479658e01000d6d696e6563726166743a647965640200176d696e6563726166743a6d757369635f646973635f31330c0200126d696e6563726166743a6379616e5f6479658f0100136d696e6563726166743a626c617a655f726f64a50100186d696e6563726166743a6c696768745f677261795f647965900100126d696e6563726166743a677261795f647965910100206d696e6563726166743a7069676c696e5f62727574655f737061776e5f656767f10100146d696e6563726166743a656c656d656e745f3431ccff001a6d696e6563726166743a7261626269745f737061776e5f656767c90100126d696e6563726166743a70696e6b5f647965920100126d696e6563726166743a6c696d655f647965930100146d696e6563726166743a79656c6c6f775f647965940100176d696e6563726166743a626c6173745f6675726e6163653cff00146d696e6563726166743a656c656d656e745f3130ebff00186d696e6563726166743a6c696768745f626c75655f647965950100146d696e6563726166743a747572746c655f65676761ff000d6d696e6563726166743a626564a00100176d696e6563726166743a737461696e65645f676c617373f10000146d696e6563726166743a6f72616e67655f647965970100146d696e6563726166743a656c656d656e745f3134e7ff00136d696e6563726166743a77686974655f647965980100196d696e6563726166743a6974656d2e666c6f7765725f706f748c0000136d696e6563726166743a626f6e655f6d65616c990100176d696e6563726166743a747572746c655f68656c6d6574330200116d696e6563726166743a756e6b6e6f776ecffe00116d696e6563726166743a696e6b5f7361639b01001f6d696e6563726166743a73747269707065645f6372696d736f6e5f7374656d10ff00166d696e6563726166743a6c617069735f6c617a756c699c0100166d696e6563726166743a63686f7275735f6672756974240200106d696e6563726166743a63616d657261460200196d696e6563726166743a737573706963696f75735f737465774302000f6d696e6563726166743a73756761729e01001b6d696e6563726166743a637265657065725f737061776e5f656767b70100126d696e6563726166743a6e616d655f7461671a02000e6d696e6563726166743a63616b659f0100126d696e6563726166743a7265706561746572a10100106d696e6563726166743a626561636f6e8a00001e6d696e6563726166743a6e65746865726974655f6368657374706c617465560200226d696e6563726166743a706f6c69736865645f616e6465736974655f73746169727352ff00146d696e6563726166743a66696c6c65645f6d6170a201001b6d696e6563726166743a64726f776e65645f737061776e5f656767e101001e6d696e6563726166743a756e706f77657265645f636f6d70617261746f72950000106d696e6563726166743a736865617273a30100146d696e6563726166743a656c656d656e745f3331d6ff00156d696e6563726166743a656e6465725f706561726ca401001e6d696e6563726166743a7265645f73616e6473746f6e655f737461697273b40000186d696e6563726166743a6361727665645f70756d706b696e65ff00146d696e6563726166743a67686173745f74656172a60100166d696e6563726166743a676c6173735f626f74746c65a90100176d696e6563726166743a636f6f6b65645f6d7574746f6e1d0200146d696e6563726166743a656c656d656e745f3434c9ff002a6d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f737461697273edfe001f6d696e6563726166743a6a756e676c655f70726573737572655f706c61746567ff001e6d696e6563726166743a6665726d656e7465645f7370696465725f657965aa0100196d696e6563726166743a686f6e6579636f6d625f626c6f636b23ff00166d696e6563726166743a626c617a655f706f77646572ab0100156d696e6563726166743a6d61676d615f637265616dac0100106d696e6563726166743a6a69677361772dff00176d696e6563726166743a62726577696e675f7374616e64ad0100156d696e6563726166743a656c656d656e745f31313186ff00126d696e6563726166743a6361756c64726f6eae01001b6d696e6563726166743a636869636b656e5f737061776e5f656767b10100176d696e6563726166743a7069675f737061776e5f656767b30100196d696e6563726166743a73686565705f737061776e5f656767b401001a6d696e6563726166743a706172726f745f737061776e5f656767dc0100186d696e6563726166743a776f6c665f737061776e5f656767b501001d6d696e6563726166743a6d6f6f7368726f6f6d5f737061776e5f656767b60100146d696e6563726166743a66656e63655f676174656b00001c6d696e6563726166743a736b656c65746f6e5f737061776e5f656767ba01001c6d696e6563726166743a646f75626c655f73746f6e655f736c6162335eff00156d696e6563726166743a627269636b5f626c6f636b2d00001a6d696e6563726166743a7370696465725f737061776e5f656767bc0100106d696e6563726166743a626c656163684902001a6d696e6563726166743a636f6c6f7265645f746f7263685f7267ca00001a6d696e6563726166743a7a6f6d6269655f737061776e5f656767bd0100146d696e6563726166743a656c656d656e745f3231e0ff001c6d696e6563726166743a76696c6c616765725f737061776e5f656767bf0100136d696e6563726166743a636f6d706f737465722bff00196d696e6563726166743a73717569645f737061776e5f656767c001001c6d696e6563726166743a706f77657265645f636f6d70617261746f72960000176d696e6563726166743a6261745f737061776e5f656767c30100196d696e6563726166743a67686173745f737061776e5f656767c40100136d696e6563726166743a656c656d656e745f30240000156d696e6563726166743a6d6f625f737061776e6572340000206d696e6563726166743a63686973656c65645f6e65746865725f627269636b73d2fe001e6d696e6563726166743a6d61676d615f637562655f737061776e5f656767c50100156d696e6563726166743a7761727065645f7369676e5b02000f6d696e6563726166743a636861696e5f0200226d696e6563726166743a7761727065645f66756e6775735f6f6e5f615f737469636b5e02001f6d696e6563726166743a636176655f7370696465725f737061776e5f656767c70100176d696e6563726166743a736f756c5f63616d70666972656202001d6d696e6563726166743a656e6465726d6974655f737061776e5f656767ca01001c6d696e6563726166743a677561726469616e5f737061776e5f656767cb0100176d696e6563726166743a6372696d736f6e5f66656e636500ff00186d696e6563726166743a6875736b5f737061776e5f656767cd01001a6d696e6563726166743a7069676c696e5f737061776e5f656767ef0100176d696e6563726166743a77656570696e675f76696e657319ff00236d696e6563726166743a7769746865725f736b656c65746f6e5f737061776e5f656767ce0100196d696e6563726166743a676c6f77696e676f6273696469616ef60000116d696e6563726166743a6c656176657332a100001a6d696e6563726166743a646f6e6b65795f737061776e5f656767cf0100156d696e6563726166743a7370727563655f7369676e360200146d696e6563726166743a656c656d656e745f3539baff00186d696e6563726166743a6d756c655f737061776e5f656767d00100166d696e6563726166743a646f75626c655f706c616e74af0000156d696e6563726166743a656c656d656e745f31303988ff00226d696e6563726166743a736b656c65746f6e5f686f7273655f737061776e5f656767d101001b6d696e6563726166743a6e65746865726974655f7069636b617865520200116d696e6563726166743a6a756b65626f78540000206d696e6563726166743a7a6f6d6269655f686f7273655f737061776e5f656767d20100176d696e6563726166743a6e70635f737061776e5f656767d40100136d696e6563726166743a69726f6e5f62617273650000146d696e6563726166743a656c656d656e745f3830a5ff001e6d696e6563726166743a706f6c61725f626561725f737061776e5f656767d60100136d696e6563726166743a656e645f73746f6e65790000196d696e6563726166743a6c6c616d615f737061776e5f656767d70100196d696e6563726166743a6974656d2e62697263685f646f6f72c200001a6d696e6563726166743a65766f6b65725f737061776e5f656767d90100176d696e6563726166743a6d757369635f646973635f31311602001a6d696e6563726166743a6c69745f72656473746f6e655f6f72654a0000186d696e6563726166743a6372616674696e675f7461626c653a0000216d696e6563726166743a626c61636b5f676c617a65645f7465727261636f747461eb0000146d696e6563726166743a656c656d656e745f3537bcff001a6d696e6563726166743a7370727563655f77616c6c5f7369676e4aff00176d696e6563726166743a7665785f737061776e5f656767da0100196d696e6563726166743a7761727065645f74726170646f6f7209ff00186d696e6563726166743a7477697374696e675f76696e6573e1fe00246d696e6563726166743a6461796c696768745f6465746563746f725f696e766572746564b20000236d696e6563726166743a7a6f6d6269655f76696c6c616765725f737061776e5f656767db01001a6d696e6563726166743a72617069645f66657274696c697a65724a02000e6d696e6563726166743a636c6179520000216d696e6563726166743a74726f706963616c5f666973685f737061776e5f656767dd0100176d696e6563726166743a7374616e64696e675f7369676e3f0000176d696e6563726166743a636f645f737061776e5f656767de0100146d696e6563726166743a6974656d2e6672616d65c70000186d696e6563726166743a6372696d736f6e5f66756e6775731cff001e6d696e6563726166743a707566666572666973685f737061776e5f656767df01001c6d696e6563726166743a7265645f6d757368726f6f6d5f626c6f636b6400001a6d696e6563726166743a73616c6d6f6e5f737061776e5f656767e00100156d696e6563726166743a7761727065645f736c6162f7fe001c6d696e6563726166743a646f75626c655f73746f6e655f736c616232b600001b6d696e6563726166743a646f6c7068696e5f737061776e5f656767e20100136d696e6563726166743a656c656d656e745f39ecff001a6d696e6563726166743a747572746c655f737061776e5f656767e301001b6d696e6563726166743a7068616e746f6d5f737061776e5f656767e40100146d696e6563726166743a656c656d656e745f3238d9ff001a6d696e6563726166743a6974656d2e6163616369615f646f6f72c40000176d696e6563726166743a6361745f737061776e5f656767e60100176d696e6563726166743a666f785f737061776e5f656767e801001a6d696e6563726166743a636f62626c6573746f6e655f77616c6c8b0000106d696e6563726166743a71756172747a0202001b6d696e6563726166743a636172726f745f6f6e5f615f737469636bfb0100246d696e6563726166743a77616e646572696e675f7472616465725f737061776e5f656767ea0100126d696e6563726166743a74726170646f6f726000001a6d696e6563726166743a686f676c696e5f737061776e5f656767ee01001b6d696e6563726166743a657870657269656e63655f626f74746c65f20100196d696e6563726166743a6a756e676c655f74726170646f6f726cff00156d696e6563726166743a666972655f636861726765f30100146d696e6563726166743a656c656d656e745f3639b0ff00176d696e6563726166743a7772697461626c655f626f6f6bf40100116d696e6563726166743a656d6572616c64f60100146d696e6563726166743a666c6f7765725f706f74f80100106d696e6563726166743a6c6561766573120000136d696e6563726166743a656d7074795f6d6170f901000f6d696e6563726166743a736b756c6cfa0100186d696e6563726166743a6372696d736f6e5f6e796c69756d18ff00196d696e6563726166743a66697265776f726b5f726f636b6574fd0100156d696e6563726166743a656c656d656e745f3130328fff00176d696e6563726166743a66697265776f726b5f73746172fe01001a6d696e6563726166743a636f6c6f7265645f746f7263685f6270cc0000186d696e6563726166743a656e6368616e7465645f626f6f6bff01001a6d696e6563726166743a746f74656d5f6f665f756e6479696e672e0200156d696e6563726166743a6e6574686572627269636b010200166d696e6563726166743a746e745f6d696e6563617274030200146d696e6563726166743a656c656d656e745f3633b6ff00196d696e6563726166743a686f707065725f6d696e6563617274040200176d696e6563726166743a647261676f6e5f627265617468260200156d696e6563726166743a636f62626c6573746f6e65040000106d696e6563726166743a686f70706572050200156d696e6563726166743a7261626269745f686964650702001d6d696e6563726166743a6c6561746865725f686f7273655f61726d6f720802001a6d696e6563726166743a69726f6e5f686f7273655f61726d6f720902001d6d696e6563726166743a6469616d6f6e645f686f7273655f61726d6f720b0200186d696e6563726166743a6d757369635f646973635f6361740d0200156d696e6563726166743a6a756e676c655f646f6f722102001b6d696e6563726166743a6d757369635f646973635f626c6f636b730e0200136d696e6563726166743a73616e6473746f6e65180000176d696e6563726166743a776f6f64656e5f627574746f6e8f0000186d696e6563726166743a6d757369635f646973635f6661721002001c6d696e6563726166743a6d757369635f646973635f6d656c6c6f6869120200166d696e6563726166743a696e666f5f75706461746532f900000e6d696e6563726166743a6c6561641902001d6d696e6563726166743a707269736d6172696e655f6372797374616c731b0200156d696e6563726166743a6163616369615f7369676e390200106d696e6563726166743a6d7574746f6e1c0200146d696e6563726166743a656c656d656e745f3332d5ff00126d696e6563726166743a636f616c5f6f7265100000156d696e6563726166743a61726d6f725f7374616e641e0200156d696e6563726166743a7370727563655f646f6f721f02001a6d696e6563726166743a7068616e746f6d5f6d656d6272616e65340200146d696e6563726166743a62697263685f646f6f72200200156d696e6563726166743a6163616369615f646f6f72220200146d696e6563726166743a656c656d656e745f3432cbff00176d696e6563726166743a6461726b5f6f616b5f646f6f722302001c6d696e6563726166743a6e65746865726974655f6c656767696e67735702001d6d696e6563726166743a706f707065645f63686f7275735f6672756974250200146d696e6563726166743a656c656d656e745f3733acff00176d696e6563726166743a73706c6173685f706f74696f6e270200216d696e6563726166743a6461726b5f6f616b5f70726573737572655f706c61746568ff001a6d696e6563726166743a707269736d6172696e655f73686172642b0200126d696e6563726166743a73656167726173737eff00176d696e6563726166743a7368756c6b65725f7368656c6c2c0200186d696e6563726166743a72656473746f6e655f626c6f636b980000106d696e6563726166743a62616e6e65722d0200156d696e6563726166743a69726f6e5f6e75676765742f0200146d696e6563726166743a656c656d656e745f3338cfff00196d696e6563726166743a636f72616c5f66616e5f68616e673278ff00146d696e6563726166743a62697263685f7369676e370200186d696e6563726166743a636f72616c5f66616e5f646561647aff00116d696e6563726166743a62616c6c6f6f6e4b0200156d696e6563726166743a6a756e676c655f7369676e380200176d696e6563726166743a6461726b5f6f616b5f7369676e3a02001f6d696e6563726166743a666c6f7765725f62616e6e65725f7061747465726e3b0200216d696e6563726166743a706f6c69736865645f64696f726974655f73746169727353ff001f6d696e6563726166743a6d6f6a616e675f62616e6e65725f7061747465726e3e0200156d696e6563726166743a6d6f6e737465725f656767610000266d696e6563726166743a6669656c645f6d61736f6e65645f62616e6e65725f7061747465726e3f02000e6d696e6563726166743a62656c6c32ff00296d696e6563726166743a626f72647572655f696e64656e7465645f62616e6e65725f7061747465726e400200126d696e6563726166743a706f7461746f65738e00001f6d696e6563726166743a7069676c696e5f62616e6e65725f7061747465726e410200146d696e6563726166743a656c656d656e745f3738a7ff00136d696e6563726166743a686f6e6579636f6d624402001a6d696e6563726166743a7265645f6e65746865725f627269636bd70000166d696e6563726166743a686f6e65795f626f74746c65450200126d696e6563726166743a636f6d706f756e64470200126d696e6563726166743a6963655f626f6d62480200126d696e6563726166743a6d65646963696e654c0200176d696e6563726166743a7761727065645f66756e6775731bff00146d696e6563726166743a656c656d656e745f393299ff001a6d696e6563726166743a656e645f706f7274616c5f6672616d65780000146d696e6563726166743a676c6f775f737469636ba60000126d696e6563726166743a626c75655f696365f5ff00146d696e6563726166743a656c656d656e745f3833a2ff001b6d696e6563726166743a6c6f646573746f6e655f636f6d706173734e0200146d696e6563726166743a71756172747a5f6f72659900001a6d696e6563726166743a6e65746865726974655f73686f76656c5102001d6d696e6563726166743a636861696e5f636f6d6d616e645f626c6f636bbd00000e6d696e6563726166743a6c6f6f6d34ff001a6d696e6563726166743a6974656d2e7761727065645f646f6f720bff00176d696e6563726166743a6e65746865726974655f617865530200176d696e6563726166743a6e65746865726974655f686f655402001a6d696e6563726166743a6e65746865726974655f68656c6d6574550200196d696e6563726166743a6e65746865726974655f7363726170590200166d696e6563726166743a6372696d736f6e5f7369676e5a0200126d696e6563726166743a636f6e6372657465ec0000166d696e6563726166743a6372696d736f6e5f646f6f725c0200106d696e6563726166743a73706f6e6765130000186d696e6563726166743a6e65746865725f7370726f7574736102001b6d696e6563726166743a636172746f6772617068795f7461626c6538ff00196d696e6563726166743a626c61636b73746f6e655f736c6162e6fe00226d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f736c6162dbfe000f6d696e6563726166743a73746f6e650100000e6d696e6563726166743a776f6f6c230000176d696e6563726166743a79656c6c6f775f666c6f7765722500001f6d696e6563726166743a737461696e65645f68617264656e65645f636c61799f00000d6d696e6563726166743a6c6f671100000f6d696e6563726166743a66656e6365550000146d696e6563726166743a656c656d656e745f3533c0ff00146d696e6563726166743a73746f6e65627269636b6200001b6d696e6563726166743a6c69745f626c6173745f6675726e6163652aff00156d696e6563726166743a636f72616c5f626c6f636b7cff00246d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b73eefe00156d696e6563726166743a656c656d656e745f31303091ff001b6d696e6563726166743a646f75626c655f73746f6e655f736c61622c00000e6d696e6563726166743a7261696c4200001c6d696e6563726166743a646f75626c655f73746f6e655f736c6162345aff001d6d696e6563726166743a73747269707065645f6163616369615f6c6f67f8ff00206d696e6563726166743a7265616c5f646f75626c655f73746f6e655f736c61622b0000136d696e6563726166743a636f72616c5f66616e7bff00246d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627574746f6ed8fe00146d696e6563726166743a7365615f7069636b6c6564ff00296d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f646f75626c655f736c6162dafe00116d696e6563726166743a7361706c696e67060000166d696e6563726166743a7761727065645f726f6f747320ff00146d696e6563726166743a656c656d656e745f3131eaff00146d696e6563726166743a7265645f666c6f776572260000136d696e6563726166743a77617465726c696c796f0000166d696e6563726166743a71756172747a5f626c6f636b9b0000136d696e6563726166743a736f756c5f736f696c14ff001f6d696e6563726166743a6163616369615f70726573737572655f706c6174656aff00136d696e6563726166743a74616c6c67726173731f0000156d696e6563726166743a656c656d656e745f3130338eff001e6d696e6563726166743a62726f776e5f6d757368726f6f6d5f626c6f636b6300000e6d696e6563726166743a6c6f6732a20000116d696e6563726166743a636f6e6475697463ff000f6d696e6563726166743a6d61676d61d50000146d696e6563726166743a656c656d656e745f3232dfff001c6d696e6563726166743a756e647965645f7368756c6b65725f626f78cd00001e6d696e6563726166743a7370727563655f7374616e64696e675f7369676e4bff00176d696e6563726166743a737469636b795f706973746f6e1d0000106d696e6563726166743a62616d626f6f5dff00126d696e6563726166743a6f62736572766572fb0000156d696e6563726166743a73636166666f6c64696e675bff00146d696e6563726166743a6772696e6473746f6e653dff00116d696e6563726166743a656e645f726f64d00000196d696e6563726166743a666c65746368696e675f7461626c6537ff00156d696e6563726166743a6974656d2e686f707065729a00000e6d696e6563726166743a776f6f642cff000d6d696e6563726166743a746e742e0000216d696e6563726166743a686172645f737461696e65645f676c6173735f70616e65bf00000f6d696e6563726166743a736c696d65a50000116d696e6563726166743a70756d706b696e560000166d696e6563726166743a6372696d736f6e5f736c6162f8fe00136d696e6563726166743a656c656d656e745f33f2ff00136d696e6563726166743a656c656d656e745f34f1ff00156d696e6563726166743a656e6465725f6368657374820000136d696e6563726166743a656c656d656e745f35f0ff00136d696e6563726166743a656c656d656e745f38edff00146d696e6563726166743a656c656d656e745f3132e9ff00146d696e6563726166743a656c656d656e745f3137e4ff00146d696e6563726166743a656c656d656e745f3138e3ff00146d696e6563726166743a656c656d656e745f3139e2ff00146d696e6563726166743a656c656d656e745f3230e1ff00146d696e6563726166743a656c656d656e745f3234ddff00146d696e6563726166743a656c656d656e745f3239d8ff00146d696e6563726166743a656c656d656e745f3333d4ff00146d696e6563726166743a656c656d656e745f3336d1ff000d6d696e6563726166743a6963654f0000146d696e6563726166743a656c656d656e745f3337d0ff00146d696e6563726166743a656c656d656e745f3339ceff00146d696e6563726166743a656c656d656e745f3430cdff00146d696e6563726166743a656c656d656e745f3435c8ff00146d696e6563726166743a656c656d656e745f3436c7ff00146d696e6563726166743a656c656d656e745f3437c6ff00146d696e6563726166743a656c656d656e745f3438c5ff00146d696e6563726166743a656c656d656e745f3534bfff00146d696e6563726166743a656c656d656e745f3536bdff00146d696e6563726166743a656c656d656e745f3538bbff00146d696e6563726166743a656c656d656e745f3630b9ff00146d696e6563726166743a656c656d656e745f3634b5ff00146d696e6563726166743a656c656d656e745f3635b4ff00146d696e6563726166743a656c656d656e745f3636b3ff00146d696e6563726166743a656c656d656e745f3637b2ff00146d696e6563726166743a656c656d656e745f3638b1ff00146d696e6563726166743a656c656d656e745f3730afff00146d696e6563726166743a656c656d656e745f3731aeff00146d696e6563726166743a656c656d656e745f3732adff00146d696e6563726166743a656c656d656e745f3735aaff00146d696e6563726166743a656c656d656e745f3736a9ff00196d696e6563726166743a6461726b5f6f616b5f627574746f6e72ff00146d696e6563726166743a656c656d656e745f3737a8ff00186d696e6563726166743a72656473746f6e655f746f7263684c0000186d696e6563726166743a64696f726974655f73746169727356ff00146d696e6563726166743a656c656d656e745f3739a6ff00146d696e6563726166743a656c656d656e745f3831a4ff00146d696e6563726166743a656c656d656e745f3832a3ff00226d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f77616c6cd7fe00146d696e6563726166743a656c656d656e745f3835a0ff00146d696e6563726166743a656c656d656e745f38379eff00146d696e6563726166743a656c656d656e745f38389dff00146d696e6563726166743a656c656d656e745f38399cff00146d696e6563726166743a656c656d656e745f39309bff00146d696e6563726166743a656c656d656e745f39319aff00146d696e6563726166743a656c656d656e745f393398ff00146d696e6563726166743a656c656d656e745f393497ff00146d696e6563726166743a656c656d656e745f393596ff00146d696e6563726166743a656c656d656e745f393695ff00146d696e6563726166743a656c656d656e745f393893ff00106d696e6563726166743a636163747573510000146d696e6563726166743a656c656d656e745f393992ff00156d696e6563726166743a656c656d656e745f3130358cff00156d696e6563726166743a656c656d656e745f3130368bff00206d696e6563726166743a6379616e5f676c617a65645f7465727261636f747461e50000156d696e6563726166743a656c656d656e745f3130378aff00156d696e6563726166743a656c656d656e745f31303889ff00156d696e6563726166743a656c656d656e745f31313087ff00156d696e6563726166743a656c656d656e745f31313285ff00176d696e6563726166743a7761727065645f627574746f6efbfe00156d696e6563726166743a656c656d656e745f31313384ff00166d696e6563726166743a62697263685f737461697273870000156d696e6563726166743a656c656d656e745f31313483ff001d6d696e6563726166743a6461726b5f6f616b5f66656e63655f67617465ba0000156d696e6563726166743a656c656d656e745f31313582ff00156d696e6563726166743a656c656d656e745f31313780ff00156d696e6563726166743a656c656d656e745f3131387fff00196d696e6563726166743a6e65746865726974655f626c6f636bf2fe00186d696e6563726166743a7265737061776e5f616e63686f72f0fe00196d696e6563726166743a637279696e675f6f6273696469616edffe000e6d696e6563726166743a626f6174630200186d696e6563726166743a62616e6e65725f7061747465726e650200156d696e6563726166743a656e645f6372797374616c6702000e6d696e6563726166743a736e6f77500000176d696e6563726166743a6465746563746f725f7261696c1c0000176d696e6563726166743a6163616369615f627574746f6e74ff00176d696e6563726166743a71756172747a5f7374616972739c00001b6d696e6563726166743a6163616369615f66656e63655f67617465bb00001e6d696e6563726166743a6163616369615f7374616e64696e675f7369676e42ff00196d696e6563726166743a6163616369615f74726170646f6f726fff00176d696e6563726166743a7075727075725f737461697273cb00001a6d696e6563726166743a6163616369615f77616c6c5f7369676e41ff000f6d696e6563726166743a616c6c6f77d20000196d696e6563726166743a7374616e64696e675f62616e6e6572b00000186d696e6563726166743a62616d626f6f5f7361706c696e675cff00156d696e6563726166743a66726f737465645f696365cf0000116d696e6563726166743a626172726965725fff00106d696e6563726166743a626173616c7416ff00126d696e6563726166743a6974656d2e6265641a0000116d696e6563726166743a626564726f636b070000126d696e6563726166743a6265655f6e65737426ff00116d696e6563726166743a6265656869766525ff00166d696e6563726166743a62697263685f627574746f6e73ff001a6d696e6563726166743a62697263685f66656e63655f67617465b800001e6d696e6563726166743a62697263685f70726573737572655f706c61746569ff00266d696e6563726166743a63686973656c65645f706f6c69736865645f626c61636b73746f6e65e9fe001d6d696e6563726166743a62697263685f7374616e64696e675f7369676e46ff00186d696e6563726166743a62697263685f74726170646f6f726eff00196d696e6563726166743a62697263685f77616c6c5f7369676e45ff00176d696e6563726166743a63686f7275735f666c6f776572c80000146d696e6563726166743a626c61636b73746f6e65effe00106d696e6563726166743a74617267657411ff00206d696e6563726166743a626c61636b73746f6e655f646f75626c655f736c6162e5fe001a6d696e6563726166743a64726965645f6b656c705f626c6f636b75ff001b6d696e6563726166743a626c61636b73746f6e655f737461697273ecfe00196d696e6563726166743a626c61636b73746f6e655f77616c6cebfe00206d696e6563726166743a626c75655f676c617a65645f7465727261636f747461e70000146d696e6563726166743a626f6e655f626c6f636bd80000166d696e6563726166743a626f726465725f626c6f636bd40000136d696e6563726166743a77616c6c5f7369676e440000226d696e6563726166743a6f72616e67655f676c617a65645f7465727261636f747461dd0000166d696e6563726166743a627269636b5f7374616972736c0000216d696e6563726166743a62726f776e5f676c617a65645f7465727261636f747461e80000176d696e6563726166743a627562626c655f636f6c756d6e60ff00156d696e6563726166743a6974656d2e63616d657261f20000176d696e6563726166743a6974656d2e6361756c64726f6e760000146d696e6563726166743a6974656d2e636861696ee2fe00176d696e6563726166743a6368656d6963616c5f68656174c00000146d696e6563726166743a676f6c645f626c6f636b290000166d696e6563726166743a63686f7275735f706c616e74f00000146d696e6563726166743a636f616c5f626c6f636bad00000f6d696e6563726166743a636f636f617f0000146d696e6563726166743a7061636b65645f696365ae0000186d696e6563726166743a636f72616c5f66616e5f68616e6779ff00196d696e6563726166743a636f72616c5f66616e5f68616e673377ff001f6d696e6563726166743a637261636b65645f6e65746865725f627269636b73d1fe002c6d696e6563726166743a637261636b65645f706f6c69736865645f626c61636b73746f6e655f627269636b73e8fe00186d696e6563726166743a6372696d736f6e5f627574746f6efcfe001d6d696e6563726166743a6372696d736f6e5f646f75626c655f736c6162f6fe001c6d696e6563726166743a6372696d736f6e5f66656e63655f67617465fefe00186d696e6563726166743a6372696d736f6e5f687970686165d5fe00156d696e6563726166743a656d6572616c645f6f7265810000186d696e6563726166743a6372696d736f6e5f706c616e6b730eff001b6d696e6563726166743a7370727563655f66656e63655f67617465b70000206d696e6563726166743a6372696d736f6e5f70726573737572655f706c617465fafe001f6d696e6563726166743a6372696d736f6e5f7374616e64696e675f7369676e06ff00166d696e6563726166743a6372696d736f6e5f7374656d1fff001b6d696e6563726166743a6372696d736f6e5f77616c6c5f7369676e04ff001b6d696e6563726166743a6461726b5f6f616b5f74726170646f6f726dff00206d696e6563726166743a6461726b5f707269736d6172696e655f737461697273fdff001f6d696e6563726166743a6461726b6f616b5f7374616e64696e675f7369676e40ff001b6d696e6563726166743a6461726b6f616b5f77616c6c5f7369676e3fff00126d696e6563726166743a6465616462757368200000156d696e6563726166743a6469616d6f6e645f6f7265380000136d696e6563726166743a64697370656e736572170000176d696e6563726166743a6c6176615f6361756c64726f6e2eff00146d696e6563726166743a647261676f6e5f6567677a0000176d696e6563726166743a6a756e676c655f737461697273880000116d696e6563726166743a64726f707065727d0000176d696e6563726166743a656d6572616c645f626c6f636b8500001a6d696e6563726166743a656e6368616e74696e675f7461626c657400001a6d696e6563726166743a656e645f627269636b5f7374616972734eff000e6d696e6563726166743a66697265330000116d696e6563726166743a6675726e6163653d00001b6d696e6563726166743a67696c6465645f626c61636b73746f6e65e7fe000f6d696e6563726166743a676c617373140000146d696e6563726166743a676c6173735f70616e65660000126d696e6563726166743a676f6c645f6f72650e0000156d696e6563726166743a676f6c64656e5f7261696c1b00000f6d696e6563726166743a6772617373020000146d696e6563726166743a67726173735f70617468c60000106d696e6563726166743a67726176656c0d0000206d696e6563726166743a677261795f676c617a65645f7465727261636f747461e30000216d696e6563726166743a677265656e5f676c617a65645f7465727261636f747461e90000146d696e6563726166743a686172645f676c617373fd0000196d696e6563726166743a686172645f676c6173735f70616e65be0000176d696e6563726166743a68617264656e65645f636c6179ac0000276d696e6563726166743a68656176795f77656967687465645f70726573737572655f706c617465940000156d696e6563726166743a696e666f5f757064617465f80000146d696e6563726166743a69726f6e5f626c6f636b2a0000176d696e6563726166743a6a756e676c655f627574746f6e71ff001a6d696e6563726166743a6974656d2e6a756e676c655f646f6f72c300001e6d696e6563726166743a6a756e676c655f7374616e64696e675f7369676e44ff00156d696e6563726166743a6c69745f6675726e6163653e00001a6d696e6563726166743a6a756e676c655f77616c6c5f7369676e43ff00136d696e6563726166743a6974656d2e6b656c7076ff001e6d696e6563726166743a756e6c69745f72656473746f6e655f746f7263684b0000106d696e6563726166743a6c6164646572410000156d696e6563726166743a6c617069735f626c6f636b160000136d696e6563726166743a6c617069735f6f72651500000e6d696e6563726166743a6c6176610b0000116d696e6563726166743a6c65637465726e3eff001b6d696e6563726166743a6d6f7373795f636f62626c6573746f6e653000000f6d696e6563726166743a6c65766572450000206d696e6563726166743a6c696d655f676c617a65645f7465727261636f747461e10000146d696e6563726166743a6c69745f736d6f6b657239ff00146d696e6563726166743a6d656c6f6e5f7374656d6900001d6d696e6563726166743a6974656d2e6e65746865725f7370726f75747312ff00226d696e6563726166743a6d6f7373795f73746f6e655f627269636b5f73746169727351ff00156d696e6563726166743a6d6f76696e67626c6f636bfa0000126d696e6563726166743a6d7963656c69756d6e0000166d696e6563726166743a6e65746865725f627269636b7000001c6d696e6563726166743a6e65746865725f627269636b5f66656e63657100001d6d696e6563726166743a6e65746865725f627269636b5f737461697273720000196d696e6563726166743a6e65746865725f676f6c645f6f7265e0fe001a6d696e6563726166743a6974656d2e6e65746865725f77617274730000146d696e6563726166743a6e65746865727261636b570000176d696e6563726166743a6e657468657272656163746f72f700001d6d696e6563726166743a6e6f726d616c5f73746f6e655f7374616972734cff00136d696e6563726166743a6e6f7465626c6f636b1900001a6d696e6563726166743a7761727065645f77616c6c5f7369676e03ff00146d696e6563726166743a6f616b5f737461697273350000206d696e6563726166743a70696e6b5f676c617a65645f7465727261636f747461e200001c6d696e6563726166743a706973746f6e61726d636f6c6c6973696f6e220000106d696e6563726166743a706f647a6f6cf30000196d696e6563726166743a706f6c69736865645f626173616c7415ff001d6d696e6563726166743a706f6c69736865645f626c61636b73746f6e65ddfe002f6d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f646f75626c655f736c6162e3fe001e6d696e6563726166743a7761727065645f7374616e64696e675f7369676e05ff00286d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f627269636b5f77616c6ceafe002c6d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f70726573737572655f706c617465d9fe00246d696e6563726166743a706f6c69736865645f626c61636b73746f6e655f737461697273dcfe001a6d696e6563726166743a706f77657265645f72657065617465725e00001b6d696e6563726166743a707269736d6172696e655f737461697273feff00166d696e6563726166743a70756d706b696e5f7374656d680000226d696e6563726166743a707572706c655f676c617a65645f7465727261636f747461db00001f6d696e6563726166743a7265645f676c617a65645f7465727261636f747461ea0000216d696e6563726166743a7265645f6e65746865725f627269636b5f73746169727348ff00176d696e6563726166743a72656473746f6e655f6c616d707b0000166d696e6563726166743a72656473746f6e655f6f7265490000176d696e6563726166743a72656473746f6e655f77697265370000216d696e6563726166743a726570656174696e675f636f6d6d616e645f626c6f636bbc00001a6d696e6563726166743a73616e6473746f6e655f737461697273800000156d696e6563726166743a7368726f6f6d6c696768741aff00146d696e6563726166743a6974656d2e736b756c6c900000256d696e6563726166743a736d6f6f74685f7265645f73616e6473746f6e655f73746169727350ff00216d696e6563726166743a736d6f6f74685f73616e6473746f6e655f7374616972734fff001c6d696e6563726166743a6974656d2e736f756c5f63616d7066697265defe00136d696e6563726166743a736f756c5f6669726513ff00166d696e6563726166743a736f756c5f6c616e7465726ef3fe00146d696e6563726166743a736f756c5f746f726368f4fe00146d696e6563726166743a6974656d2e77686561743b00001a6d696e6563726166743a6974656d2e7370727563655f646f6f72c100001f6d696e6563726166743a7370727563655f70726573737572655f706c61746566ff00196d696e6563726166743a7370727563655f74726170646f6f726bff00166d696e6563726166743a73746f6e655f627574746f6e4d0000166d696e6563726166743a73746f6e655f737461697273430000156d696e6563726166743a73746f6e65637574746572f500001c6d696e6563726166743a73747269707065645f62697263685f6c6f67faff00216d696e6563726166743a73747269707065645f6372696d736f6e5f687970686165d4fe001f6d696e6563726166743a73747269707065645f6461726b5f6f616b5f6c6f67f7ff001d6d696e6563726166743a73747269707065645f6a756e676c655f6c6f67f9ff001d6d696e6563726166743a73747269707065645f7370727563655f6c6f67fbff00206d696e6563726166743a73747269707065645f7761727065645f687970686165d3fe001e6d696e6563726166743a73747269707065645f7761727065645f7374656d0fff00196d696e6563726166743a7374727563747572655f626c6f636bfc0000186d696e6563726166743a7374727563747572655f766f6964d900001a6d696e6563726166743a73776565745f62657272795f6275736831ff000f6d696e6563726166743a746f726368320000176d696e6563726166743a74726970776972655f686f6f6b8300001a6d696e6563726166743a756e64657277617465725f746f726368ef00001c6d696e6563726166743a756e706f77657265645f72657065617465725d00001b6d696e6563726166743a7761727065645f776172745f626c6f636b1dff000e6d696e6563726166743a76696e656a0000156d696e6563726166743a77616c6c5f62616e6e6572b100001c6d696e6563726166743a7761727065645f646f75626c655f736c6162f5fe001b6d696e6563726166743a7761727065645f66656e63655f67617465fdfe00176d696e6563726166743a7761727065645f687970686165d6fe00176d696e6563726166743a7761727065645f6e796c69756d17ff00176d696e6563726166743a7761727065645f706c616e6b730dff001f6d696e6563726166743a7761727065645f70726573737572655f706c617465f9fe00176d696e6563726166743a7761727065645f73746169727301ff00156d696e6563726166743a7761727065645f7374656d1eff000f6d696e6563726166743a77617465720900000d6d696e6563726166743a7765621e0000216d696e6563726166743a77686974655f676c617a65645f7465727261636f747461dc00001f6d696e6563726166743a776f6f64656e5f70726573737572655f706c617465480000156d696e6563726166743a7769746865725f726f736528ff001a6d696e6563726166743a6974656d2e776f6f64656e5f646f6f724000002465303438386162302d333234362d346133372d386238332d38626435616239623433366601' - const buf = Buffer.from(s, 'hex') - const des = read(buf) - console.log(des.data.name) - const newBuf = write(des.data.name, des.data.params) - console.log(newBuf) - console.assert(newBuf.toString('hex')==s) - // console.log(serialize(des.data.params, 2)) - } - - async function testAdventureSettings() { - // const buf = Buffer.from('3720009f02010001000000fdffffff') - // const des = read(buf) - // console.log(serialize(des.data.params, 2)) - - const buf = write('adventure_settings', { - flags: { - world_immutable: true, - no_pvp: true - }, - command_permission: 'normal', - action_permissions: { - open_containers: true - }, - permission_level: 'member', - custom_stored_permissions: 0, - user_id: 0 - }) - const des = read(buf) - // fs.writeFileSync('cc.json', serialize(des.data.params, 2)) - console.log('Des', JSON.stringify(des, null, 2)) - } - - async function testInventory() { - const buf = Buffer.from('1e00020000008c0a419e0104060031bb2144723d8342aff19b420000403f0079873e8047513f8833', 'hex') - const des = read(buf) - console.log(JSON.stringify(des)) - } - - async function testInventory() { - const buf = Buffer.from('1e00020000008c0a419e0104060031bb2144723d8342aff19b420000403f0079873e8047513f8833', 'hex') - - } - - function testLevelEventGeneric() { - const s = '7cce1f0305436f756e74800205084469725363616c65cdcc4c3e0504456e647800a01c440504456e647900001a420504456e647a00008942050653746172747899ef1944050653746172747900002042050653746172747a4583a042050a566172696174696f6e789a99193f050a566172696174696f6e799a99394000' - const buf = Buffer.from(s, 'hex') - const des = read(buf) - console.log(JSON.stringify(des)) - - console.log(des.data.name) - const newBuf = write(des.data.name, des.data.params) - console.log(newBuf.toString('hex'), s) - console.assert(newBuf.toString('hex')==s) - } - - function testEvent() { - const s = '41fdffffff5f2801001203e1417678933fdf294642a034a03e57b65b40' - const buf = Buffer.from(s, 'hex') - const des = read(buf) - console.log(serialize(des)) - - console.log(des.data.name) - const newBuf = write(des.data.name, des.data.params) - console.log(newBuf.toString('hex'), s) - console.assert(newBuf.toString('hex')==s) - } - - function testItemStackReq() { - const s = '93010105030b9d050e01920502000000000100013b32053a000000' - const buf = Buffer.from(s, 'hex') - const des = read(buf) - console.log(serialize(des)) - - console.log(des.data.name) - const newBuf = write(des.data.name, des.data.params) - console.log(newBuf.toString('hex'), 'OLD:', s) - console.assert(newBuf.toString('hex')==s) - } - - // creativeTst() - // availableCommands() - // avaliableCmd() - // creativeTestNew() - // biomeDefinitions() - // startGame() - // testLevelEventGeneric() - testItemStackReq() -} - -if (!module.parent) { - test() -} - -function serialize(obj = {}, fmt) { - return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) -} \ No newline at end of file diff --git a/test/vanilla.test.js b/test/vanilla.test.js index d820a5b..252de3b 100644 --- a/test/vanilla.test.js +++ b/test/vanilla.test.js @@ -3,7 +3,7 @@ const { clientTest } = require('./vanilla') const { Versions } = require('../src/options') -describe ('vanilla server test', function () { +describe('vanilla server test', function () { this.timeout(120 * 1000) for (const version in Versions) { @@ -11,4 +11,4 @@ describe ('vanilla server test', function () { await clientTest(version) }) } -}) \ No newline at end of file +}) From cf6471f6eb0db16f097aa1751faba1916f1e9421 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 23 Mar 2021 03:35:38 -0400 Subject: [PATCH 135/458] Add packet dumper, configuable vanilla server, client events --- src/client.js | 18 ++------ tools/genPacketDumps.js | 83 +++++++++++++++++++++++++++++++++++++ tools/startVanillaServer.js | 30 +++++++++----- 3 files changed, 105 insertions(+), 26 deletions(-) create mode 100644 tools/genPacketDumps.js diff --git a/src/client.js b/src/client.js index 47c5a60..b270c2c 100644 --- a/src/client.js +++ b/src/client.js @@ -108,10 +108,8 @@ class Client extends Connection { } onDisconnectRequest (packet) { - // We're talking over UDP, so there is no connection to close, instead - // we stop communicating with the server console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) - process.exit(1) // TODO: handle + this.emit('kick', packet) } onPlayStatus (statusPacket) { @@ -125,6 +123,7 @@ class Client extends Connection { } close () { + this.emit('close') clearInterval(this.loop) clearTimeout(this.connectTimeout) this.q = [] @@ -155,22 +154,13 @@ class Client extends Connection { const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100) */) + this.emit('packet', pakData) if (debugging) { // Packet verifying (decode + re-encode + match test) if (pakData.name) { this.tryRencode(pakData.name, pakData.params, packet) } - - // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) - // Packet dumping - try { - const root = __dirname + `../data/${this.options.version}/sample/` - if (!fs.existsSync(root + `packets/${pakData.name}.json`)) { - fs.writeFileSync(root + `packets/${pakData.name}.json`, serialize(pakData.params, 2)) - fs.writeFileSync(root + `packets/${pakData.name}.txt`, packet.toString('hex')) - } - } catch { } } // Abstract some boilerplate before sending to listeners @@ -187,8 +177,6 @@ class Client extends Connection { case 'play_status': this.onPlayStatus(pakData.params) break - default: - // console.log('Sending to listeners') } // Emit packet diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js new file mode 100644 index 0000000..dd74150 --- /dev/null +++ b/tools/genPacketDumps.js @@ -0,0 +1,83 @@ +/* eslint-disable */ +// Collect sample packets needed for `serverTest.js` +// process.env.DEBUG = 'minecraft-protocol' +const fs = require('fs') +const vanillaServer = require('../tools/startVanillaServer') +const { Client } = require('../src/client') +const { serialize, waitFor } = require('../src/datatypes/util') +const { CURRENT_VERSION } = require('../src/options') +const { join } = require('path') + +let loop + +async function main() { + const random = ((Math.random() * 100) | 0) + const port = 19130 + random + + const handle = await vanillaServer.startServerAndWait(CURRENT_VERSION, 1000 * 120, { 'server-port': port, path: 'bds_' }) + + console.log('Started server') + const client = new Client({ + hostname: '127.0.0.1', + port, + username: 'Boat' + random, + offline: true + }) + + return waitFor(async res => { + const root = join(__dirname, `../data/${client.options.version}/sample/packets/`) + if (!fs.existsSync(root)) { + fs.mkdirSync(root, { recursive: true }) + } + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + // client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + + clearInterval(loop) + loop = setInterval(() => { + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: BigInt(Date.now()) }) + }, 200) + }) + + client.on('packet', pakData => { // Packet dumping + if (pakData.name == 'level_chunk') return + try { + if (!fs.existsSync(root + `${pakData.name}.json`)) { + fs.promises.writeFile(root + `${pakData.name}.json`, serialize(pakData.params, 2)) + } + } catch (e) { console.log(e) } + }) + + console.log('Awaiting join...') + + client.on('spawn', () => { + console.log('Spawned!') + clearInterval(loop) + client.close() + handle.kill() + res() + }) + }, 1000 * 60, () => { + clearInterval(loop) + throw Error('timed out') + }) +} + +main().then(() => { + console.log('Successfully dumped packets') +}) \ No newline at end of file diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 83856f4..07587ae 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -17,18 +17,18 @@ function fetchLatestStable () { } // Download + extract vanilla server and enter the directory -async function download (os, version) { +async function download (os, version, path = 'bds-') { process.chdir(__dirname) const verStr = version.split('.').slice(0, 3).join('.') - const dir = 'bds-' + version + const dir = path + version if (fs.existsSync(dir) && getFiles(dir).length) { - process.chdir('bds-' + version) // Enter server folder + process.chdir(path + version) // Enter server folder return verStr } try { fs.mkdirSync(dir) } catch { } - process.chdir('bds-' + version) // Enter server folder + process.chdir(path + version) // Enter server folder const url = (os, version) => `https://minecraft.azureedge.net/bin-${os}/bedrock-server-${version}.zip` let found = false @@ -53,10 +53,18 @@ async function download (os, version) { return verStr } +const defaultOptions = { + 'level-generator': '2', + 'server-port': '19130', + 'online-mode': 'false' +} + // Setup the server -function configure () { +function configure (options = {}) { + const opts = { ...defaultOptions, ...options } let config = fs.readFileSync('./server.properties', 'utf-8') - config += '\nlevel-generator=2\nserver-port=19130\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator\nonline-mode=false' + config += '\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator' + for (const o in opts) config += `\n${o}=${opts[o]}` fs.writeFileSync('./server.properties', config) } @@ -66,13 +74,13 @@ function run (inheritStdout = true) { } // Run the server -async function startServer (version, onStart) { +async function startServer (version, onStart, options = {}) { const os = process.platform === 'win32' ? 'win' : process.platform if (os !== 'win' && os !== 'linux') { throw Error('unsupported os ' + os) } - await download(os, version) - configure() + await download(os, version, options.path) + configure(options) const handle = run(!onStart) if (onStart) { handle.stdout.on('data', data => data.includes('Server started.') ? onStart() : null) @@ -83,10 +91,10 @@ async function startServer (version, onStart) { } // Start the server and wait for it to be ready, with a timeout -async function startServerAndWait (version, withTimeout) { +async function startServerAndWait (version, withTimeout, options) { let handle await waitFor(async res => { - handle = await startServer(version, res) + handle = await startServer(version, res, options) }, withTimeout, () => { handle?.kill() throw new Error('Server did not start on time ' + withTimeout) From e22dfea5999916d65c86216f02eaf8e4c330e4f7 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 24 Mar 2021 06:10:56 -0400 Subject: [PATCH 136/458] Fix server/client closing --- src/client.js | 11 ++++++++--- src/connection.js | 4 +++- src/server.js | 6 ++++-- src/serverPlayer.js | 8 +++++--- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/client.js b/src/client.js index b270c2c..bd841b3 100644 --- a/src/client.js +++ b/src/client.js @@ -108,7 +108,7 @@ class Client extends Connection { } onDisconnectRequest (packet) { - console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) + console.warn(`C Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) this.emit('kick', packet) } @@ -130,7 +130,7 @@ class Client extends Connection { this.q2 = [] this.connection?.close() this.removeAllListeners() - console.log('Closed!') + console.log('Client closed!') } tryRencode (name, params, actual) { @@ -154,7 +154,7 @@ class Client extends Connection { const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100) */) - this.emit('packet', pakData) + this.emit('packet', des) if (debugging) { // Packet verifying (decode + re-encode + match test) @@ -177,6 +177,11 @@ class Client extends Connection { case 'play_status': this.onPlayStatus(pakData.params) break + default: + if (this.status !== ClientStatus.Initializing && this.status !== ClientStatus.Initialized) { + this.inLog(`Can't accept ${des.data.name}, client not yet authenticated : ${this.status}`) + return + } } // Emit packet diff --git a/src/connection.js b/src/connection.js index 220013c..a9061c0 100644 --- a/src/connection.js +++ b/src/connection.js @@ -16,6 +16,8 @@ const ClientStatus = { class Connection extends EventEmitter { status = ClientStatus.Disconnected + q = [] + q2 = [] versionLessThan (version) { if (typeof version === 'string') { @@ -121,7 +123,7 @@ class Connection extends EventEmitter { // TODO: Rename this to sendEncapsulated sendMCPE (buffer, immediate) { - if (this.connection.connected === false) return + if (this.connection.connected === false || this.status === ClientStatus.Disconnected) return this.connection.sendReliable(buffer, immediate) } diff --git a/src/server.js b/src/server.js index 2c5187c..bf440d3 100644 --- a/src/server.js +++ b/src/server.js @@ -15,8 +15,8 @@ class Server extends EventEmitter { /** @type {Object} */ this.clients = {} this.clientCount = 0 - this.inLog = (...args) => debug('C -> S', ...args) - this.outLog = (...args) => debug('S -> C', ...args) + this.inLog = (...args) => debug('S ->', ...args) + this.outLog = (...args) => debug('S <-', ...args) } validateOptions () { @@ -40,6 +40,8 @@ class Server extends EventEmitter { onCloseConnection = (inetAddr, reason) => { console.debug('close connection', inetAddr, reason) + delete this.clients[inetAddr]?.connection // Prevent close loop + this.clients[inetAddr]?.close() delete this.clients[inetAddr] this.clientCount-- } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 49f7917..6fb03bb 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -21,8 +21,8 @@ class Player extends Connection { this.startQueue() this.status = ClientStatus.Authenticating - this.inLog = (...args) => console.info('S -> C', ...args) - this.outLog = (...args) => console.info('C -> S', ...args) + this.inLog = (...args) => console.info('S ->', ...args) + this.outLog = (...args) => console.info('S <-', ...args) } getData () { @@ -82,7 +82,7 @@ class Player extends Connection { /** * Disconnects a client */ - disconnect (reason, hide = false) { + disconnect (reason = 'Server closed', hide = false) { if ([ClientStatus.Authenticating, ClientStatus.Initializing].includes(this.status)) { this.sendDisconnectStatus('failed_server_full') } else { @@ -110,6 +110,7 @@ class Player extends Connection { clearInterval(this.loop) this.connection?.close() this.removeAllListeners() + this.status = ClientStatus.Disconnected } readPacket (packet) { @@ -136,6 +137,7 @@ class Player extends Connection { break case 'set_local_player_as_initialized': this.status = ClientStatus.Initialized + this.inLog('Server client spawned') // Emit the 'spawn' event this.emit('spawn') break From bb9b94fa0276b506632014d1647b418ee4999a1a Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 24 Mar 2021 08:30:24 -0400 Subject: [PATCH 137/458] Add internal server test --- package.json | 3 +- test/internal.js | 204 ++++++++++++++++++++++++++++++++++++++++ tools/genPacketDumps.js | 46 ++++++--- types/Item.js | 37 ++++++++ 4 files changed, 274 insertions(+), 16 deletions(-) create mode 100644 test/internal.js create mode 100644 types/Item.js diff --git a/package.json b/package.json index aec7b49..9bb997d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "pretest": "npm run lint", "lint": "standard", "vanillaServer": "node tools/startVanillaServer.js", + "dumpPackets": "node tools/genPacketDumps.js", "fix": "standard --fix" }, "keywords": [ @@ -33,7 +34,7 @@ "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", "protodef": "^1.11.0", - "raknet-native": "^0.1.0", + "raknet-native": "^0.2.0", "uuid-1345": "^1.0.2" }, "devDependencies": { diff --git a/test/internal.js b/test/internal.js new file mode 100644 index 0000000..e01e932 --- /dev/null +++ b/test/internal.js @@ -0,0 +1,204 @@ +process.env.DEBUG = 'minecraft-protocol raknet' +const { Server, Client } = require('../') +const { dumpPackets, hasDumps } = require('../tools/genPacketDumps') +const DataProvider = require('../data/provider') + +// First we need to dump some packets that a vanilla server would send a vanilla +// client. Then we can replay those back in our custom server. +function prepare (version) { + if (!hasDumps(version)) { + return dumpPackets(version) + } +} + +async function startTest (version = '1.16.210', ok) { + await prepare(version) + const Item = require('../types/Item')(version) + const port = 19130 + const server = new Server({ hostname: '0.0.0.0', port, version }) + + function getPath (packetPath) { + return DataProvider(server.options.protocolVersion).getPath(packetPath) + } + + function get (packetPath) { + return require(getPath('sample/' + packetPath)) + } + + server.listen() + console.log('Started server') + + const respawnPacket = get('packets/respawn.json') + const chunks = await requestChunks(respawnPacket.x, respawnPacket.z, 1) + + let loop + + // server logic + server.on('connect', client => { + client.on('join', () => { + console.log('Client joined', client.getData()) + + client.write('resource_packs_info', { + must_accept: false, + has_scripts: false, + behaviour_packs: [], + texture_packs: [] + }) + + client.once('resource_pack_client_response', async rp => { + // Tell the server we will compress everything (>=1 byte) + client.write('network_settings', { compression_threshold: 1 }) + // Send some inventory slots + for (let i = 0; i < 3; i++) { + client.queue('inventory_slot', { window_id: 'armor', slot: 0, item: new Item().toBedrock() }) + } + + // client.queue('inventory_transaction', get('packets/inventory_transaction.json')) + client.queue('player_list', get('packets/player_list.json')) + client.queue('start_game', get('packets/start_game.json')) + client.queue('item_component', { entries: [] }) + client.queue('set_spawn_position', get('packets/set_spawn_position.json')) + client.queue('set_time', { time: 5433771 }) + client.queue('set_difficulty', { difficulty: 1 }) + client.queue('set_commands_enabled', { enabled: true }) + client.queue('adventure_settings', get('packets/adventure_settings.json')) + + client.queue('biome_definition_list', get('packets/biome_definition_list.json')) + client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) + + client.queue('update_attributes', get('packets/update_attributes.json')) + client.queue('creative_content', get('packets/creative_content.json')) + client.queue('inventory_content', get('packets/inventory_content.json')) + + client.queue('player_hotbar', { selected_slot: 3, window_id: 'inventory', select_slot: true }) + + client.queue('crafting_data', get('packets/crafting_data.json')) + client.queue('available_commands', get('packets/available_commands.json')) + client.queue('chunk_radius_update', { chunk_radius: 5 }) + + // client.queue('set_entity_data', get('packets/set_entity_data.json')) + + client.queue('game_rules_changed', get('packets/game_rules_changed.json')) + client.queue('respawn', get('packets/game_rules_changed.json')) + + for (const chunk of chunks) { + client.queue('level_chunk', chunk) + } + + loop = setInterval(() => { + client.write('network_chunk_publisher_update', { coordinates: { x: 646, y: 130, z: 77 }, radius: 64 }) + }, 9500) + + setTimeout(() => { + client.write('play_status', { status: 'player_spawn' }) + }, 6000) + + // Respond to tick synchronization packets + client.on('tick_sync', (packet) => { + client.queue('tick_sync', { + request_time: packet.request_time, + response_time: BigInt(Date.now()) + }) + }) + }) + }) + }) + + // client logic + const client = new Client({ + hostname: '127.0.0.1', + port, + username: 'Notch', + version, + offline: true + }) + + console.log('Started client') + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) + + client.once('spawn', () => { + console.info('Client spawend!') + setTimeout(() => { + client.close() + + server.close() + ok?.() + }, 500) + clearInterval(loop) + }) +} + +const { ChunkColumn, Version } = require('bedrock-provider') +const { waitFor } = require('../src/datatypes/util') +const mcData = require('minecraft-data')('1.16') + +async function requestChunks (x, z, radius) { + const cxStart = (x >> 4) - radius + const cxEnd = (x >> 4) + radius + const czStart = (z >> 4) - radius + const czEnd = (z >> 4) + radius + + const stone = mcData.blocksByName.stone + const chunks = [] + + for (let cx = cxStart; cx < cxEnd; cx++) { + for (let cz = czStart; cz < czEnd; cz++) { + console.log('reading chunk at ', cx, cz) + const cc = new ChunkColumn(Version.v1_2_0_bis, x, z) + + for (let x = 0; x < 16; x++) { + for (let y = 0; y < 60; y++) { + for (let z = 0; z < 16; z++) { + cc.setBlock(x, y, z, stone) + } + } + } + + if (!cc) { + console.log('no chunk') + continue + } + const cbuf = await cc.networkEncodeNoCache() + chunks.push({ + x: cx, + z: cz, + sub_chunk_count: cc.sectionsLen, + cache_enabled: false, + blobs: [], + payload: cbuf + }) + // console.log('Ht',cc.sectionsLen,cc.sections) + } + } + + return chunks +} + +async function timedTest (version) { + await waitFor((res) => { + startTest(version, res) + }, 1000 * 60, () => { + throw Error('timed out') + }) + console.info('✔ ok') +} + +if (!module.parent) timedTest() +module.exports = { startTest, timedTest, requestChunks } diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index dd74150..3b3de74 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -1,20 +1,27 @@ -/* eslint-disable */ // Collect sample packets needed for `serverTest.js` // process.env.DEBUG = 'minecraft-protocol' const fs = require('fs') const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') -const { serialize, waitFor } = require('../src/datatypes/util') +const { serialize, waitFor, getFiles } = require('../src/datatypes/util') const { CURRENT_VERSION } = require('../src/options') const { join } = require('path') +function hasDumps (version) { + const root = join(__dirname, `../data/${version}/sample/packets/`) + if (!fs.existsSync(root) || getFiles(root).length < 10) { + return false + } + return true +} + let loop -async function main() { +async function dump (version, force) { const random = ((Math.random() * 100) | 0) const port = 19130 + random - const handle = await vanillaServer.startServerAndWait(CURRENT_VERSION, 1000 * 120, { 'server-port': port, path: 'bds_' }) + const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port, path: 'bds_' }) console.log('Started server') const client = new Client({ @@ -25,9 +32,10 @@ async function main() { }) return waitFor(async res => { - const root = join(__dirname, `../data/${client.options.version}/sample/packets/`) - if (!fs.existsSync(root)) { - fs.mkdirSync(root, { recursive: true }) + const root = join(__dirname, `../data/${client.options.version}/sample/`) + if (!fs.existsSync(root + 'packets') || !fs.existsSync(root + 'chunks')) { + fs.mkdirSync(root + 'packets', { recursive: true }) + fs.mkdirSync(root + 'chunks', { recursive: true }) } client.once('resource_packs_info', (packet) => { @@ -43,7 +51,6 @@ async function main() { }) }) - client.queue('client_cache_status', { enabled: false }) client.queue('request_chunk_radius', { chunk_radius: 1 }) // client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) @@ -54,11 +61,17 @@ async function main() { }, 200) }) - client.on('packet', pakData => { // Packet dumping - if (pakData.name == 'level_chunk') return + let i = 0 + + client.on('packet', async packet => { // Packet dumping + const { name, params } = packet.data + if (name === 'level_chunk') { + fs.writeFileSync(root + `chunks/${name}-${i++}.bin`, packet.buffer) + return + } try { - if (!fs.existsSync(root + `${pakData.name}.json`)) { - fs.promises.writeFile(root + `${pakData.name}.json`, serialize(pakData.params, 2)) + if (!fs.existsSync(root + `packets/${name}.json`) || force) { + fs.writeFileSync(root + `packets/${name}.json`, serialize(params, 2)) } } catch (e) { console.log(e) } }) @@ -78,6 +91,9 @@ async function main() { }) } -main().then(() => { - console.log('Successfully dumped packets') -}) \ No newline at end of file +if (!module.parent) { + dump(null, true).then(() => { + console.log('Successfully dumped packets') + }) +} +module.exports = { dumpPackets: dump, hasDumps } diff --git a/types/Item.js b/types/Item.js new file mode 100644 index 0000000..eb4d804 --- /dev/null +++ b/types/Item.js @@ -0,0 +1,37 @@ +module.exports = (version) => + class Item { + nbt + constructor (obj) { + this.networkId = 0 + this.runtimeId = 0 + this.count = 0 + this.metadata = 0 + Object.assign(this, obj) + this.version = version + } + + static fromBedrock (obj) { + return new Item({ + runtimeId: obj.runtime_id, + networkId: obj.item?.network_id, + count: obj.item?.auxiliary_value & 0xff, + metadata: obj.item?.auxiliary_value >> 8, + nbt: obj.item?.nbt?.nbt + }) + } + + toBedrock () { + return { + runtime_id: this.runtimeId, + item: { + network_id: this.networkId, + auxiliary_value: (this.metadata << 8) | (this.count & 0xff), + has_nbt: !!this.nbt, + nbt: { version: 1, nbt: this.nbt }, + can_place_on: [], + can_destroy: [], + blocking_tick: 0 + } + } + } + } From 3f5b82f0f4af27342bcb0ac31118d81473bfa547 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 24 Mar 2021 08:32:32 -0400 Subject: [PATCH 138/458] protocol: use WindowID types --- data/1.16.201/protocol.json | 10 ++++----- data/1.16.210/protocol.json | 45 ++++++++++++++++++++++++++++++++----- data/latest/proto.yml | 10 ++++----- data/latest/types.yaml | 29 ++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/data/1.16.201/protocol.json b/data/1.16.201/protocol.json index 2dd5be8..361d139 100644 --- a/data/1.16.201/protocol.json +++ b/data/1.16.201/protocol.json @@ -4531,7 +4531,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -4552,7 +4552,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "server", @@ -4595,7 +4595,7 @@ [ { "name": "window_id", - "type": "varint" + "type": "WindowID" }, { "name": "slot", @@ -5481,7 +5481,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -5526,7 +5526,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index fe48767..27a31ae 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -2546,6 +2546,41 @@ } } ], + "WindowIDVarint": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], "WindowType": [ "mapper", { @@ -4672,7 +4707,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -4693,7 +4728,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "server", @@ -4736,7 +4771,7 @@ [ { "name": "window_id", - "type": "varint" + "type": "WindowIDVarint" }, { "name": "slot", @@ -5653,7 +5688,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -5698,7 +5733,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", diff --git a/data/latest/proto.yml b/data/latest/proto.yml index f24b5fb..713dfff 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -896,7 +896,7 @@ packet_container_open: !bound: client # WindowID is the ID representing the window that is being opened. It may be used later to close the # container using a ContainerClose packet. - window_id: u8 + window_id: WindowID # ContainerType is the type ID of the container that is being opened when opening the container at the # position of the packet. It depends on the block/entity, and could, for example, be the window type of # a chest or a hopper, but also a horse inventory. @@ -917,7 +917,7 @@ packet_container_close: !bound: both # WindowID is the ID representing the window of the container that should be closed. It must be equal to # the one sent in the ContainerOpen packet to close the designated window. - window_id: u8 + window_id: WindowID # ServerSide determines whether or not the container was force-closed by the server. If this value is # not set correctly, the client may ignore the packet and respond with a PacketViolationWarning. server: bool @@ -954,7 +954,7 @@ packet_inventory_slot: !bound: both # WindowID is the ID of the window that the packet modifies. It must point to one of the windows that the # client currently has opened. - window_id: varint + window_id: WindowIDVarint # Slot is the index of the slot that the packet modifies. The new item will be set to the slot at this # index. slot: varint @@ -1448,7 +1448,7 @@ packet_update_trade: !id: 0x50 !bound: client # WindowID is the ID that identifies the trading window that the client currently has opened. - window_id: u8 + window_id: WindowID # WindowType is an identifier specifying the type of the window opened. In vanilla, it appears this is # always filled out with 15. window_type: WindowType @@ -1486,7 +1486,7 @@ packet_update_equipment: !bound: client # WindowID is the identifier associated with the window that the UpdateEquip packet concerns. It is the # ID sent for the horse inventory that was opened before this packet was sent. - window_id: u8 + window_id: WindowID # WindowType is the type of the window that was opened. Generally, this is the type of a horse inventory, # as the packet is specifically made for that. window_type: WindowType diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 1c613d3..6ba41c8 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -996,6 +996,35 @@ WindowID: i8 => 123: fixed_inventory 124: ui +WindowIDVarint: varint => + -100: drop_contents + -24: beacon + -23: trading_output + -22: trading_use_inputs + -21: trading_input_2 + -20: trading_input_1 + -17: enchant_output + -16: enchant_material + -15: enchant_input + -13: anvil_output + -12: anvil_result + -11: anvil_material + -10: container_input + -5: crafting_use_ingredient + -4: crafting_result + -3: crafting_remove_ingredient + -2: crafting_add_ingredient + -1: none + 0: inventory + 1: first + 100: last + 119: offhand + 120: armor + 121: creative + 122: hotbar + 123: fixed_inventory + 124: ui + WindowType: u8 => 0: container 1: workbench From 43ef9c9430b657df608d14898cf4e0c06fdd6479 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Mar 2021 02:33:56 -0400 Subject: [PATCH 139/458] Add internal client/server test --- src/auth/loginVerify.js | 5 ++--- src/serverPlayer.js | 10 +++++----- test/internal.js | 2 +- test/internal.test.js | 11 +++++++++++ 4 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 test/internal.test.js diff --git a/src/auth/loginVerify.js b/src/auth/loginVerify.js index 6d21e41..e1c2743 100644 --- a/src/auth/loginVerify.js +++ b/src/auth/loginVerify.js @@ -17,10 +17,10 @@ module.exports = (client, server, options) => { let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it let finalKey = null - console.log(pubKey) + // console.log(pubKey) for (const token of chain) { const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - console.log('Decoded', decoded) + // console.log('Decoded', decoded) // Check if signed by Mojang key const x5u = getX5U(token) @@ -69,7 +69,6 @@ function getX5U (token) { } function mcPubKeyToPem (mcPubKeyBuffer) { - console.log(mcPubKeyBuffer) if (mcPubKeyBuffer[0] === '-') return mcPubKeyBuffer let pem = '-----BEGIN PUBLIC KEY-----\n' let base64PubKey = mcPubKeyBuffer.toString('base64') diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 6fb03bb..b11d8f4 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -1,6 +1,7 @@ const { ClientStatus, Connection } = require('./connection') const fs = require('fs') const Options = require('./options') +const debug = require('debug')('minecraft-protocol') const { Encrypt } = require('./auth/encryption') const Login = require('./auth/login') @@ -21,8 +22,8 @@ class Player extends Connection { this.startQueue() this.status = ClientStatus.Authenticating - this.inLog = (...args) => console.info('S ->', ...args) - this.outLog = (...args) => console.info('S <-', ...args) + this.inLog = (...args) => debug('S ->', ...args) + this.outLog = (...args) => debug('S <-', ...args) } getData () { @@ -125,10 +126,9 @@ class Player extends Connection { throw e } - console.log('-> S', des) switch (des.data.name) { case 'login': - console.log(des) + // console.log(des) this.onLogin(des) return case 'client_to_server_handshake': @@ -142,7 +142,7 @@ class Player extends Connection { this.emit('spawn') break default: - console.log('ignoring, unhandled') + // console.log('ignoring, unhandled') } this.emit(des.data.name, des.data.params) } diff --git a/test/internal.js b/test/internal.js index e01e932..6e04641 100644 --- a/test/internal.js +++ b/test/internal.js @@ -1,4 +1,4 @@ -process.env.DEBUG = 'minecraft-protocol raknet' +// process.env.DEBUG = 'minecraft-protocol raknet' const { Server, Client } = require('../') const { dumpPackets, hasDumps } = require('../tools/genPacketDumps') const DataProvider = require('../data/provider') diff --git a/test/internal.test.js b/test/internal.test.js new file mode 100644 index 0000000..e3feeac --- /dev/null +++ b/test/internal.test.js @@ -0,0 +1,11 @@ +/* eslint-env jest */ + +const { timedTest } = require('./internal') + +describe('internal client/server test', function () { + this.timeout(120 * 1000) + + it('connects', async () => { + await timedTest() + }) +}) From be98fc6cf8b2cceed1f4a6319c9125cd00d520c0 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Mar 2021 04:38:46 -0400 Subject: [PATCH 140/458] test timeout fixes --- .github/workflows/ci.yml | 2 +- data/provider.js | 6 +++--- package.json | 2 +- test/internal.js | 4 ++-- tools/genPacketDumps.js | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c565b62..7803afb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,8 @@ on: jobs: build: - runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: diff --git a/data/provider.js b/data/provider.js index 3f51f02..6ad1af7 100644 --- a/data/provider.js +++ b/data/provider.js @@ -2,7 +2,7 @@ const { Versions } = require('../src/options') const { getFiles } = require('../src/datatypes/util') const { join } = require('path') -const fileMap = {} +let fileMap = {} // Walks all the directories for each of the supported versions in options.js // then builds a file map for each version @@ -23,6 +23,8 @@ function loadVersions () { } module.exports = (protocolVersion) => { + fileMap = {} + loadVersions() return { // Returns the most recent file based on the specified protocolVersion // e.g. if `version` is 1.16 and a file for 1.16 doesn't exist, load from 1.15 file @@ -40,5 +42,3 @@ module.exports = (protocolVersion) => { } } } - -loadVersions() diff --git a/package.json b/package.json index 9bb997d..9be65ba 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "cd tools && node compileProtocol.js", "prepare": "npm run build", - "test": "mocha", + "test": "mocha --bail", "pretest": "npm run lint", "lint": "standard", "vanillaServer": "node tools/startVanillaServer.js", diff --git a/test/internal.js b/test/internal.js index 6e04641..f87d258 100644 --- a/test/internal.js +++ b/test/internal.js @@ -191,10 +191,10 @@ async function requestChunks (x, z, radius) { return chunks } -async function timedTest (version) { +async function timedTest (version, timeout = 1000 * 120) { await waitFor((res) => { startTest(version, res) - }, 1000 * 60, () => { + }, timeout, () => { throw Error('timed out') }) console.info('✔ ok') diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index 3b3de74..33530d8 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -87,6 +87,7 @@ async function dump (version, force) { }) }, 1000 * 60, () => { clearInterval(loop) + handle.kill() throw Error('timed out') }) } From 0bdd071876365b0ce7bc17dfe15fee74bb2df46b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 26 Mar 2021 04:38:25 -0400 Subject: [PATCH 141/458] client example updates --- examples/clientTest.js | 26 ++++++++++++++------------ src/client.js | 7 ++++++- test/vanilla.js | 6 ++++++ tools/genPacketDumps.js | 2 +- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/examples/clientTest.js b/examples/clientTest.js index 157f450..b523d19 100644 --- a/examples/clientTest.js +++ b/examples/clientTest.js @@ -1,10 +1,13 @@ process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('bedrock-protocol') +const { ChunkColumn, Version } = require('bedrock-provider') async function test () { const client = new Client({ hostname: '127.0.0.1', - port: 19132 + port: 19130 + // You can specify version by adding : + // version: '1.16.210' }) client.once('resource_packs_info', (packet) => { @@ -20,23 +23,22 @@ async function test () { }) }) - // client.once('resource_packs_info', (packet) => { - // client.write('resource_pack_client_response', { - // response_status: 'completed', - // resourcepackids: [] - // }) - // }) client.queue('client_cache_status', { enabled: false }) client.queue('request_chunk_radius', { chunk_radius: 1 }) client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) }) - // var read = 0; - // client.on('level_chunk', (packet) => { - // read++ - // fs.writeFileSync(`level_chunk-${read}.json`, JSON.stringify(packet, null, 2)) - // }) + client.on('level_chunk', async packet => { + const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + await cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count) + let blocks = [] + for (let x = 0; x < 16; x++) { + for (let z = 0; z < 16; z++) { + blocks.push(cc.getBlock(x, 0, z)) // Read some blocks in this chunk + } + } + }) } test() diff --git a/src/client.js b/src/client.js index bd841b3..829eb0d 100644 --- a/src/client.js +++ b/src/client.js @@ -41,6 +41,7 @@ class Client extends Connection { } this.startGameData = {} + this.clientRuntimeId = null this.startQueue() this.inLog = (...args) => debug('C ->', ...args) @@ -60,6 +61,10 @@ class Client extends Connection { } } + get entityId() { + return this.startGameData.runtime_entity_id + } + onEncapsulated = (encapsulated, inetAddr) => { const buffer = Buffer.from(encapsulated.buffer) this.handle(buffer) @@ -116,7 +121,7 @@ class Client extends Connection { if (this.status === ClientStatus.Initializing && this.options.autoInitPlayer === true) { if (statusPacket.status === 'player_spawn') { this.status = ClientStatus.Initialized - this.write('set_local_player_as_initialized', { runtime_entity_id: this.startGameData.runtime_entity_id }) + this.write('set_local_player_as_initialized', { runtime_entity_id: this.entityId }) this.emit('spawn') } } diff --git a/test/vanilla.js b/test/vanilla.js index 1088396..4f37d6b 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -2,6 +2,7 @@ const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') const { waitFor } = require('../src/datatypes/util') +const { ChunkColumn, Version } = require('bedrock-provider') async function test (version) { // Start the server, wait for it to accept clients, throws on timeout @@ -42,6 +43,11 @@ async function test (version) { client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: BigInt(Date.now()) }) }, 200) + client.on('level_chunk', async packet => { // Chunk read test + const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + await cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count) + }) + console.log('Awaiting join') client.on('spawn', () => { diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index 33530d8..5add677 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -21,7 +21,7 @@ async function dump (version, force) { const random = ((Math.random() * 100) | 0) const port = 19130 + random - const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port, path: 'bds_' }) + const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port }) console.log('Started server') const client = new Client({ From 3369fc279062d2c6095288752dbc81b0d10af32b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 26 Mar 2021 04:41:42 -0400 Subject: [PATCH 142/458] update server example, use protocol updates Server example with bedrock-provider Use 64-bit varints for entity runtime ids --- data/1.16.210/protocol.json | 36 +++--- data/latest/proto.yml | 36 +++--- examples/clientTest.js | 5 +- examples/serverChunks.js | 48 ++++++++ examples/serverTest.js | 234 +++++++++++++++++------------------- src/client.js | 2 +- 6 files changed, 200 insertions(+), 161 deletions(-) create mode 100644 examples/serverChunks.js diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 27a31ae..8c34b12 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -3756,7 +3756,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "platform_chat_id", @@ -3853,7 +3853,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "entity_type", @@ -3927,7 +3927,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "item", @@ -3972,7 +3972,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "target", @@ -3985,7 +3985,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "flags", @@ -4129,7 +4129,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "coordinates", @@ -4303,7 +4303,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "event_id", @@ -4381,7 +4381,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "event_id", @@ -4436,7 +4436,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "item", @@ -4461,7 +4461,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "helmet", @@ -4500,7 +4500,7 @@ }, { "name": "target_runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "position", @@ -4561,7 +4561,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "action", @@ -4591,7 +4591,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "metadata", @@ -4608,7 +4608,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "velocity", @@ -4673,7 +4673,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" } ] ], @@ -4698,7 +4698,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" } ] ], @@ -5321,7 +5321,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "status", @@ -6100,7 +6100,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "unknown0", diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 713dfff..68a7bbe 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -393,7 +393,7 @@ packet_add_player: entity_id_self: zigzag64 # The runtime ID of the player. The runtime ID is unique for each world session, # and entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint + runtime_entity_id: varint64 # An identifier only set for particular platforms when chatting (presumably only for # Nintendo Switch). It is otherwise an empty string, and is used to decide which players # are able to chat with each other. @@ -423,7 +423,7 @@ packet_add_entity: !id: 0x0d !bound: client entity_id_self: zigzag64 - runtime_entity_id: varint + runtime_entity_id: varint64 entity_type: string x: lf32 y: lf32 @@ -447,7 +447,7 @@ packet_add_item_entity: !id: 0x0f !bound: client entity_id_self: zigzag64 - runtime_entity_id: varint + runtime_entity_id: varint64 item: Item x: lf32 y: lf32 @@ -461,13 +461,13 @@ packet_add_item_entity: packet_take_item_entity: !id: 0x11 !bound: client - runtime_entity_id: varint + runtime_entity_id: varint64 target: varint packet_move_entity: !id: 0x12 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 flags: u8 position: vec3f rotation: Rotation @@ -559,7 +559,7 @@ packet_add_painting: !id: 0x16 !bound: client entity_id_self: zigzag64 - runtime_entity_id: varint + runtime_entity_id: varint64 coordinates: BlockCoordinates direction: zigzag32 title: string @@ -675,7 +675,7 @@ packet_block_event: packet_entity_event: !id: 0x1b !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 event_id: u8 => 1: jump 2: hurt_animation @@ -739,7 +739,7 @@ packet_entity_event: packet_mob_effect: !id: 0x1c !bound: client - runtime_entity_id: varint + runtime_entity_id: varint64 event_id: u8 effect_id: zigzag32 amplifier: zigzag32 @@ -765,7 +765,7 @@ packet_inventory_transaction: packet_mob_equipment: !id: 0x1f !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 item: Item slot: u8 selected_slot: u8 @@ -774,7 +774,7 @@ packet_mob_equipment: packet_mob_armor_equipment: !id: 0x20 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 helmet: Item chestplate: Item leggings: Item @@ -793,7 +793,7 @@ packet_interact: 6: open_inventory # TargetEntityRuntimeID is the runtime ID of the entity that the player interacted with. This is empty # for the InteractActionOpenInventory action type. - target_runtime_entity_id: varint + target_runtime_entity_id: varint64 # Position associated with the ActionType above. For the InteractActionMouseOverEntity, this is the # position relative to the entity moused over over which the player hovered with its mouse/touch. For the # InteractActionLeaveVehicle, this is the position that the player spawns at after leaving the vehicle. @@ -822,7 +822,7 @@ packet_player_action: !bound: server # EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and # entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint + runtime_entity_id: varint64 # ActionType is the ID of the action that was executed by the player. It is one of the constants that may # be found above. action: Action @@ -841,14 +841,14 @@ packet_hurt_armor: packet_set_entity_data: !id: 0x27 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 metadata: MetadataDictionary tick: varint packet_set_entity_motion: !id: 0x28 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 velocity: vec3f # SetActorLink is sent by the server to initiate an entity link client-side, meaning one entity will start @@ -877,7 +877,7 @@ packet_animate: !id: 0x2c !bound: both action_id: zigzag32 - runtime_entity_id: varint + runtime_entity_id: varint64 packet_respawn: !id: 0x2d @@ -886,7 +886,7 @@ packet_respawn: y: lf32 z: lf32 state: u8 - runtime_entity_id: varint + runtime_entity_id: varint64 # ContainerOpen is sent by the server to open a container client-side. This container must be physically # present in the world, for the packet to have any effect. Unlike Java Edition, Bedrock Edition requires that @@ -1287,7 +1287,7 @@ packet_boss_event: packet_show_credits: !id: 0x4b !bound: client - runtime_entity_id: varint + runtime_entity_id: varint64 status: zigzag32 # This packet sends a list of commands to the client. Commands can have @@ -1647,7 +1647,7 @@ packet_book_edit: packet_npc_request: !id: 0x62 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 unknown0: u8 unknown1: string unknown2: u8 diff --git a/examples/clientTest.js b/examples/clientTest.js index b523d19..bcb644e 100644 --- a/examples/clientTest.js +++ b/examples/clientTest.js @@ -5,7 +5,7 @@ const { ChunkColumn, Version } = require('bedrock-provider') async function test () { const client = new Client({ hostname: '127.0.0.1', - port: 19130 + port: 19132 // You can specify version by adding : // version: '1.16.210' }) @@ -23,7 +23,6 @@ async function test () { }) }) - client.queue('client_cache_status', { enabled: false }) client.queue('request_chunk_radius', { chunk_radius: 1 }) client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) @@ -32,7 +31,7 @@ async function test () { client.on('level_chunk', async packet => { const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) await cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count) - let blocks = [] + const blocks = [] for (let x = 0; x < 16; x++) { for (let z = 0; z < 16; z++) { blocks.push(cc.getBlock(x, 0, z)) // Read some blocks in this chunk diff --git a/examples/serverChunks.js b/examples/serverChunks.js new file mode 100644 index 0000000..0b711c4 --- /dev/null +++ b/examples/serverChunks.js @@ -0,0 +1,48 @@ +// CHUNKS +const { WorldProvider } = require('bedrock-provider') +const { LevelDB } = require('leveldb-zlib') +const { join } = require('path') + +async function loadWorld (version) { + const path = join(__dirname, `../tools/bds-${version}/worlds/Bedrock level/db`) + console.log('Loading world at path', path) // Load world from testing server + const db = new LevelDB(path, { createIfMissing: false }) + await db.open() + const wp = new WorldProvider(db, { dimension: 0 }) + + async function requestChunks (x, z, radius) { + const chunks = [] + const cxStart = (x >> 4) - radius + const cxEnd = (x >> 4) + radius + const czStart = (z >> 4) - radius + const czEnd = (z >> 4) + radius + + for (let cx = cxStart; cx < cxEnd; cx++) { + for (let cz = czStart; cz < czEnd; cz++) { + // console.log('reading chunk at ', cx, cz) + + const cc = await wp.load(cx, cz, true) + if (!cc) { + // console.log('no chunk') + continue + } + const cbuf = await cc.networkEncodeNoCache() + chunks.push({ + x: cx, + z: cz, + sub_chunk_count: cc.sectionsLen, + cache_enabled: false, + blobs: [], + payload: cbuf + }) + // console.log('Ht',cc.sectionsLen,cc.sections) + } + } + + return chunks + } + + return { requestChunks } +} + +module.exports = { loadWorld } diff --git a/examples/serverTest.js b/examples/serverTest.js index 5006736..58b083e 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -1,39 +1,57 @@ -const fs = require('fs') -process.env.DEBUG = 'minecraft-protocol raknet' +/** + * bedrock-protocol server example; to run this example you need to clone this repo from git. + * first need to dump some packets from the vanilla server as there is alot of boilerplate + * to send to clients. + * + * In your server implementation, you need to implement each of the following packets to + * get a client to spawn like vanilla. You can look at the dumped packets in `data/1.16.10/sample` + * + * First, dump packets for version 1.16.210 by running `npm run dumpPackets`. + */ +process.env.DEBUG = 'minecraft-protocol' // packet logging +// const fs = require('fs') const { Server } = require('../src/server') -// const CreativeItems = require('../data/creativeitems.json') +const { hasDumps } = require('../tools/genPacketDumps') const DataProvider = require('../data/provider') +const { waitFor } = require('../src/datatypes/util') +const { loadWorld } = require('./serverChunks') -const server = new Server({ +async function startServer (version = '1.16.210', ok) { + if (!hasDumps(version)) { + throw Error('You need to dump some packets first. Run tools/genPacketDumps.js') + } -}) -server.create('0.0.0.0', 19132) + const Item = require('../types/Item')(version) + const port = 19132 + const server = new Server({ hostname: '0.0.0.0', port, version }) + let loop -function getPath (packetPath) { - return DataProvider(server.options.protocolVersion).getPath(packetPath) -} + const getPath = (packetPath) => DataProvider(server.options.protocolVersion).getPath(packetPath) + const get = (packetPath) => require(getPath('sample/' + packetPath)) -function get (packetPath) { - return require(getPath('sample/' + packetPath)) -} + server.listen() + console.log('Started server') -// const ran = false + // Find the center position from the dumped packets + const respawnPacket = get('packets/respawn.json') + const world = await loadWorld(version) + const chunks = await world.requestChunks(respawnPacket.x, respawnPacket.z, 2) -server.on('connect', ({ client }) => { - /** @type {Player} */ - client.on('join', () => { - console.log('Client joined', client.getData()) + // Connect is emitted when a client first joins our server, before authing them + server.on('connect', client => { + // Join is emitted after the client has been authenticated and encryption has started + client.on('join', () => { + console.log('Client joined', client.getData()) - // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It - // sends a list of the resource packs it has and basic information on them like the version and description. - client.write('resource_packs_info', { - must_accept: false, - has_scripts: false, - behaviour_packs: [], - texture_packs: [] - }) + // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It + // sends a list of the resource packs it has and basic information on them like the version and description. + client.write('resource_packs_info', { + must_accept: false, + has_scripts: false, + behaviour_packs: [], + texture_packs: [] + }) - client.once('resource_pack_client_response', async (packet) => { // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs // should be applied (and downloaded) by the client. client.write('resource_pack_stack', { @@ -45,109 +63,83 @@ server.on('connect', ({ client }) => { experiments_previously_used: false }) - client.once('resource_pack_client_response', async (packet) => { + client.once('resource_pack_client_response', async rp => { + // Tell the server we will compress everything (>=1 byte) + client.write('network_settings', { compression_threshold: 1 }) + // Send some inventory slots + for (let i = 0; i < 3; i++) { + client.queue('inventory_slot', { window_id: 120, slot: 0, item: new Item().toBedrock() }) + } - }) + client.write('player_list', get('packets/player_list.json')) + client.write('start_game', get('packets/start_game.json')) + client.write('item_component', { entries: [] }) + client.write('set_spawn_position', get('packets/set_spawn_position.json')) + client.write('set_time', { time: 5433771 }) + client.write('set_difficulty', { difficulty: 1 }) + client.write('set_commands_enabled', { enabled: true }) + client.write('adventure_settings', get('packets/adventure_settings.json')) + client.write('biome_definition_list', get('packets/biome_definition_list.json')) + client.write('available_entity_identifiers', get('packets/available_entity_identifiers.json')) + client.write('update_attributes', get('packets/update_attributes.json')) + client.write('creative_content', get('packets/creative_content.json')) + client.write('inventory_content', get('packets/inventory_content.json')) + client.write('player_hotbar', { selected_slot: 3, window_id: 'inventory', select_slot: true }) + client.write('crafting_data', get('packets/crafting_data.json')) + client.write('available_commands', get('packets/available_commands.json')) + client.write('chunk_radius_update', { chunk_radius: 1 }) + client.write('game_rules_changed', get('packets/game_rules_changed.json')) + client.write('respawn', get('packets/respawn.json')) - client.write('network_settings', { - compression_threshold: 1 - }) + for (const chunk of chunks) { + client.queue('level_chunk', chunk) + } - for (let i = 0; i < 3; i++) { - client.queue('inventory_slot', { inventory_id: 120, slot: i, uniqueid: 0, item: { network_id: 0 } }) - } + // Uncomment below and comment above to send dumped chunks. We use bedrock-provider in this example which is still a WIP, some blocks may be broken. + // for (const file of fs.readdirSync(`../data/${server.options.version}/sample/chunks`)) { + // const buffer = fs.readFileSync(`../data/${server.options.version}/sample/chunks/` + file) + // // console.log('Sending chunk', buffer) + // client.sendBuffer(buffer) + // } - client.queue('inventory_transaction', get('packets/inventory_transaction.json')) - client.queue('player_list', get('packets/player_list.json')) - client.queue('start_game', get('packets/start_game.json')) - client.queue('item_component', { entries: [] }) - client.queue('set_spawn_position', get('packets/set_spawn_position.json')) - client.queue('set_time', { time: 5433771 }) - client.queue('set_difficulty', { difficulty: 1 }) - client.queue('set_commands_enabled', { enabled: true }) - client.queue('adventure_settings', get('packets/adventure_settings.json')) + // Constantly send this packet to the client to tell it the center position for chunks. The client should then request these + // missing chunks from the us if it's missing any within the radius. `radius` is in blocks. + loop = setInterval(() => { + client.write('network_chunk_publisher_update', { coordinates: { x: respawnPacket.x, y: 130, z: respawnPacket.z }, radius: 80 }) + }, 4500) - client.queue('biome_definition_list', get('packets/biome_definition_list.json')) - client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) + // Wait some time to allow for the client to recieve and load all the chunks + setTimeout(() => { + // Allow the client to spawn + client.write('play_status', { status: 'player_spawn' }) + }, 6000) - client.queue('update_attributes', get('packets/update_attributes.json')) - client.queue('creative_content', get('packets/creative_content.json')) - client.queue('inventory_content', get('packets/inventory_content.json')) - client.queue('player_hotbar', { selected_slot: 3, window_id: 0, select_slot: true }) - - client.queue('crafting_data', get('packets/crafting_data.json')) - client.queue('available_commands', get('packets/available_commands.json')) - client.queue('chunk_radius_update', { chunk_radius: 5 }) - - client.queue('set_entity_data', get('packets/set_entity_data.json')) - - client.queue('game_rules_changed', get('packets/game_rules_changed.json')) - client.queue('respawn', { x: 646.9405517578125, y: 65.62001037597656, z: 77.86255645751953, state: 0, runtime_entity_id: 0 }) - - for (const file of fs.readdirSync(`../data/${server.options.version}/sample/chunks`)) { - const buffer = Buffer.from(fs.readFileSync(`../data/${server.options.version}/sample/chunks/` + file, 'utf8'), 'hex') - // console.log('Sending chunk', chunk) - client.sendBuffer(buffer) - } - - // for (const chunk of chunks) { - // client.queue('level_chunk', chunk) - // } - - setInterval(() => { - client.write('network_chunk_publisher_update', { coordinates: { x: 646, y: 130, z: 77 }, radius: 64 }) - }, 9500) - - setTimeout(() => { - client.write('play_status', { status: 'player_spawn' }) - }, 8000) - - // Respond to tick synchronization packets - client.on('tick_sync', (packet) => { - client.queue('tick_sync', { - request_time: packet.request_time, - response_time: BigInt(Date.now()) + // Respond to tick synchronization packets + client.on('tick_sync', (packet) => { + client.queue('tick_sync', { + request_time: packet.request_time, + response_time: BigInt(Date.now()) + }) }) }) }) }) + + ok() + + return { + kill: () => { + clearInterval(loop) + server.close() + } + } +} + +let server +waitFor((res) => { + server = startServer(process.argv[2], res) +}, 1000 * 60 /* Wait 60 seconds for the server to start */, function onTimeout () { + console.error('Server did not start in time') + server?.close() + process.exit(1) }) - -// CHUNKS -// const { ChunkColumn, Version } = require('bedrock-provider') -// const mcData = require('minecraft-data')('1.16') -// const chunks = [] -// async function buildChunks () { -// // "x": 40, -// // "z": 4, - -// const stone = mcData.blocksByName.stone - -// for (let cx = 35; cx < 45; cx++) { -// for (let cz = 0; cz < 8; cz++) { -// const column = new ChunkColumn(Version.v1_2_0_bis, x, z) -// for (let x = 0; x < 16; x++) { -// for (let y = 0; y < 60; y++) { -// for (let z = 0; z < 16; z++) { -// column.setBlock(x, y, z, stone) -// } -// } -// } - -// const ser = await column.networkEncodeNoCache() - -// chunks.push({ -// x: cx, -// z: cz, -// sub_chunk_count: column.sectionsLen, -// cache_enabled: false, -// blobs: [], -// payload: ser -// }) -// } -// } - -// // console.log('Chunks',chunks) -// } - -// // buildChunks() diff --git a/src/client.js b/src/client.js index 829eb0d..2fb3ce1 100644 --- a/src/client.js +++ b/src/client.js @@ -61,7 +61,7 @@ class Client extends Connection { } } - get entityId() { + get entityId () { return this.startGameData.runtime_entity_id } From 47c76ee5972df7f39ab8a7390dfa1250ae4366d3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 26 Mar 2021 05:13:01 -0400 Subject: [PATCH 143/458] fix internal test packet path --- test/internal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/internal.js b/test/internal.js index f87d258..40aeb5e 100644 --- a/test/internal.js +++ b/test/internal.js @@ -79,7 +79,7 @@ async function startTest (version = '1.16.210', ok) { // client.queue('set_entity_data', get('packets/set_entity_data.json')) client.queue('game_rules_changed', get('packets/game_rules_changed.json')) - client.queue('respawn', get('packets/game_rules_changed.json')) + client.queue('respawn', get('packets/respawn.json')) for (const chunk of chunks) { client.queue('level_chunk', chunk) From a55eaddc9801ef5e6ae997c75d7ce900084061e9 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 26 Mar 2021 05:19:08 -0400 Subject: [PATCH 144/458] Add packet dumper, new server example, internal client/server test (#4) * Add packet dumper, configuable vanilla server, client events * Fix server/client closing * Add internal server test * protocol: use WindowID types * Add internal client/server test * test timeout fixes * client example updates * update server example, use protocol updates Server example with bedrock-provider Use 64-bit varints for entity runtime ids * fix internal test packet path --- .github/workflows/ci.yml | 2 +- data/1.16.201/protocol.json | 10 +- data/1.16.210/protocol.json | 81 +++++++++---- data/latest/proto.yml | 46 +++---- data/latest/types.yaml | 29 +++++ data/provider.js | 6 +- examples/clientTest.js | 25 ++-- examples/serverChunks.js | 48 ++++++++ examples/serverTest.js | 234 +++++++++++++++++------------------- package.json | 5 +- src/auth/loginVerify.js | 5 +- src/client.js | 32 +++-- src/connection.js | 4 +- src/server.js | 6 +- src/serverPlayer.js | 14 ++- test/internal.js | 204 +++++++++++++++++++++++++++++++ test/internal.test.js | 11 ++ test/vanilla.js | 6 + tools/genPacketDumps.js | 100 +++++++++++++++ tools/startVanillaServer.js | 30 +++-- types/Item.js | 37 ++++++ 21 files changed, 705 insertions(+), 230 deletions(-) create mode 100644 examples/serverChunks.js create mode 100644 test/internal.js create mode 100644 test/internal.test.js create mode 100644 tools/genPacketDumps.js create mode 100644 types/Item.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c565b62..7803afb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,8 @@ on: jobs: build: - runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: diff --git a/data/1.16.201/protocol.json b/data/1.16.201/protocol.json index 2dd5be8..361d139 100644 --- a/data/1.16.201/protocol.json +++ b/data/1.16.201/protocol.json @@ -4531,7 +4531,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -4552,7 +4552,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "server", @@ -4595,7 +4595,7 @@ [ { "name": "window_id", - "type": "varint" + "type": "WindowID" }, { "name": "slot", @@ -5481,7 +5481,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -5526,7 +5526,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index fe48767..8c34b12 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -2546,6 +2546,41 @@ } } ], + "WindowIDVarint": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], "WindowType": [ "mapper", { @@ -3721,7 +3756,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "platform_chat_id", @@ -3818,7 +3853,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "entity_type", @@ -3892,7 +3927,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "item", @@ -3937,7 +3972,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "target", @@ -3950,7 +3985,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "flags", @@ -4094,7 +4129,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "coordinates", @@ -4268,7 +4303,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "event_id", @@ -4346,7 +4381,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "event_id", @@ -4401,7 +4436,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "item", @@ -4426,7 +4461,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "helmet", @@ -4465,7 +4500,7 @@ }, { "name": "target_runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "position", @@ -4526,7 +4561,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "action", @@ -4556,7 +4591,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "metadata", @@ -4573,7 +4608,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "velocity", @@ -4638,7 +4673,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" } ] ], @@ -4663,7 +4698,7 @@ }, { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" } ] ], @@ -4672,7 +4707,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -4693,7 +4728,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "server", @@ -4736,7 +4771,7 @@ [ { "name": "window_id", - "type": "varint" + "type": "WindowIDVarint" }, { "name": "slot", @@ -5286,7 +5321,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "status", @@ -5653,7 +5688,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -5698,7 +5733,7 @@ [ { "name": "window_id", - "type": "u8" + "type": "WindowID" }, { "name": "window_type", @@ -6065,7 +6100,7 @@ [ { "name": "runtime_entity_id", - "type": "varint" + "type": "varint64" }, { "name": "unknown0", diff --git a/data/latest/proto.yml b/data/latest/proto.yml index f24b5fb..68a7bbe 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -393,7 +393,7 @@ packet_add_player: entity_id_self: zigzag64 # The runtime ID of the player. The runtime ID is unique for each world session, # and entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint + runtime_entity_id: varint64 # An identifier only set for particular platforms when chatting (presumably only for # Nintendo Switch). It is otherwise an empty string, and is used to decide which players # are able to chat with each other. @@ -423,7 +423,7 @@ packet_add_entity: !id: 0x0d !bound: client entity_id_self: zigzag64 - runtime_entity_id: varint + runtime_entity_id: varint64 entity_type: string x: lf32 y: lf32 @@ -447,7 +447,7 @@ packet_add_item_entity: !id: 0x0f !bound: client entity_id_self: zigzag64 - runtime_entity_id: varint + runtime_entity_id: varint64 item: Item x: lf32 y: lf32 @@ -461,13 +461,13 @@ packet_add_item_entity: packet_take_item_entity: !id: 0x11 !bound: client - runtime_entity_id: varint + runtime_entity_id: varint64 target: varint packet_move_entity: !id: 0x12 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 flags: u8 position: vec3f rotation: Rotation @@ -559,7 +559,7 @@ packet_add_painting: !id: 0x16 !bound: client entity_id_self: zigzag64 - runtime_entity_id: varint + runtime_entity_id: varint64 coordinates: BlockCoordinates direction: zigzag32 title: string @@ -675,7 +675,7 @@ packet_block_event: packet_entity_event: !id: 0x1b !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 event_id: u8 => 1: jump 2: hurt_animation @@ -739,7 +739,7 @@ packet_entity_event: packet_mob_effect: !id: 0x1c !bound: client - runtime_entity_id: varint + runtime_entity_id: varint64 event_id: u8 effect_id: zigzag32 amplifier: zigzag32 @@ -765,7 +765,7 @@ packet_inventory_transaction: packet_mob_equipment: !id: 0x1f !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 item: Item slot: u8 selected_slot: u8 @@ -774,7 +774,7 @@ packet_mob_equipment: packet_mob_armor_equipment: !id: 0x20 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 helmet: Item chestplate: Item leggings: Item @@ -793,7 +793,7 @@ packet_interact: 6: open_inventory # TargetEntityRuntimeID is the runtime ID of the entity that the player interacted with. This is empty # for the InteractActionOpenInventory action type. - target_runtime_entity_id: varint + target_runtime_entity_id: varint64 # Position associated with the ActionType above. For the InteractActionMouseOverEntity, this is the # position relative to the entity moused over over which the player hovered with its mouse/touch. For the # InteractActionLeaveVehicle, this is the position that the player spawns at after leaving the vehicle. @@ -822,7 +822,7 @@ packet_player_action: !bound: server # EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and # entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint + runtime_entity_id: varint64 # ActionType is the ID of the action that was executed by the player. It is one of the constants that may # be found above. action: Action @@ -841,14 +841,14 @@ packet_hurt_armor: packet_set_entity_data: !id: 0x27 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 metadata: MetadataDictionary tick: varint packet_set_entity_motion: !id: 0x28 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 velocity: vec3f # SetActorLink is sent by the server to initiate an entity link client-side, meaning one entity will start @@ -877,7 +877,7 @@ packet_animate: !id: 0x2c !bound: both action_id: zigzag32 - runtime_entity_id: varint + runtime_entity_id: varint64 packet_respawn: !id: 0x2d @@ -886,7 +886,7 @@ packet_respawn: y: lf32 z: lf32 state: u8 - runtime_entity_id: varint + runtime_entity_id: varint64 # ContainerOpen is sent by the server to open a container client-side. This container must be physically # present in the world, for the packet to have any effect. Unlike Java Edition, Bedrock Edition requires that @@ -896,7 +896,7 @@ packet_container_open: !bound: client # WindowID is the ID representing the window that is being opened. It may be used later to close the # container using a ContainerClose packet. - window_id: u8 + window_id: WindowID # ContainerType is the type ID of the container that is being opened when opening the container at the # position of the packet. It depends on the block/entity, and could, for example, be the window type of # a chest or a hopper, but also a horse inventory. @@ -917,7 +917,7 @@ packet_container_close: !bound: both # WindowID is the ID representing the window of the container that should be closed. It must be equal to # the one sent in the ContainerOpen packet to close the designated window. - window_id: u8 + window_id: WindowID # ServerSide determines whether or not the container was force-closed by the server. If this value is # not set correctly, the client may ignore the packet and respond with a PacketViolationWarning. server: bool @@ -954,7 +954,7 @@ packet_inventory_slot: !bound: both # WindowID is the ID of the window that the packet modifies. It must point to one of the windows that the # client currently has opened. - window_id: varint + window_id: WindowIDVarint # Slot is the index of the slot that the packet modifies. The new item will be set to the slot at this # index. slot: varint @@ -1287,7 +1287,7 @@ packet_boss_event: packet_show_credits: !id: 0x4b !bound: client - runtime_entity_id: varint + runtime_entity_id: varint64 status: zigzag32 # This packet sends a list of commands to the client. Commands can have @@ -1448,7 +1448,7 @@ packet_update_trade: !id: 0x50 !bound: client # WindowID is the ID that identifies the trading window that the client currently has opened. - window_id: u8 + window_id: WindowID # WindowType is an identifier specifying the type of the window opened. In vanilla, it appears this is # always filled out with 15. window_type: WindowType @@ -1486,7 +1486,7 @@ packet_update_equipment: !bound: client # WindowID is the identifier associated with the window that the UpdateEquip packet concerns. It is the # ID sent for the horse inventory that was opened before this packet was sent. - window_id: u8 + window_id: WindowID # WindowType is the type of the window that was opened. Generally, this is the type of a horse inventory, # as the packet is specifically made for that. window_type: WindowType @@ -1647,7 +1647,7 @@ packet_book_edit: packet_npc_request: !id: 0x62 !bound: both - runtime_entity_id: varint + runtime_entity_id: varint64 unknown0: u8 unknown1: string unknown2: u8 diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 1c613d3..6ba41c8 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -996,6 +996,35 @@ WindowID: i8 => 123: fixed_inventory 124: ui +WindowIDVarint: varint => + -100: drop_contents + -24: beacon + -23: trading_output + -22: trading_use_inputs + -21: trading_input_2 + -20: trading_input_1 + -17: enchant_output + -16: enchant_material + -15: enchant_input + -13: anvil_output + -12: anvil_result + -11: anvil_material + -10: container_input + -5: crafting_use_ingredient + -4: crafting_result + -3: crafting_remove_ingredient + -2: crafting_add_ingredient + -1: none + 0: inventory + 1: first + 100: last + 119: offhand + 120: armor + 121: creative + 122: hotbar + 123: fixed_inventory + 124: ui + WindowType: u8 => 0: container 1: workbench diff --git a/data/provider.js b/data/provider.js index 3f51f02..6ad1af7 100644 --- a/data/provider.js +++ b/data/provider.js @@ -2,7 +2,7 @@ const { Versions } = require('../src/options') const { getFiles } = require('../src/datatypes/util') const { join } = require('path') -const fileMap = {} +let fileMap = {} // Walks all the directories for each of the supported versions in options.js // then builds a file map for each version @@ -23,6 +23,8 @@ function loadVersions () { } module.exports = (protocolVersion) => { + fileMap = {} + loadVersions() return { // Returns the most recent file based on the specified protocolVersion // e.g. if `version` is 1.16 and a file for 1.16 doesn't exist, load from 1.15 file @@ -40,5 +42,3 @@ module.exports = (protocolVersion) => { } } } - -loadVersions() diff --git a/examples/clientTest.js b/examples/clientTest.js index 157f450..bcb644e 100644 --- a/examples/clientTest.js +++ b/examples/clientTest.js @@ -1,10 +1,13 @@ process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('bedrock-protocol') +const { ChunkColumn, Version } = require('bedrock-provider') async function test () { const client = new Client({ hostname: '127.0.0.1', port: 19132 + // You can specify version by adding : + // version: '1.16.210' }) client.once('resource_packs_info', (packet) => { @@ -20,23 +23,21 @@ async function test () { }) }) - // client.once('resource_packs_info', (packet) => { - // client.write('resource_pack_client_response', { - // response_status: 'completed', - // resourcepackids: [] - // }) - // }) - client.queue('client_cache_status', { enabled: false }) client.queue('request_chunk_radius', { chunk_radius: 1 }) client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) }) - // var read = 0; - // client.on('level_chunk', (packet) => { - // read++ - // fs.writeFileSync(`level_chunk-${read}.json`, JSON.stringify(packet, null, 2)) - // }) + client.on('level_chunk', async packet => { + const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + await cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count) + const blocks = [] + for (let x = 0; x < 16; x++) { + for (let z = 0; z < 16; z++) { + blocks.push(cc.getBlock(x, 0, z)) // Read some blocks in this chunk + } + } + }) } test() diff --git a/examples/serverChunks.js b/examples/serverChunks.js new file mode 100644 index 0000000..0b711c4 --- /dev/null +++ b/examples/serverChunks.js @@ -0,0 +1,48 @@ +// CHUNKS +const { WorldProvider } = require('bedrock-provider') +const { LevelDB } = require('leveldb-zlib') +const { join } = require('path') + +async function loadWorld (version) { + const path = join(__dirname, `../tools/bds-${version}/worlds/Bedrock level/db`) + console.log('Loading world at path', path) // Load world from testing server + const db = new LevelDB(path, { createIfMissing: false }) + await db.open() + const wp = new WorldProvider(db, { dimension: 0 }) + + async function requestChunks (x, z, radius) { + const chunks = [] + const cxStart = (x >> 4) - radius + const cxEnd = (x >> 4) + radius + const czStart = (z >> 4) - radius + const czEnd = (z >> 4) + radius + + for (let cx = cxStart; cx < cxEnd; cx++) { + for (let cz = czStart; cz < czEnd; cz++) { + // console.log('reading chunk at ', cx, cz) + + const cc = await wp.load(cx, cz, true) + if (!cc) { + // console.log('no chunk') + continue + } + const cbuf = await cc.networkEncodeNoCache() + chunks.push({ + x: cx, + z: cz, + sub_chunk_count: cc.sectionsLen, + cache_enabled: false, + blobs: [], + payload: cbuf + }) + // console.log('Ht',cc.sectionsLen,cc.sections) + } + } + + return chunks + } + + return { requestChunks } +} + +module.exports = { loadWorld } diff --git a/examples/serverTest.js b/examples/serverTest.js index 5006736..58b083e 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -1,39 +1,57 @@ -const fs = require('fs') -process.env.DEBUG = 'minecraft-protocol raknet' +/** + * bedrock-protocol server example; to run this example you need to clone this repo from git. + * first need to dump some packets from the vanilla server as there is alot of boilerplate + * to send to clients. + * + * In your server implementation, you need to implement each of the following packets to + * get a client to spawn like vanilla. You can look at the dumped packets in `data/1.16.10/sample` + * + * First, dump packets for version 1.16.210 by running `npm run dumpPackets`. + */ +process.env.DEBUG = 'minecraft-protocol' // packet logging +// const fs = require('fs') const { Server } = require('../src/server') -// const CreativeItems = require('../data/creativeitems.json') +const { hasDumps } = require('../tools/genPacketDumps') const DataProvider = require('../data/provider') +const { waitFor } = require('../src/datatypes/util') +const { loadWorld } = require('./serverChunks') -const server = new Server({ +async function startServer (version = '1.16.210', ok) { + if (!hasDumps(version)) { + throw Error('You need to dump some packets first. Run tools/genPacketDumps.js') + } -}) -server.create('0.0.0.0', 19132) + const Item = require('../types/Item')(version) + const port = 19132 + const server = new Server({ hostname: '0.0.0.0', port, version }) + let loop -function getPath (packetPath) { - return DataProvider(server.options.protocolVersion).getPath(packetPath) -} + const getPath = (packetPath) => DataProvider(server.options.protocolVersion).getPath(packetPath) + const get = (packetPath) => require(getPath('sample/' + packetPath)) -function get (packetPath) { - return require(getPath('sample/' + packetPath)) -} + server.listen() + console.log('Started server') -// const ran = false + // Find the center position from the dumped packets + const respawnPacket = get('packets/respawn.json') + const world = await loadWorld(version) + const chunks = await world.requestChunks(respawnPacket.x, respawnPacket.z, 2) -server.on('connect', ({ client }) => { - /** @type {Player} */ - client.on('join', () => { - console.log('Client joined', client.getData()) + // Connect is emitted when a client first joins our server, before authing them + server.on('connect', client => { + // Join is emitted after the client has been authenticated and encryption has started + client.on('join', () => { + console.log('Client joined', client.getData()) - // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It - // sends a list of the resource packs it has and basic information on them like the version and description. - client.write('resource_packs_info', { - must_accept: false, - has_scripts: false, - behaviour_packs: [], - texture_packs: [] - }) + // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It + // sends a list of the resource packs it has and basic information on them like the version and description. + client.write('resource_packs_info', { + must_accept: false, + has_scripts: false, + behaviour_packs: [], + texture_packs: [] + }) - client.once('resource_pack_client_response', async (packet) => { // ResourcePackStack is sent by the server to send the order in which resource packs and behaviour packs // should be applied (and downloaded) by the client. client.write('resource_pack_stack', { @@ -45,109 +63,83 @@ server.on('connect', ({ client }) => { experiments_previously_used: false }) - client.once('resource_pack_client_response', async (packet) => { + client.once('resource_pack_client_response', async rp => { + // Tell the server we will compress everything (>=1 byte) + client.write('network_settings', { compression_threshold: 1 }) + // Send some inventory slots + for (let i = 0; i < 3; i++) { + client.queue('inventory_slot', { window_id: 120, slot: 0, item: new Item().toBedrock() }) + } - }) + client.write('player_list', get('packets/player_list.json')) + client.write('start_game', get('packets/start_game.json')) + client.write('item_component', { entries: [] }) + client.write('set_spawn_position', get('packets/set_spawn_position.json')) + client.write('set_time', { time: 5433771 }) + client.write('set_difficulty', { difficulty: 1 }) + client.write('set_commands_enabled', { enabled: true }) + client.write('adventure_settings', get('packets/adventure_settings.json')) + client.write('biome_definition_list', get('packets/biome_definition_list.json')) + client.write('available_entity_identifiers', get('packets/available_entity_identifiers.json')) + client.write('update_attributes', get('packets/update_attributes.json')) + client.write('creative_content', get('packets/creative_content.json')) + client.write('inventory_content', get('packets/inventory_content.json')) + client.write('player_hotbar', { selected_slot: 3, window_id: 'inventory', select_slot: true }) + client.write('crafting_data', get('packets/crafting_data.json')) + client.write('available_commands', get('packets/available_commands.json')) + client.write('chunk_radius_update', { chunk_radius: 1 }) + client.write('game_rules_changed', get('packets/game_rules_changed.json')) + client.write('respawn', get('packets/respawn.json')) - client.write('network_settings', { - compression_threshold: 1 - }) + for (const chunk of chunks) { + client.queue('level_chunk', chunk) + } - for (let i = 0; i < 3; i++) { - client.queue('inventory_slot', { inventory_id: 120, slot: i, uniqueid: 0, item: { network_id: 0 } }) - } + // Uncomment below and comment above to send dumped chunks. We use bedrock-provider in this example which is still a WIP, some blocks may be broken. + // for (const file of fs.readdirSync(`../data/${server.options.version}/sample/chunks`)) { + // const buffer = fs.readFileSync(`../data/${server.options.version}/sample/chunks/` + file) + // // console.log('Sending chunk', buffer) + // client.sendBuffer(buffer) + // } - client.queue('inventory_transaction', get('packets/inventory_transaction.json')) - client.queue('player_list', get('packets/player_list.json')) - client.queue('start_game', get('packets/start_game.json')) - client.queue('item_component', { entries: [] }) - client.queue('set_spawn_position', get('packets/set_spawn_position.json')) - client.queue('set_time', { time: 5433771 }) - client.queue('set_difficulty', { difficulty: 1 }) - client.queue('set_commands_enabled', { enabled: true }) - client.queue('adventure_settings', get('packets/adventure_settings.json')) + // Constantly send this packet to the client to tell it the center position for chunks. The client should then request these + // missing chunks from the us if it's missing any within the radius. `radius` is in blocks. + loop = setInterval(() => { + client.write('network_chunk_publisher_update', { coordinates: { x: respawnPacket.x, y: 130, z: respawnPacket.z }, radius: 80 }) + }, 4500) - client.queue('biome_definition_list', get('packets/biome_definition_list.json')) - client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) + // Wait some time to allow for the client to recieve and load all the chunks + setTimeout(() => { + // Allow the client to spawn + client.write('play_status', { status: 'player_spawn' }) + }, 6000) - client.queue('update_attributes', get('packets/update_attributes.json')) - client.queue('creative_content', get('packets/creative_content.json')) - client.queue('inventory_content', get('packets/inventory_content.json')) - client.queue('player_hotbar', { selected_slot: 3, window_id: 0, select_slot: true }) - - client.queue('crafting_data', get('packets/crafting_data.json')) - client.queue('available_commands', get('packets/available_commands.json')) - client.queue('chunk_radius_update', { chunk_radius: 5 }) - - client.queue('set_entity_data', get('packets/set_entity_data.json')) - - client.queue('game_rules_changed', get('packets/game_rules_changed.json')) - client.queue('respawn', { x: 646.9405517578125, y: 65.62001037597656, z: 77.86255645751953, state: 0, runtime_entity_id: 0 }) - - for (const file of fs.readdirSync(`../data/${server.options.version}/sample/chunks`)) { - const buffer = Buffer.from(fs.readFileSync(`../data/${server.options.version}/sample/chunks/` + file, 'utf8'), 'hex') - // console.log('Sending chunk', chunk) - client.sendBuffer(buffer) - } - - // for (const chunk of chunks) { - // client.queue('level_chunk', chunk) - // } - - setInterval(() => { - client.write('network_chunk_publisher_update', { coordinates: { x: 646, y: 130, z: 77 }, radius: 64 }) - }, 9500) - - setTimeout(() => { - client.write('play_status', { status: 'player_spawn' }) - }, 8000) - - // Respond to tick synchronization packets - client.on('tick_sync', (packet) => { - client.queue('tick_sync', { - request_time: packet.request_time, - response_time: BigInt(Date.now()) + // Respond to tick synchronization packets + client.on('tick_sync', (packet) => { + client.queue('tick_sync', { + request_time: packet.request_time, + response_time: BigInt(Date.now()) + }) }) }) }) }) + + ok() + + return { + kill: () => { + clearInterval(loop) + server.close() + } + } +} + +let server +waitFor((res) => { + server = startServer(process.argv[2], res) +}, 1000 * 60 /* Wait 60 seconds for the server to start */, function onTimeout () { + console.error('Server did not start in time') + server?.close() + process.exit(1) }) - -// CHUNKS -// const { ChunkColumn, Version } = require('bedrock-provider') -// const mcData = require('minecraft-data')('1.16') -// const chunks = [] -// async function buildChunks () { -// // "x": 40, -// // "z": 4, - -// const stone = mcData.blocksByName.stone - -// for (let cx = 35; cx < 45; cx++) { -// for (let cz = 0; cz < 8; cz++) { -// const column = new ChunkColumn(Version.v1_2_0_bis, x, z) -// for (let x = 0; x < 16; x++) { -// for (let y = 0; y < 60; y++) { -// for (let z = 0; z < 16; z++) { -// column.setBlock(x, y, z, stone) -// } -// } -// } - -// const ser = await column.networkEncodeNoCache() - -// chunks.push({ -// x: cx, -// z: cz, -// sub_chunk_count: column.sectionsLen, -// cache_enabled: false, -// blobs: [], -// payload: ser -// }) -// } -// } - -// // console.log('Chunks',chunks) -// } - -// // buildChunks() diff --git a/package.json b/package.json index aec7b49..9be65ba 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,11 @@ "scripts": { "build": "cd tools && node compileProtocol.js", "prepare": "npm run build", - "test": "mocha", + "test": "mocha --bail", "pretest": "npm run lint", "lint": "standard", "vanillaServer": "node tools/startVanillaServer.js", + "dumpPackets": "node tools/genPacketDumps.js", "fix": "standard --fix" }, "keywords": [ @@ -33,7 +34,7 @@ "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", "protodef": "^1.11.0", - "raknet-native": "^0.1.0", + "raknet-native": "^0.2.0", "uuid-1345": "^1.0.2" }, "devDependencies": { diff --git a/src/auth/loginVerify.js b/src/auth/loginVerify.js index 6d21e41..e1c2743 100644 --- a/src/auth/loginVerify.js +++ b/src/auth/loginVerify.js @@ -17,10 +17,10 @@ module.exports = (client, server, options) => { let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it let finalKey = null - console.log(pubKey) + // console.log(pubKey) for (const token of chain) { const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) - console.log('Decoded', decoded) + // console.log('Decoded', decoded) // Check if signed by Mojang key const x5u = getX5U(token) @@ -69,7 +69,6 @@ function getX5U (token) { } function mcPubKeyToPem (mcPubKeyBuffer) { - console.log(mcPubKeyBuffer) if (mcPubKeyBuffer[0] === '-') return mcPubKeyBuffer let pem = '-----BEGIN PUBLIC KEY-----\n' let base64PubKey = mcPubKeyBuffer.toString('base64') diff --git a/src/client.js b/src/client.js index 47c5a60..2fb3ce1 100644 --- a/src/client.js +++ b/src/client.js @@ -41,6 +41,7 @@ class Client extends Connection { } this.startGameData = {} + this.clientRuntimeId = null this.startQueue() this.inLog = (...args) => debug('C ->', ...args) @@ -60,6 +61,10 @@ class Client extends Connection { } } + get entityId () { + return this.startGameData.runtime_entity_id + } + onEncapsulated = (encapsulated, inetAddr) => { const buffer = Buffer.from(encapsulated.buffer) this.handle(buffer) @@ -108,30 +113,29 @@ class Client extends Connection { } onDisconnectRequest (packet) { - // We're talking over UDP, so there is no connection to close, instead - // we stop communicating with the server - console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) - process.exit(1) // TODO: handle + console.warn(`C Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) + this.emit('kick', packet) } onPlayStatus (statusPacket) { if (this.status === ClientStatus.Initializing && this.options.autoInitPlayer === true) { if (statusPacket.status === 'player_spawn') { this.status = ClientStatus.Initialized - this.write('set_local_player_as_initialized', { runtime_entity_id: this.startGameData.runtime_entity_id }) + this.write('set_local_player_as_initialized', { runtime_entity_id: this.entityId }) this.emit('spawn') } } } close () { + this.emit('close') clearInterval(this.loop) clearTimeout(this.connectTimeout) this.q = [] this.q2 = [] this.connection?.close() this.removeAllListeners() - console.log('Closed!') + console.log('Client closed!') } tryRencode (name, params, actual) { @@ -155,22 +159,13 @@ class Client extends Connection { const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100) */) + this.emit('packet', des) if (debugging) { // Packet verifying (decode + re-encode + match test) if (pakData.name) { this.tryRencode(pakData.name, pakData.params, packet) } - - // console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v)) - // Packet dumping - try { - const root = __dirname + `../data/${this.options.version}/sample/` - if (!fs.existsSync(root + `packets/${pakData.name}.json`)) { - fs.writeFileSync(root + `packets/${pakData.name}.json`, serialize(pakData.params, 2)) - fs.writeFileSync(root + `packets/${pakData.name}.txt`, packet.toString('hex')) - } - } catch { } } // Abstract some boilerplate before sending to listeners @@ -188,7 +183,10 @@ class Client extends Connection { this.onPlayStatus(pakData.params) break default: - // console.log('Sending to listeners') + if (this.status !== ClientStatus.Initializing && this.status !== ClientStatus.Initialized) { + this.inLog(`Can't accept ${des.data.name}, client not yet authenticated : ${this.status}`) + return + } } // Emit packet diff --git a/src/connection.js b/src/connection.js index 220013c..a9061c0 100644 --- a/src/connection.js +++ b/src/connection.js @@ -16,6 +16,8 @@ const ClientStatus = { class Connection extends EventEmitter { status = ClientStatus.Disconnected + q = [] + q2 = [] versionLessThan (version) { if (typeof version === 'string') { @@ -121,7 +123,7 @@ class Connection extends EventEmitter { // TODO: Rename this to sendEncapsulated sendMCPE (buffer, immediate) { - if (this.connection.connected === false) return + if (this.connection.connected === false || this.status === ClientStatus.Disconnected) return this.connection.sendReliable(buffer, immediate) } diff --git a/src/server.js b/src/server.js index 2c5187c..bf440d3 100644 --- a/src/server.js +++ b/src/server.js @@ -15,8 +15,8 @@ class Server extends EventEmitter { /** @type {Object} */ this.clients = {} this.clientCount = 0 - this.inLog = (...args) => debug('C -> S', ...args) - this.outLog = (...args) => debug('S -> C', ...args) + this.inLog = (...args) => debug('S ->', ...args) + this.outLog = (...args) => debug('S <-', ...args) } validateOptions () { @@ -40,6 +40,8 @@ class Server extends EventEmitter { onCloseConnection = (inetAddr, reason) => { console.debug('close connection', inetAddr, reason) + delete this.clients[inetAddr]?.connection // Prevent close loop + this.clients[inetAddr]?.close() delete this.clients[inetAddr] this.clientCount-- } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 49f7917..b11d8f4 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -1,6 +1,7 @@ const { ClientStatus, Connection } = require('./connection') const fs = require('fs') const Options = require('./options') +const debug = require('debug')('minecraft-protocol') const { Encrypt } = require('./auth/encryption') const Login = require('./auth/login') @@ -21,8 +22,8 @@ class Player extends Connection { this.startQueue() this.status = ClientStatus.Authenticating - this.inLog = (...args) => console.info('S -> C', ...args) - this.outLog = (...args) => console.info('C -> S', ...args) + this.inLog = (...args) => debug('S ->', ...args) + this.outLog = (...args) => debug('S <-', ...args) } getData () { @@ -82,7 +83,7 @@ class Player extends Connection { /** * Disconnects a client */ - disconnect (reason, hide = false) { + disconnect (reason = 'Server closed', hide = false) { if ([ClientStatus.Authenticating, ClientStatus.Initializing].includes(this.status)) { this.sendDisconnectStatus('failed_server_full') } else { @@ -110,6 +111,7 @@ class Player extends Connection { clearInterval(this.loop) this.connection?.close() this.removeAllListeners() + this.status = ClientStatus.Disconnected } readPacket (packet) { @@ -124,10 +126,9 @@ class Player extends Connection { throw e } - console.log('-> S', des) switch (des.data.name) { case 'login': - console.log(des) + // console.log(des) this.onLogin(des) return case 'client_to_server_handshake': @@ -136,11 +137,12 @@ class Player extends Connection { break case 'set_local_player_as_initialized': this.status = ClientStatus.Initialized + this.inLog('Server client spawned') // Emit the 'spawn' event this.emit('spawn') break default: - console.log('ignoring, unhandled') + // console.log('ignoring, unhandled') } this.emit(des.data.name, des.data.params) } diff --git a/test/internal.js b/test/internal.js new file mode 100644 index 0000000..40aeb5e --- /dev/null +++ b/test/internal.js @@ -0,0 +1,204 @@ +// process.env.DEBUG = 'minecraft-protocol raknet' +const { Server, Client } = require('../') +const { dumpPackets, hasDumps } = require('../tools/genPacketDumps') +const DataProvider = require('../data/provider') + +// First we need to dump some packets that a vanilla server would send a vanilla +// client. Then we can replay those back in our custom server. +function prepare (version) { + if (!hasDumps(version)) { + return dumpPackets(version) + } +} + +async function startTest (version = '1.16.210', ok) { + await prepare(version) + const Item = require('../types/Item')(version) + const port = 19130 + const server = new Server({ hostname: '0.0.0.0', port, version }) + + function getPath (packetPath) { + return DataProvider(server.options.protocolVersion).getPath(packetPath) + } + + function get (packetPath) { + return require(getPath('sample/' + packetPath)) + } + + server.listen() + console.log('Started server') + + const respawnPacket = get('packets/respawn.json') + const chunks = await requestChunks(respawnPacket.x, respawnPacket.z, 1) + + let loop + + // server logic + server.on('connect', client => { + client.on('join', () => { + console.log('Client joined', client.getData()) + + client.write('resource_packs_info', { + must_accept: false, + has_scripts: false, + behaviour_packs: [], + texture_packs: [] + }) + + client.once('resource_pack_client_response', async rp => { + // Tell the server we will compress everything (>=1 byte) + client.write('network_settings', { compression_threshold: 1 }) + // Send some inventory slots + for (let i = 0; i < 3; i++) { + client.queue('inventory_slot', { window_id: 'armor', slot: 0, item: new Item().toBedrock() }) + } + + // client.queue('inventory_transaction', get('packets/inventory_transaction.json')) + client.queue('player_list', get('packets/player_list.json')) + client.queue('start_game', get('packets/start_game.json')) + client.queue('item_component', { entries: [] }) + client.queue('set_spawn_position', get('packets/set_spawn_position.json')) + client.queue('set_time', { time: 5433771 }) + client.queue('set_difficulty', { difficulty: 1 }) + client.queue('set_commands_enabled', { enabled: true }) + client.queue('adventure_settings', get('packets/adventure_settings.json')) + + client.queue('biome_definition_list', get('packets/biome_definition_list.json')) + client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) + + client.queue('update_attributes', get('packets/update_attributes.json')) + client.queue('creative_content', get('packets/creative_content.json')) + client.queue('inventory_content', get('packets/inventory_content.json')) + + client.queue('player_hotbar', { selected_slot: 3, window_id: 'inventory', select_slot: true }) + + client.queue('crafting_data', get('packets/crafting_data.json')) + client.queue('available_commands', get('packets/available_commands.json')) + client.queue('chunk_radius_update', { chunk_radius: 5 }) + + // client.queue('set_entity_data', get('packets/set_entity_data.json')) + + client.queue('game_rules_changed', get('packets/game_rules_changed.json')) + client.queue('respawn', get('packets/respawn.json')) + + for (const chunk of chunks) { + client.queue('level_chunk', chunk) + } + + loop = setInterval(() => { + client.write('network_chunk_publisher_update', { coordinates: { x: 646, y: 130, z: 77 }, radius: 64 }) + }, 9500) + + setTimeout(() => { + client.write('play_status', { status: 'player_spawn' }) + }, 6000) + + // Respond to tick synchronization packets + client.on('tick_sync', (packet) => { + client.queue('tick_sync', { + request_time: packet.request_time, + response_time: BigInt(Date.now()) + }) + }) + }) + }) + }) + + // client logic + const client = new Client({ + hostname: '127.0.0.1', + port, + username: 'Notch', + version, + offline: true + }) + + console.log('Started client') + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) + + client.once('spawn', () => { + console.info('Client spawend!') + setTimeout(() => { + client.close() + + server.close() + ok?.() + }, 500) + clearInterval(loop) + }) +} + +const { ChunkColumn, Version } = require('bedrock-provider') +const { waitFor } = require('../src/datatypes/util') +const mcData = require('minecraft-data')('1.16') + +async function requestChunks (x, z, radius) { + const cxStart = (x >> 4) - radius + const cxEnd = (x >> 4) + radius + const czStart = (z >> 4) - radius + const czEnd = (z >> 4) + radius + + const stone = mcData.blocksByName.stone + const chunks = [] + + for (let cx = cxStart; cx < cxEnd; cx++) { + for (let cz = czStart; cz < czEnd; cz++) { + console.log('reading chunk at ', cx, cz) + const cc = new ChunkColumn(Version.v1_2_0_bis, x, z) + + for (let x = 0; x < 16; x++) { + for (let y = 0; y < 60; y++) { + for (let z = 0; z < 16; z++) { + cc.setBlock(x, y, z, stone) + } + } + } + + if (!cc) { + console.log('no chunk') + continue + } + const cbuf = await cc.networkEncodeNoCache() + chunks.push({ + x: cx, + z: cz, + sub_chunk_count: cc.sectionsLen, + cache_enabled: false, + blobs: [], + payload: cbuf + }) + // console.log('Ht',cc.sectionsLen,cc.sections) + } + } + + return chunks +} + +async function timedTest (version, timeout = 1000 * 120) { + await waitFor((res) => { + startTest(version, res) + }, timeout, () => { + throw Error('timed out') + }) + console.info('✔ ok') +} + +if (!module.parent) timedTest() +module.exports = { startTest, timedTest, requestChunks } diff --git a/test/internal.test.js b/test/internal.test.js new file mode 100644 index 0000000..e3feeac --- /dev/null +++ b/test/internal.test.js @@ -0,0 +1,11 @@ +/* eslint-env jest */ + +const { timedTest } = require('./internal') + +describe('internal client/server test', function () { + this.timeout(120 * 1000) + + it('connects', async () => { + await timedTest() + }) +}) diff --git a/test/vanilla.js b/test/vanilla.js index 1088396..4f37d6b 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -2,6 +2,7 @@ const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') const { waitFor } = require('../src/datatypes/util') +const { ChunkColumn, Version } = require('bedrock-provider') async function test (version) { // Start the server, wait for it to accept clients, throws on timeout @@ -42,6 +43,11 @@ async function test (version) { client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: BigInt(Date.now()) }) }, 200) + client.on('level_chunk', async packet => { // Chunk read test + const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + await cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count) + }) + console.log('Awaiting join') client.on('spawn', () => { diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js new file mode 100644 index 0000000..5add677 --- /dev/null +++ b/tools/genPacketDumps.js @@ -0,0 +1,100 @@ +// Collect sample packets needed for `serverTest.js` +// process.env.DEBUG = 'minecraft-protocol' +const fs = require('fs') +const vanillaServer = require('../tools/startVanillaServer') +const { Client } = require('../src/client') +const { serialize, waitFor, getFiles } = require('../src/datatypes/util') +const { CURRENT_VERSION } = require('../src/options') +const { join } = require('path') + +function hasDumps (version) { + const root = join(__dirname, `../data/${version}/sample/packets/`) + if (!fs.existsSync(root) || getFiles(root).length < 10) { + return false + } + return true +} + +let loop + +async function dump (version, force) { + const random = ((Math.random() * 100) | 0) + const port = 19130 + random + + const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port }) + + console.log('Started server') + const client = new Client({ + hostname: '127.0.0.1', + port, + username: 'Boat' + random, + offline: true + }) + + return waitFor(async res => { + const root = join(__dirname, `../data/${client.options.version}/sample/`) + if (!fs.existsSync(root + 'packets') || !fs.existsSync(root + 'chunks')) { + fs.mkdirSync(root + 'packets', { recursive: true }) + fs.mkdirSync(root + 'chunks', { recursive: true }) + } + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + // client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + + clearInterval(loop) + loop = setInterval(() => { + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: BigInt(Date.now()) }) + }, 200) + }) + + let i = 0 + + client.on('packet', async packet => { // Packet dumping + const { name, params } = packet.data + if (name === 'level_chunk') { + fs.writeFileSync(root + `chunks/${name}-${i++}.bin`, packet.buffer) + return + } + try { + if (!fs.existsSync(root + `packets/${name}.json`) || force) { + fs.writeFileSync(root + `packets/${name}.json`, serialize(params, 2)) + } + } catch (e) { console.log(e) } + }) + + console.log('Awaiting join...') + + client.on('spawn', () => { + console.log('Spawned!') + clearInterval(loop) + client.close() + handle.kill() + res() + }) + }, 1000 * 60, () => { + clearInterval(loop) + handle.kill() + throw Error('timed out') + }) +} + +if (!module.parent) { + dump(null, true).then(() => { + console.log('Successfully dumped packets') + }) +} +module.exports = { dumpPackets: dump, hasDumps } diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 83856f4..07587ae 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -17,18 +17,18 @@ function fetchLatestStable () { } // Download + extract vanilla server and enter the directory -async function download (os, version) { +async function download (os, version, path = 'bds-') { process.chdir(__dirname) const verStr = version.split('.').slice(0, 3).join('.') - const dir = 'bds-' + version + const dir = path + version if (fs.existsSync(dir) && getFiles(dir).length) { - process.chdir('bds-' + version) // Enter server folder + process.chdir(path + version) // Enter server folder return verStr } try { fs.mkdirSync(dir) } catch { } - process.chdir('bds-' + version) // Enter server folder + process.chdir(path + version) // Enter server folder const url = (os, version) => `https://minecraft.azureedge.net/bin-${os}/bedrock-server-${version}.zip` let found = false @@ -53,10 +53,18 @@ async function download (os, version) { return verStr } +const defaultOptions = { + 'level-generator': '2', + 'server-port': '19130', + 'online-mode': 'false' +} + // Setup the server -function configure () { +function configure (options = {}) { + const opts = { ...defaultOptions, ...options } let config = fs.readFileSync('./server.properties', 'utf-8') - config += '\nlevel-generator=2\nserver-port=19130\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator\nonline-mode=false' + config += '\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator' + for (const o in opts) config += `\n${o}=${opts[o]}` fs.writeFileSync('./server.properties', config) } @@ -66,13 +74,13 @@ function run (inheritStdout = true) { } // Run the server -async function startServer (version, onStart) { +async function startServer (version, onStart, options = {}) { const os = process.platform === 'win32' ? 'win' : process.platform if (os !== 'win' && os !== 'linux') { throw Error('unsupported os ' + os) } - await download(os, version) - configure() + await download(os, version, options.path) + configure(options) const handle = run(!onStart) if (onStart) { handle.stdout.on('data', data => data.includes('Server started.') ? onStart() : null) @@ -83,10 +91,10 @@ async function startServer (version, onStart) { } // Start the server and wait for it to be ready, with a timeout -async function startServerAndWait (version, withTimeout) { +async function startServerAndWait (version, withTimeout, options) { let handle await waitFor(async res => { - handle = await startServer(version, res) + handle = await startServer(version, res, options) }, withTimeout, () => { handle?.kill() throw new Error('Server did not start on time ' + withTimeout) diff --git a/types/Item.js b/types/Item.js new file mode 100644 index 0000000..eb4d804 --- /dev/null +++ b/types/Item.js @@ -0,0 +1,37 @@ +module.exports = (version) => + class Item { + nbt + constructor (obj) { + this.networkId = 0 + this.runtimeId = 0 + this.count = 0 + this.metadata = 0 + Object.assign(this, obj) + this.version = version + } + + static fromBedrock (obj) { + return new Item({ + runtimeId: obj.runtime_id, + networkId: obj.item?.network_id, + count: obj.item?.auxiliary_value & 0xff, + metadata: obj.item?.auxiliary_value >> 8, + nbt: obj.item?.nbt?.nbt + }) + } + + toBedrock () { + return { + runtime_id: this.runtimeId, + item: { + network_id: this.networkId, + auxiliary_value: (this.metadata << 8) | (this.count & 0xff), + has_nbt: !!this.nbt, + nbt: { version: 1, nbt: this.nbt }, + can_place_on: [], + can_destroy: [], + blocking_tick: 0 + } + } + } + } From f5321dd277321f6ce8cd897b76b3f94e086e7678 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 30 Mar 2021 01:39:28 -0400 Subject: [PATCH 145/458] create pviewer exxample --- examples/viewer/client/BotProvider.js | 195 ++++++++++++++++++++++++++ examples/viewer/client/BotViewer.js | 68 +++++++++ examples/viewer/client/Chunk.js | 56 ++++++++ examples/viewer/client/app.css | 22 +++ examples/viewer/client/index.html | 22 +++ examples/viewer/client/index.js | 4 + examples/viewer/client/preload.js | 9 ++ examples/viewer/client/worker.js | 2 + examples/viewer/index.js | 37 +++++ examples/viewer/package.json | 13 ++ 10 files changed, 428 insertions(+) create mode 100644 examples/viewer/client/BotProvider.js create mode 100644 examples/viewer/client/BotViewer.js create mode 100644 examples/viewer/client/Chunk.js create mode 100644 examples/viewer/client/app.css create mode 100644 examples/viewer/client/index.html create mode 100644 examples/viewer/client/index.js create mode 100644 examples/viewer/client/preload.js create mode 100644 examples/viewer/client/worker.js create mode 100644 examples/viewer/index.js create mode 100644 examples/viewer/package.json diff --git a/examples/viewer/client/BotProvider.js b/examples/viewer/client/BotProvider.js new file mode 100644 index 0000000..d6c733b --- /dev/null +++ b/examples/viewer/client/BotProvider.js @@ -0,0 +1,195 @@ +/* eslint-disable */ +const { Client } = require('bedrock-protocol') +const { Version } = require('bedrock-provider') +const { WorldView } = require('prismarine-viewer/viewer') +const vec3, { Vec3 } = require('vec3') +const World = require('prismarine-world')() +const ChunkColumn = require('./Chunk')() +const Physics = require('prismarine-physics') + +class BotProvider extends WorldView { + chunks = {} + lastSentPos + + constructor() { + super() + this.connect() + this.listenToBot() + this.world = new World() + + // Server auth movement : we send inputs, server calculates position & sends back + this.serverMovements = true + + this.tick = 0n + } + + connect() { + const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', port: 19132, connectTimeout: 100000 }) + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) + + this.client = client + } + + listenToBot() { + this.client.on('connect', () => { + console.log('Bot has connected!') + }) + this.client.on('start_game', packet => { + this.updatePosition(packet.player_position) + }) + + this.client.on('spawn', () => { + // server allows client to render chunks & spawn in world + this.emit('spawn', { position: this.lastPos }) + }) + + this.client.on('level_chunk', packet => { + const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count).then(() => { + this.loadedChunks[(packet.x << 4) + ',' + (packet.z << 4)] = true + this.world.setColumn(packet.x, packet.z, cc) + const chunk = cc.serialize() + console.log('Chunk', chunk) + this.emitter.emit('loadChunk', { x: packet.x << 4, z: packet.z << 4, chunk }) + }) + }) + + this.client.on('move_player', packet => { + if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) + }) + + this.client.on('set_entity_motion', packet=>{ + if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) + }) + + this.client.on('tick_sync', (packet) => { + this.lastTick = packet.request_time + }) + + this.tickLoop = setInterval(() => { + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) + } + + stopBot() { + clearInterval(this.tickLoop) + } + + // Server gives us a new position + updatePosition(pos) { + this.lastPos ??= vec3(pos) + super.updatePosition(this.lastPos) + } + + // Ask the server to be in a new position + requestPosition() { + const positionUpdated = !this.lastSentPos || !this.lastPos.equals(this.lastSentPos) + + if (positionUpdated) { + this.client.queue('player_auth_input', { + pitch: 0, + yaw: this.lastYaw, + position: { + x: this.lastPos.x, + y: this.lastPos.y, + z: this.lastPos.z + }, + move_vector: { x: 0, z: 0 }, + head_yaw: 0, + input_data: { + ascend: false, + descend: false, + north_jump: false, + jump_down: false, + sprint_down: false, + change_height: false, + jumping: false, + auto_jumping_in_water: false, + sneaking: false, + sneak_down: false, + up: false, + down: false, + left: false, + right: false, + up_left: false, + up_right: false, + want_up: false, + want_down: false, + want_down_slow: false, + want_up_slow: false, + sprinting: false, + ascend_scaffolding: false, + descend_scaffolding: false, + sneak_toggle_down: false, + persist_sneak: false + }, + input_mode: 'mouse', + play_mode: 'screen', + tick: this.tick, + delta: { x: 0, y: -0.07840000092983246, z: 0 } + }) + } + } + + initPhys() { + this.lastVel = new Vec3(0, 0, 0) + this.lastYaw = 0 + this.player = { + entity: { + position: this.lastPos, + velocity: this.lastVel, + onGround: false, + isInWater: false, + isInLava: false, + isInWeb: false, + isCollidedHorizontally: false, + isCollidedVertically: false, + yaw: this.lastYaw + }, + jumpTicks: 0, + jumpQueued: false + } + + this.physics = Physics(mcData, fakeWorld) + this.controls = { + forward: false, + back: false, + left: false, + right: false, + jump: false, + sprint: false, + sneak: false + } + this.playerState = new PlayerState(this.player, this.controls) + } + + startPhys() { + this.physicsLoop = setInterval(() => { + this.physics.simulatePlayer(this.playerState, this.world).apply(this.player) + this.requestPosition() + }, 50) + } + + stopPhys() { + clearInterval(this.physics) + } +} + +module.exports = { BotProvider } diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js new file mode 100644 index 0000000..3782824 --- /dev/null +++ b/examples/viewer/client/BotViewer.js @@ -0,0 +1,68 @@ +/* global THREE */ +const { Viewer, MapControls } = require('prismarine-viewer/viewer') +const { Vec3 } = require('vec3') +const { BotProvider } = require('./BotProvider') +global.THREE = require('three') + +const MCVER = '1.16.1' + +class BotViewer { + constructor() { + // Create viewer data provider + this.world = new BotProvider() + } + + start() { + this.worldView = new BotProvider() + + // Create three.js context, add to page + this.renderer = new THREE.WebGLRenderer() + this.renderer.setPixelRatio(window.devicePixelRatio || 1) + this.renderer.setSize(window.innerWidth, window.innerHeight) + document.body.appendChild(this.renderer.domElement) + + // Create viewer + this.viewer = new Viewer(this.renderer) + this.viewer.setVersion(MCVER) + // Attach controls to viewer + this.controls = new MapControls(this.viewer.camera, this.renderer.domElement) + // Enable damping (inertia) on movement + this.controls.enableDamping = true + this.controls.dampingFactor = 0.09 + console.info('Registered handlers') + // Link WorldView and Viewer + this.viewer.listen(this.worldView) + + this.worldView.on('spawn', ({ position }) => { + // Initialize viewer, load chunks + this.worldView.init(position) + }) + + this.controls.update() + + // Browser animation loop + const animate = () => { + window.requestAnimationFrame(animate) + if (this.controls) this.controls.update() + this.viewer.update() + this.renderer.render(this.viewer.scene, this.viewer.camera) + } + animate() + + window.addEventListener('resize', () => { + this.viewer.camera.aspect = window.innerWidth / window.innerHeight + this.viewer.camera.updateProjectionMatrix() + this.renderer.setSize(window.innerWidth, window.innerHeight) + }) + } + + onKeyDown = () => { + + } + + registerBrowserEvents() { + this.renderer.domElement.addEventListener('keydown', this.onKeyDown) + } +} + +module.exports = { BotViewer } diff --git a/examples/viewer/client/Chunk.js b/examples/viewer/client/Chunk.js new file mode 100644 index 0000000..fdfd29f --- /dev/null +++ b/examples/viewer/client/Chunk.js @@ -0,0 +1,56 @@ +const { ChunkColumn, Version } = require('bedrock-provider') +const { SubChunk } = require('bedrock-provider/js/SubChunk') +try { var v8 = require('v8') } catch { } + +const Block = require('prismarine-block')('1.16.1') + +class ChunkColumnWrapped extends ChunkColumn { // pchunk compatiblity wrapper + // Block access + setBlockStateId(pos, stateId) { + super.setBlock(pos.x, pos.y, pos.z, Block.fromStateId(stateId)) + } + + getBlockStateId(pos) { + return super.getBlock(pos.x, pos.y, pos.z)?.stateId + } + + // // Serialization + // serialize() { + // if (typeof v8 === 'undefined') { + // return JSON.stringify(this) + // } else { + // const copy = { ...this, sections: [] } + // for (const section of this.sections) { + // copy.sections.push(v8.serialize(section)) + // } + // return v8.serialize(copy) + // } + // } + + // toJson() { return this.serialize() } + + // static deserialize(obj) { + // if (typeof obj === 'string') { + // Oject.assign(this, JSON.parse(obj)) + // } else { // Buffer + // const chunk = new ChunkColumnWrapped() + // const des = v8.deserialize(obj) + // Object.assign(chunk, des) + // chunk.sections = [] + // for (const section of des.sections) { + // const s = new SubChunk() + // chunk.sections.push(Object.assign(s, v8.deserialize(section))) + // } + // // console.log('Des',obj,chunk) + // return chunk + // } + // } + + // static fromJson(obj) { + // return ChunkColumnWrapped.deserialize(obj) + // } +} + +module.exports = (version) => { + return ChunkColumnWrapped +} \ No newline at end of file diff --git a/examples/viewer/client/app.css b/examples/viewer/client/app.css new file mode 100644 index 0000000..44c6bea --- /dev/null +++ b/examples/viewer/client/app.css @@ -0,0 +1,22 @@ +html { + overflow: hidden; +} + +html, body { + height: 100%; + margin: 0; + padding: 0; + font-family: sans-serif; +} + +a { + text-decoration: none; +} + +canvas { + height: 100%; + width: 100%; + font-size: 0; + margin: 0; + padding: 0; +} diff --git a/examples/viewer/client/index.html b/examples/viewer/client/index.html new file mode 100644 index 0000000..537be49 --- /dev/null +++ b/examples/viewer/client/index.html @@ -0,0 +1,22 @@ + + + + + Prismarine Viewer + + + + + +

+
Prismarine Viewer
+ +
+
Connecting to 127.0.0.1, port 19132...
+
+
+ + + + + \ No newline at end of file diff --git a/examples/viewer/client/index.js b/examples/viewer/client/index.js new file mode 100644 index 0000000..1b0334d --- /dev/null +++ b/examples/viewer/client/index.js @@ -0,0 +1,4 @@ +const { BotViewer } = require('./BotViewer') + +global.viewer = new BotViewer() +global.viewer.start() diff --git a/examples/viewer/client/preload.js b/examples/viewer/client/preload.js new file mode 100644 index 0000000..58594b5 --- /dev/null +++ b/examples/viewer/client/preload.js @@ -0,0 +1,9 @@ +// Required to detect electron in prismarine-viewer +globalThis.isElectron = true + +// If you need to disable node integration: +// * Node.js APIs will only be avaliable in this file +// * Use this file to load a viewer manager class +// based on one of the examples +// * Expose this class to the global window +// * Interact with the class in your code diff --git a/examples/viewer/client/worker.js b/examples/viewer/client/worker.js new file mode 100644 index 0000000..23ff320 --- /dev/null +++ b/examples/viewer/client/worker.js @@ -0,0 +1,2 @@ +// hack for path resolving +require('prismarine-viewer/viewer/lib/worker') diff --git a/examples/viewer/index.js b/examples/viewer/index.js new file mode 100644 index 0000000..f2a942c --- /dev/null +++ b/examples/viewer/index.js @@ -0,0 +1,37 @@ +const path = require('path') +const { app, BrowserWindow } = require('electron') + +function createMainWindow () { + const window = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + nodeIntegrationInWorker: true, + contextIsolation: false, + preload: path.join(__dirname, './client/preload.js') + } + }) + + // Open dev tools on load + window.webContents.openDevTools() + + window.loadFile(path.join(__dirname, './client/index.html')) + + window.webContents.on('devtools-opened', () => { + window.focus() + setImmediate(() => { + window.focus() + }) + }) + + return window +} + +app.on('ready', () => { + createMainWindow() +}) + +app.on('window-all-closed', function () { + app.quit() +}) + +app.allowRendererProcessReuse = false diff --git a/examples/viewer/package.json b/examples/viewer/package.json new file mode 100644 index 0000000..142f191 --- /dev/null +++ b/examples/viewer/package.json @@ -0,0 +1,13 @@ +{ + "name": "bedrock-protocol-viewer", + "description": "bedrock-protocol prismarine-viewer example", + "scripts": { + "start": "electron ." + }, + "dependencies": { + "bedrock-protocol": "file:../../", + "electron": "^12.0.2", + "patch-package": "^6.4.7", + "prismarine-viewer": "^1.19.1" + } +} From b79e4a65e40d28b315a4c6465a09c261d50b7543 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 3 Apr 2021 20:25:53 -0400 Subject: [PATCH 146/458] packet fixes, login chain update, raknet updates --- data/1.16.210/protocol.json | 34 +++++++++++++++++++--------------- data/latest/proto.yml | 23 +++++++++++++++++++---- data/latest/types.yaml | 2 +- src/auth/login.js | 7 ++++--- src/datatypes/util.js | 6 +++++- src/rak.js | 5 +++-- src/server.js | 3 ++- 7 files changed, 53 insertions(+), 27 deletions(-) diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 8c34b12..9a61484 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -840,11 +840,11 @@ } ] ], - "creative": [ + "craft": [ "container", [ { - "name": "inventory_id", + "name": "action", "type": "varint" } ] @@ -858,15 +858,6 @@ } ] ], - "craft": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], "craft_slot": [ "container", [ @@ -4870,7 +4861,20 @@ ], "packet_gui_data_pick_item": [ "container", - [] + [ + { + "name": "item_name", + "type": "string" + }, + { + "name": "item_effects", + "type": "string" + }, + { + "name": "hotbar_slot", + "type": "li32" + } + ] ], "packet_adventure_settings": [ "container", @@ -6283,14 +6287,14 @@ }, { "name": "entity_unique_id", - "type": "varint" + "type": "zigzag64" }, { "name": "transition_type", "type": [ "mapper", { - "type": "varint", + "type": "varint64", "mappings": { "0": "entity", "1": "create", @@ -7162,7 +7166,7 @@ "type": [ "switch", { - "compareTo": "types.feet", + "compareTo": "type.feet", "fields": { "true": "zigzag32" }, diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 68a7bbe..0d8db35 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -845,10 +845,16 @@ packet_set_entity_data: metadata: MetadataDictionary tick: varint +# SetActorMotion is sent by the server to change the client-side velocity of an entity. It is usually used +# in combination with server-side movement calculation. packet_set_entity_motion: !id: 0x28 !bound: both + # EntityRuntimeID is the runtime ID of the entity. The runtime ID is unique for each world session, and + # entities are generally identified in packets using this runtime ID. runtime_entity_id: varint64 + # Velocity is the new velocity the entity gets. This velocity will initiate the client-side movement of + # the entity. velocity: vec3f # SetActorLink is sent by the server to initiate an entity link client-side, meaning one entity will start @@ -1007,10 +1013,19 @@ packet_crafting_event: # Output is a list of items that were obtained as a result of crafting the recipe. result: Item[]varint - +# GUIDataPickItem is sent by the server to make the client 'select' a hot bar slot. It currently appears to +# be broken however, and does not actually set the selected slot to the hot bar slot set in the packet. packet_gui_data_pick_item: !id: 0x36 !bound: client + # ItemName is the name of the item that shows up in the top part of the popup that shows up when + # selecting an item. It is shown as if an item was selected by the player itself. + item_name: string + # ItemEffects is the line under the ItemName, where the effects of the item are usually situated. + item_effects: string + # HotBarSlot is the hot bar slot to be selected/picked. This does not currently work, so it does not + # matter what number this is. + hotbar_slot: li32 # AdventureSettings is sent by the server to update game-play related features, in particular permissions to # access these features for the client. It includes allowing the player to fly, build and mine, and attack @@ -1745,11 +1760,11 @@ packet_update_block_synced: # entity transitions from. # Note that for both possible values for TransitionType, the EntityUniqueID should point to the falling # block entity involved. - entity_unique_id: varint + entity_unique_id: zigzag64 # TransitionType is the type of the transition that happened. It is either BlockToEntityTransition, when # a block placed becomes a falling entity, or EntityToBlockTransition, when a falling entity hits the # ground and becomes a solid block again. - transition_type: varint => + transition_type: varint64 => # For falling sand, when a sand turns to an entity 0: entity # When sand turns back to a new block @@ -2231,7 +2246,7 @@ packet_player_armor_damage: if true: zigzag32 leggings_damage: type.legs ? if true: zigzag32 - boots_damage: types.feet ? + boots_damage: type.feet ? if true: zigzag32 ArmorDamageType: [ "bitflags", diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 6ba41c8..b2d8730 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -448,7 +448,7 @@ TransactionActions: 100: craft_slot 99999: craft _: source_type? - if container or creative: + if container or craft: inventory_id: varint if world_interaction: flags: varint diff --git a/src/auth/login.js b/src/auth/login.js index 55c7ef9..49913b4 100644 --- a/src/auth/login.js +++ b/src/auth/login.js @@ -3,6 +3,7 @@ const JWT = require('jsonwebtoken') const DataProvider = require('../../data/provider') const ecPem = require('ec-pem') const curve = 'secp384r1' +const { nextUUID } = require('../datatypes/util') module.exports = (client, server, options) => { const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') @@ -45,10 +46,10 @@ module.exports = (client, server, options) => { CapeImageHeight: 0, CapeImageWidth: 0, CapeOnClassicSkin: false, - ClientRandomId: 1, // TODO make biggeer + ClientRandomId: Date.now(), CurrentInputMode: 1, DefaultInputMode: 1, - DeviceId: '2099de18-429a-465a-a49b-fc4710a17bb3', // TODO random + DeviceId: nextUUID(), DeviceModel: '', DeviceOS: client.session?.deviceOS || 7, GameVersion: options.version || '1.16.201', @@ -64,7 +65,7 @@ module.exports = (client, server, options) => { // inside of PlayFab. PlayFabId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', // 1.16.210 PremiumSkin: false, - SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343701', + SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343702', ServerAddress: `${options.hostname}:${options.port}`, SkinAnimationData: '', SkinColor: '#ffffcd96', diff --git a/src/datatypes/util.js b/src/datatypes/util.js index 4a14e31..b080577 100644 --- a/src/datatypes/util.js +++ b/src/datatypes/util.js @@ -39,4 +39,8 @@ function uuidFrom (string) { return UUID.v3({ namespace: '6ba7b811-9dad-11d1-80b4-00c04fd430c8', name: string }) } -module.exports = { getFiles, sleep, waitFor, serialize, uuidFrom } +function nextUUID () { + return uuidFrom(Date.now().toString()) +} + +module.exports = { getFiles, sleep, waitFor, serialize, uuidFrom, nextUUID } diff --git a/src/rak.js b/src/rak.js index e4a203d..88682d6 100644 --- a/src/rak.js +++ b/src/rak.js @@ -23,12 +23,13 @@ class RakNativeClient extends EventEmitter { this.raknet.on('encapsulated', ({ buffer, address }) => { this.onEncapsulated(buffer, address) }) - this.raknet.on('connected', () => { + + this.raknet.on('connect', () => { this.connected = true this.onConnected() }) - this.raknet.on('disconnected', ({ reason }) => { + this.raknet.on('disconnect', ({ reason }) => { this.connected = false this.onCloseConnection(reason) }) diff --git a/src/server.js b/src/server.js index bf440d3..c2dcdf7 100644 --- a/src/server.js +++ b/src/server.js @@ -3,7 +3,7 @@ const { createDeserializer, createSerializer } = require('./transforms/serialize const { Player } = require('./serverPlayer') const { RakServer } = require('./rak') const Options = require('./options') -const debug = require('debug')('minecraft-protocol') +const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol') class Server extends EventEmitter { constructor (options) { @@ -62,6 +62,7 @@ class Server extends EventEmitter { this.raknet.onOpenConnection = this.onOpenConnection this.raknet.onCloseConnection = this.onCloseConnection this.raknet.onEncapsulated = this.onEncapsulated + return { hostname, port } } close (disconnectReason) { From 88f88559af5800f171ec8c520061583540223d99 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 3 Apr 2021 20:30:01 -0400 Subject: [PATCH 147/458] switch to browserify-crypto on electron --- package.json | 3 ++- src/relay.js | 23 ++++++++++++++--------- src/transforms/encryption.js | 15 +++++++++------ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 9be65ba..8090cfa 100644 --- a/package.json +++ b/package.json @@ -25,11 +25,12 @@ "@xboxreplay/xboxlive-auth": "^3.3.3", "aes-js": "^3.1.2", "asn1": "^0.2.4", - "bedrock-provider": "^0.1.1", + "browserify-cipher": "^1.0.1", "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", "jsp-raknet": "github:extremeheat/raknet#client", + "leveldb-zlib": "0.0.26", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", diff --git a/src/relay.js b/src/relay.js index ed78a09..8203ad8 100644 --- a/src/relay.js +++ b/src/relay.js @@ -2,7 +2,7 @@ const { Client } = require('./client') const { Server } = require('./server') const { Player } = require('./serverPlayer') -const debug = require('debug')('minecraft-protocol relay') +const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol relay') const { serialize } = require('./datatypes/util') /** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ @@ -22,10 +22,10 @@ class RelayPlayer extends Player { }) this.downQ = [] this.upQ = [] - this.upInLog = (...msg) => console.info('** Backend -> Proxy', ...msg) - this.upOutLog = (...msg) => console.info('** Proxy -> Backend', ...msg) - this.downInLog = (...msg) => console.info('** Client -> Proxy', ...msg) - this.downOutLog = (...msg) => console.info('** Proxy -> Client', ...msg) + this.upInLog = (...msg) => console.debug('** Backend -> Proxy', ...msg) + this.upOutLog = (...msg) => console.debug('** Proxy -> Backend', ...msg) + this.downInLog = (...msg) => console.debug('** Client -> Proxy', ...msg) + this.downOutLog = (...msg) => console.debug('** Proxy -> Client', ...msg) if (!server.options.logging) { this.upInLog = () => { } @@ -52,11 +52,11 @@ class RelayPlayer extends Player { this.downQ.push(packet) return } - this.upInLog('Recv packet', packet) + // this.upInLog('Recv packet', packet) const des = this.server.deserializer.parsePacketBuffer(packet) const name = des.data.name const params = des.data.params - this.upInLog('~ Bounce B->C', name, serialize(params).slice(0, 100)) + // this.upInLog('~ Bounce B->C', name, serialize(params).slice(0, 100)) // this.upInLog('~ ', des.buffer) if (name === 'play_status' && params.status === 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect @@ -72,6 +72,8 @@ class RelayPlayer extends Player { this.queue(name, params) // this.sendBuffer(packet) + + this.emit('clientbound', des.data) } // Send queued packets to the connected client @@ -105,7 +107,7 @@ class RelayPlayer extends Player { return } this.flushUpQueue() // Send queued packets - this.downInLog('Recv packet', packet) + // this.downInLog('Recv packet', packet) // TODO: If we fail to parse a packet, proxy it raw and log an error const des = this.server.deserializer.parsePacketBuffer(packet) @@ -129,6 +131,7 @@ class RelayPlayer extends Player { this.downInLog('Relaying', des.data) this.upstream.sendBuffer(packet) } + this.emit('serverbound', des.data) } else { super.readPacket(packet) } @@ -162,6 +165,8 @@ class Relay extends Server { ds.flushUpQueue() console.log('Connected to upstream server') client.readPacket = (packet) => ds.readUpstream(packet) + + this.emit('join', /* client connected to proxy */ ds, /* backend server */ client) }) this.upstreams.set(clientAddr.hash, client) } @@ -183,7 +188,7 @@ class Relay extends Server { const player = new this.RelayPlayer(this, conn) console.debug('New connection from', conn.address) this.clients[conn.address] = player - this.emit('connect', { client: player }) + this.emit('connect', player) this.openUpstreamConnection(player, conn.address) } } diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 41432c1..81a70af 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,5 +1,6 @@ const { Transform } = require('readable-stream') -const crypto = require('crypto') +const crypto = globalThis.isElectron ? require('browserify-cipher/browser') : require('crypto') +const { createHash } = require('crypto') const aesjs = require('aes-js') const Zlib = require('zlib') @@ -52,7 +53,7 @@ class Decipher extends Transform { } function computeCheckSum (packetPlaintext, sendCounter, secretKeyBytes) { - const digest = crypto.createHash('sha256') + const digest = createHash('sha256') const counter = Buffer.alloc(8) counter.writeBigInt64LE(sendCounter, 0) digest.update(counter) @@ -70,10 +71,12 @@ function createEncryptor (client, iv) { // The send counter is represented as a little-endian 64-bit long and incremented after each packet. function process (chunk) { - const buffer = Zlib.deflateRawSync(chunk, { level: 7 }) - const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) - client.sendCounter++ - client.cipher.write(packet) + Zlib.deflateRaw(chunk, { level: 7 }, (err, buffer) => { + if (err) throw err + const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) + client.sendCounter++ + client.cipher.write(packet) + }) } client.cipher.on('data', client.onEncryptedPacket) From d2c0d3c386465d6302893717fbe31aa2e57ba28a Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 3 Apr 2021 20:34:42 -0400 Subject: [PATCH 148/458] viewer: add proxy example --- examples/viewer/client/BotProvider.js | 252 ++++++++++++++++++------ examples/viewer/client/BotViewer.js | 31 +-- examples/viewer/client/Chunk.js | 8 +- examples/viewer/client/ProxyProvider.js | 126 ++++++++++++ examples/viewer/package.json | 2 + src/connection.js | 13 +- 6 files changed, 356 insertions(+), 76 deletions(-) create mode 100644 examples/viewer/client/ProxyProvider.js diff --git a/examples/viewer/client/BotProvider.js b/examples/viewer/client/BotProvider.js index d6c733b..f4d0d37 100644 --- a/examples/viewer/client/BotProvider.js +++ b/examples/viewer/client/BotProvider.js @@ -2,14 +2,19 @@ const { Client } = require('bedrock-protocol') const { Version } = require('bedrock-provider') const { WorldView } = require('prismarine-viewer/viewer') -const vec3, { Vec3 } = require('vec3') +const vec3 = require('vec3') const World = require('prismarine-world')() const ChunkColumn = require('./Chunk')() -const Physics = require('prismarine-physics') +const { Physics, PlayerState } = require('prismarine-physics') +const { performance } = require('perf_hooks') + +const PHYSICS_INTERVAL_MS = 50 +const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000 class BotProvider extends WorldView { chunks = {} lastSentPos + positionUpdated = true constructor() { super() @@ -19,7 +24,6 @@ class BotProvider extends WorldView { // Server auth movement : we send inputs, server calculates position & sends back this.serverMovements = true - this.tick = 0n } @@ -47,6 +51,10 @@ class BotProvider extends WorldView { this.client = client } + close() { + this.client?.close() + } + listenToBot() { this.client.on('connect', () => { console.log('Bot has connected!') @@ -58,33 +66,39 @@ class BotProvider extends WorldView { this.client.on('spawn', () => { // server allows client to render chunks & spawn in world this.emit('spawn', { position: this.lastPos }) + + this.tickLoop = setInterval(() => { + this.client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) }) this.client.on('level_chunk', packet => { - const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) - cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count).then(() => { - this.loadedChunks[(packet.x << 4) + ',' + (packet.z << 4)] = true - this.world.setColumn(packet.x, packet.z, cc) - const chunk = cc.serialize() - console.log('Chunk', chunk) - this.emitter.emit('loadChunk', { x: packet.x << 4, z: packet.z << 4, chunk }) - }) + this.handleChunk(packet) }) this.client.on('move_player', packet => { if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) }) - this.client.on('set_entity_motion', packet=>{ + this.client.on('set_entity_motion', packet => { if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) }) this.client.on('tick_sync', (packet) => { - this.lastTick = packet.request_time + this.lastTick = packet.response_time }) + } - this.tickLoop = setInterval(() => { - client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + handleChunk(packet, render = true) { + const hash = (packet.x << 4) + ',' + (packet.z << 4) + if (this.loadChunk[hash]) return + const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count).then(() => { + this.loadedChunks[hash] = true + this.world.setColumn(packet.x, packet.z, cc) + const chunk = cc.serialize() + // console.log('Chunk', chunk) + if (render) this.emitter.emit('loadChunk', { x: packet.x << 4, z: packet.z << 4, chunk }) }) } @@ -99,60 +113,53 @@ class BotProvider extends WorldView { } // Ask the server to be in a new position - requestPosition() { + requestPosition(time, inputState) { const positionUpdated = !this.lastSentPos || !this.lastPos.equals(this.lastSentPos) + // if (globalThis.logging)console.log('New pos', this.lastSentPos,this.lastPos) if (positionUpdated) { + this.lastSentPos = this.lastPos.clone() + console.log('We computed', this.lastPos) + this.pushCamera({ + position: this.lastSentPos, + input_data: {}, + yaw: this.playerState.yaw, pitch: this.playerState.pitch + }, 2) + return this.client.queue('player_auth_input', { - pitch: 0, - yaw: this.lastYaw, + pitch: this.player.pitch, + yaw: this.player.yaw, position: { x: this.lastPos.x, y: this.lastPos.y, z: this.lastPos.z }, - move_vector: { x: 0, z: 0 }, - head_yaw: 0, - input_data: { - ascend: false, - descend: false, - north_jump: false, - jump_down: false, - sprint_down: false, - change_height: false, - jumping: false, - auto_jumping_in_water: false, - sneaking: false, - sneak_down: false, - up: false, - down: false, - left: false, - right: false, - up_left: false, - up_right: false, - want_up: false, - want_down: false, - want_down_slow: false, - want_up_slow: false, - sprinting: false, - ascend_scaffolding: false, - descend_scaffolding: false, - sneak_toggle_down: false, - persist_sneak: false + move_vector: { // Minecraft coords, N: Z+1, S: Z-1, W: X+1, E: X-1 + x: inputState.left ? 1 : (inputState.right ? -1 : 0), + z: inputState.up ? 1 : (inputState.down ? -1 : 0) }, + head_yaw: this.player.headYaw, + input_data: inputState, input_mode: 'mouse', play_mode: 'screen', tick: this.tick, - delta: { x: 0, y: -0.07840000092983246, z: 0 } + delta: this.lastSentPos?.minus(this.lastPos) ?? { x: 0, y: 0, z: 0 } }) + this.positionUpdated = false + this.lastSentPos = this.lastPos.clone() } } - initPhys() { - this.lastVel = new Vec3(0, 0, 0) - this.lastYaw = 0 + initPhys(position, velocity, yaw = 0, pitch = 0, headYaw = 0) { + this.lastPos = position ? vec3(position) : vec3(0, 0, 0) + this.lastVel = velocity ? vec3(velocity) : vec3(0, 0, 0) this.player = { + version: '1.16.1', + inventory: { + slots: [] + }, entity: { + effects: {}, position: this.lastPos, velocity: this.lastVel, onGround: false, @@ -161,13 +168,23 @@ class BotProvider extends WorldView { isInWeb: false, isCollidedHorizontally: false, isCollidedVertically: false, - yaw: this.lastYaw + yaw, + pitch, + headYaw // bedrock + }, + events: { // Control events to send next tick + startSprint: false, + stopSprint: false, + startSneak: false, + stopSneak: false }, jumpTicks: 0, - jumpQueued: false + jumpQueued: false, + downJump: false } - this.physics = Physics(mcData, fakeWorld) + const mcData = require('minecraft-data')('1.16.1') + this.physics = Physics(mcData, this.world) this.controls = { forward: false, back: false, @@ -180,16 +197,137 @@ class BotProvider extends WorldView { this.playerState = new PlayerState(this.player, this.controls) } + // This function should be executed each tick (every 0.05 seconds) + // How it works: https://gafferongames.com/post/fix_your_timestep/ + timeAccumulator = 0 + lastPhysicsFrameTime = null + inputQueue = [] + doPhysics() { + const now = performance.now() + const deltaSeconds = (now - this.lastPhysicsFrameTime) / 1000 + this.lastPhysicsFrameTime = now + + this.timeAccumulator += deltaSeconds + + while (this.timeAccumulator >= PHYSICS_TIMESTEP) { + let q = this.inputQueue.shift() + if (q) { + Object.assign(this.playerState.control, q) + if (q.yaw) { this.player.entity.yaw = q.yaw; this.playerState.yaw = q.yaw; } + if (q.pitch) this.player.entity.pitch = q.pitch + } + this.physics.simulatePlayer(this.playerState, this.world.sync).apply(this.player) + this.lastPos = this.playerState.pos + this.requestPosition(PHYSICS_TIMESTEP, { + ascend: false, + descend: false, + // Players bob up and down in water, north jump is true when going up. + // In water this is only true after the player has reached max height before bobbing back down. + north_jump: this.player.jumpTicks > 0, // Jump + jump_down: this.controls.jump, // Jump + sprint_down: this.controls.sprint, + change_height: false, + jumping: this.controls.jump, // Jump + auto_jumping_in_water: false, + sneaking: false, + sneak_down: false, + up: this.controls.forward, + down: this.controls.back, + left: this.controls.left, + right: this.controls.right, + up_left: false, + up_right: false, + want_up: this.controls.jump, // Jump + want_down: false, + want_down_slow: false, + want_up_slow: false, + sprinting: false, + ascend_scaffolding: false, + descend_scaffolding: false, + sneak_toggle_down: false, + persist_sneak: false, + start_sprinting: this.player.events.startSprint || false, + stop_sprinting: this.player.events.stopSprint || false, + start_sneaking: this.player.events.startSneak || false, + stop_sneaking: this.player.events.stopSneak || false, + // Player is Update Aqatic swimming + start_swimming: false, + // Player stops Update Aqatic swimming + stop_swimming: false, + start_jumping: this.player.jumpTicks === 1, // Jump + start_gliding: false, + stop_gliding: false, + }) + this.timeAccumulator -= PHYSICS_TIMESTEP + } + } + startPhys() { + console.log('Start phys') this.physicsLoop = setInterval(() => { - this.physics.simulatePlayer(this.playerState, this.world).apply(this.player) - this.requestPosition() - }, 50) + this.doPhysics() + }, PHYSICS_INTERVAL_MS) + } + + setControlState(control, state) { + if (this.controls[control] === state) return + if (control === 'sprint') { + this.player.events.startSprint = state + this.player.events.stopSprint = !state + this.controls.sprint = true + } else if (control === 'sneak') { + this.player.events.startSneak = state + this.player.events.stopSneak = !state + this.controls.sprint = true + } + } + + pushInputState(state, yaw, pitch) { + const yawRad = d2r(yaw) + const pitchRad = d2r(pitch) + this.inputQueue.push({ + forward: state.up, + back: state.down,// TODO: left and right switched ??? + left: state.right, + right: state.left, + jump: state.jump_down, + sneak: state.sprint_down, + yaw: yawRad, pitch: pitchRad, + }) + globalThis.yaw = [yaw, yawRad] + if (global.logYaw) console.log('Pushed', yaw, pitch) + } + + pushCamera(state, id = 1) { + let { x, y, z } = state.position + if (id == 1) y -= 1.62 // account for player bb + const pos = vec3({ x, y, z }) + if (state.position) { + viewer.viewer.entities.update({ + name: 'player', + id, pos, width: 0.6, height: 1.8, + yaw: id == 1 ? d2r(state.yaw) : state.yaw + }) + + //viewer.viewer.camera.position.set(x, y, z) + } + + if (state.input_data.sneak_down) { + this.player.entity.position = pos + this.playerState.pos = this.player.entity.position + } + } + + onCameraMovement(newYaw, newPitch, newHeadYaw) { + this.player.yaw = newYaw + this.player.pitch = newPitch + this.player.headYaw = newHeadYaw } stopPhys() { - clearInterval(this.physics) + clearInterval(this.physicsLoop) } } +const d2r = deg => (180 - (deg < 0 ? (360 + deg) : deg)) * (Math.PI / 180) module.exports = { BotProvider } diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js index 3782824..7600b0a 100644 --- a/examples/viewer/client/BotViewer.js +++ b/examples/viewer/client/BotViewer.js @@ -2,19 +2,20 @@ const { Viewer, MapControls } = require('prismarine-viewer/viewer') const { Vec3 } = require('vec3') const { BotProvider } = require('./BotProvider') +const { ProxyProvider } = require('./ProxyProvider') global.THREE = require('three') const MCVER = '1.16.1' class BotViewer { - constructor() { - // Create viewer data provider - this.world = new BotProvider() + constructor () { + } - start() { - this.worldView = new BotProvider() - + start () { + // this.bot = new BotProvider() + this.bot = new ProxyProvider() + // return // Create three.js context, add to page this.renderer = new THREE.WebGLRenderer() this.renderer.setPixelRatio(window.devicePixelRatio || 1) @@ -31,11 +32,13 @@ class BotViewer { this.controls.dampingFactor = 0.09 console.info('Registered handlers') // Link WorldView and Viewer - this.viewer.listen(this.worldView) + this.viewer.listen(this.bot) - this.worldView.on('spawn', ({ position }) => { + this.bot.on('spawn', ({ position }) => { // Initialize viewer, load chunks - this.worldView.init(position) + this.bot.init(position) + // Start listening for keys + this.registerBrowserEvents() }) this.controls.update() @@ -56,12 +59,14 @@ class BotViewer { }) } - onKeyDown = () => { - + onKeyDown = (evt) => { + console.log('Key down', evt) + // this.bot.initPhys() + // this.bot.startPhys() } - registerBrowserEvents() { - this.renderer.domElement.addEventListener('keydown', this.onKeyDown) + registerBrowserEvents () { + this.renderer.domElement.parentElement.addEventListener('keydown', this.onKeyDown) } } diff --git a/examples/viewer/client/Chunk.js b/examples/viewer/client/Chunk.js index fdfd29f..b2ecc57 100644 --- a/examples/viewer/client/Chunk.js +++ b/examples/viewer/client/Chunk.js @@ -1,16 +1,16 @@ const { ChunkColumn, Version } = require('bedrock-provider') const { SubChunk } = require('bedrock-provider/js/SubChunk') -try { var v8 = require('v8') } catch { } +try { const v8 = require('v8') } catch { } const Block = require('prismarine-block')('1.16.1') class ChunkColumnWrapped extends ChunkColumn { // pchunk compatiblity wrapper // Block access - setBlockStateId(pos, stateId) { + setBlockStateId (pos, stateId) { super.setBlock(pos.x, pos.y, pos.z, Block.fromStateId(stateId)) } - getBlockStateId(pos) { + getBlockStateId (pos) { return super.getBlock(pos.x, pos.y, pos.z)?.stateId } @@ -53,4 +53,4 @@ class ChunkColumnWrapped extends ChunkColumn { // pchunk compatiblity wrapper module.exports = (version) => { return ChunkColumnWrapped -} \ No newline at end of file +} diff --git a/examples/viewer/client/ProxyProvider.js b/examples/viewer/client/ProxyProvider.js new file mode 100644 index 0000000..0db00df --- /dev/null +++ b/examples/viewer/client/ProxyProvider.js @@ -0,0 +1,126 @@ +const { Relay } = require('bedrock-protocol') +const { BotProvider } = require('./BotProvider') +const vec3 = require('vec3') + +class ProxyProvider extends BotProvider { + lastPlayerMovePacket + + connect () { + const proxy = new Relay({ + hostname: '0.0.0.0', + port: 19130, + // logging: true, + destination: { + hostname: '127.0.0.1', + port: 19132 + } + }) + + proxy.listen() + + console.info('Waiting for connect') + + const maxChunks = 40 + + proxy.on('join', (client, server) => { + client.on('clientbound', ({ name, params }) => { + if (name == 'level_chunk') { + // maxChunks-- + // if (maxChunks >= 0) { + // this.handleChunk(params) + // } + this.handleChunk(params, true) + } else if (name == 'start_game') { + this.initPhys(params.player_position, null, params.rotation.z, params.rotation.x, 0) + } else if (name === 'play_status') { + // this.emit('spawn', { position: server.startGameData.player_position }) + + this.startPhys() + console.info('Started physics!') + } else if (name === 'move_player') { + console.log('move_player', packet) + // if (packet.runtime_id === server.entityId) { + // this.updatePosition(packet.position) + // if (this.lastServerMovement.x == packet.position.x && this.lastServerMovement.y == packet.position.y && this.lastServerMovement.z == packet.position.z) { + + // } else { + // console.log('Server computed', packet.position) + // } + // this.lastServerMovement = { ...packet.position } + // } + } + if (name.includes('entity') || name.includes('network_chunk_publisher_update') || name.includes('tick') || name.includes('level')) return + console.log('CB', name) + }) + + client.on('serverbound', ({ name, params }) => { + // { name, params } + if (name == 'player_auth_input') { + // console.log('player_auth_input', this.lastPlayerMovePacket, params) + + // this.controls.forward = params.input_data.up + // this.controls.back = params.input_data.down + // this.controls.left = params.input_data.left + // this.controls.right = params.input_data.right + // this.player.entity.pitch = params.pitch + // this.player.entity.yaw = params.yaw + this.pushInputState(params.input_data, params.yaw, params.pitch) + this.pushCamera(params) + this.lastMovePacket = params + + // Log Movement deltas + { + if (this.firstPlayerMovePacket) { + const id = diff(this.firstPlayerMovePacket.input_data, params.input_data) + const md = diff(this.firstPlayerMovePacket.move_vector, params.move_vector) + const dd = diff(this.firstPlayerMovePacket.delta, params.delta) + if (id || md) { + if (globalThis.logging) console.log('Move', params.position, id, md, dd) + globalThis.movements ??= [] + globalThis.movements.push(params) + } + } + if (!this.firstPlayerMovePacket) { + this.firstPlayerMovePacket = params + for (const key in params.input_data) { + params.input_data[key] = false + } + params.input_data._value = 0n + params.move_vector = { x: 0, z: 0 } + params.delta = { x: 0, y: 0, z: 0 } + } + } + } else if (!name.includes('tick') && !name.includes('level')) { + console.log('Sending', name) + } + }) + console.info('Client and Server Connected!') + }) + + this.proxy = proxy + } + + listenToBot () { + + } + + close () { + this.proxy?.close() + } +} + +const difference = (o1, o2) => Object.keys(o2).reduce((diff, key) => { + if (o1[key] === o2[key]) return diff + return { + ...diff, + [key]: o2[key] + } +}, {}) + +// console.log = () => {} +// console.debug = () => {} + +const diff = (o1, o2) => { const dif = difference(o1, o2); return Object.keys(dif).length ? dif : null } + +module.exports = { ProxyProvider } +globalThis.logging = true diff --git a/examples/viewer/package.json b/examples/viewer/package.json index 142f191..9895117 100644 --- a/examples/viewer/package.json +++ b/examples/viewer/package.json @@ -6,8 +6,10 @@ }, "dependencies": { "bedrock-protocol": "file:../../", + "browserify-cipher": "^1.0.1", "electron": "^12.0.2", "patch-package": "^6.4.7", + "prismarine-physics": "^1.2.2", "prismarine-viewer": "^1.19.1" } } diff --git a/src/connection.js b/src/connection.js index a9061c0..6a55a1a 100644 --- a/src/connection.js +++ b/src/connection.js @@ -15,10 +15,19 @@ const ClientStatus = { } class Connection extends EventEmitter { - status = ClientStatus.Disconnected + #status = ClientStatus.Disconnected q = [] q2 = [] + get status () { + return this.#status + } + + set status (val) { + this.inLog('* new status', val) + this.#status = val + } + versionLessThan (version) { if (typeof version === 'string') { return Versions[version] < this.options.protocolVersion @@ -132,7 +141,7 @@ class Connection extends EventEmitter { this.outLog('Enc buf', buf) const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header - this.outLog('Sending wrapped encrypted batch', packet) + // this.outLog('Sending wrapped encrypted batch', packet) this.sendMCPE(packet) } From 32d52e987852fdf139c6d351b88223845f212fa3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 3 Apr 2021 22:54:42 -0400 Subject: [PATCH 149/458] viewer: refactor and cleanup --- examples/viewer/client/BotProvider.js | 316 ++--------------------- examples/viewer/client/BotViewer.js | 11 +- examples/viewer/client/Chunk.js | 40 +-- examples/viewer/client/ClientProvider.js | 68 +++++ examples/viewer/client/ProxyProvider.js | 62 +---- examples/viewer/client/movements.js | 244 +++++++++++++++++ examples/viewer/client/util.js | 16 ++ src/connection.js | 4 +- tools/startVanillaServer.js | 2 +- 9 files changed, 366 insertions(+), 397 deletions(-) create mode 100644 examples/viewer/client/ClientProvider.js create mode 100644 examples/viewer/client/movements.js create mode 100644 examples/viewer/client/util.js diff --git a/examples/viewer/client/BotProvider.js b/examples/viewer/client/BotProvider.js index f4d0d37..fe225cf 100644 --- a/examples/viewer/client/BotProvider.js +++ b/examples/viewer/client/BotProvider.js @@ -1,15 +1,9 @@ /* eslint-disable */ -const { Client } = require('bedrock-protocol') const { Version } = require('bedrock-provider') const { WorldView } = require('prismarine-viewer/viewer') -const vec3 = require('vec3') const World = require('prismarine-world')() const ChunkColumn = require('./Chunk')() -const { Physics, PlayerState } = require('prismarine-physics') -const { performance } = require('perf_hooks') - -const PHYSICS_INTERVAL_MS = 50 -const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000 +const { MovementManager } = require('./movements') class BotProvider extends WorldView { chunks = {} @@ -21,72 +15,7 @@ class BotProvider extends WorldView { this.connect() this.listenToBot() this.world = new World() - - // Server auth movement : we send inputs, server calculates position & sends back - this.serverMovements = true - this.tick = 0n - } - - connect() { - const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', port: 19132, connectTimeout: 100000 }) - - client.once('resource_packs_info', (packet) => { - client.write('resource_pack_client_response', { - response_status: 'completed', - resourcepackids: [] - }) - - client.once('resource_pack_stack', (stack) => { - client.write('resource_pack_client_response', { - response_status: 'completed', - resourcepackids: [] - }) - }) - - client.queue('client_cache_status', { enabled: false }) - client.queue('request_chunk_radius', { chunk_radius: 1 }) - client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) - }) - - this.client = client - } - - close() { - this.client?.close() - } - - listenToBot() { - this.client.on('connect', () => { - console.log('Bot has connected!') - }) - this.client.on('start_game', packet => { - this.updatePosition(packet.player_position) - }) - - this.client.on('spawn', () => { - // server allows client to render chunks & spawn in world - this.emit('spawn', { position: this.lastPos }) - - this.tickLoop = setInterval(() => { - this.client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) - }) - }) - - this.client.on('level_chunk', packet => { - this.handleChunk(packet) - }) - - this.client.on('move_player', packet => { - if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) - }) - - this.client.on('set_entity_motion', packet => { - if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) - }) - - this.client.on('tick_sync', (packet) => { - this.lastTick = packet.response_time - }) + this.movements = new MovementManager(this) } handleChunk(packet, render = true) { @@ -102,232 +31,27 @@ class BotProvider extends WorldView { }) } + updatePlayerCamera(id, pos, yaw, pitch, updateState) { + // TODO: do this properly + window.viewer.viewer.entities.update({ + name: 'player', + id, + pos, + width: 0.6, + height: 1.8, + yaw, + pitch + }) + + if (updateState) { + this.movements.updatePosition(pos, yaw, pitch) + } + } + stopBot() { clearInterval(this.tickLoop) - } - - // Server gives us a new position - updatePosition(pos) { - this.lastPos ??= vec3(pos) - super.updatePosition(this.lastPos) - } - - // Ask the server to be in a new position - requestPosition(time, inputState) { - const positionUpdated = !this.lastSentPos || !this.lastPos.equals(this.lastSentPos) - // if (globalThis.logging)console.log('New pos', this.lastSentPos,this.lastPos) - - if (positionUpdated) { - this.lastSentPos = this.lastPos.clone() - console.log('We computed', this.lastPos) - this.pushCamera({ - position: this.lastSentPos, - input_data: {}, - yaw: this.playerState.yaw, pitch: this.playerState.pitch - }, 2) - return - this.client.queue('player_auth_input', { - pitch: this.player.pitch, - yaw: this.player.yaw, - position: { - x: this.lastPos.x, - y: this.lastPos.y, - z: this.lastPos.z - }, - move_vector: { // Minecraft coords, N: Z+1, S: Z-1, W: X+1, E: X-1 - x: inputState.left ? 1 : (inputState.right ? -1 : 0), - z: inputState.up ? 1 : (inputState.down ? -1 : 0) - }, - head_yaw: this.player.headYaw, - input_data: inputState, - input_mode: 'mouse', - play_mode: 'screen', - tick: this.tick, - delta: this.lastSentPos?.minus(this.lastPos) ?? { x: 0, y: 0, z: 0 } - }) - this.positionUpdated = false - this.lastSentPos = this.lastPos.clone() - } - } - - initPhys(position, velocity, yaw = 0, pitch = 0, headYaw = 0) { - this.lastPos = position ? vec3(position) : vec3(0, 0, 0) - this.lastVel = velocity ? vec3(velocity) : vec3(0, 0, 0) - this.player = { - version: '1.16.1', - inventory: { - slots: [] - }, - entity: { - effects: {}, - position: this.lastPos, - velocity: this.lastVel, - onGround: false, - isInWater: false, - isInLava: false, - isInWeb: false, - isCollidedHorizontally: false, - isCollidedVertically: false, - yaw, - pitch, - headYaw // bedrock - }, - events: { // Control events to send next tick - startSprint: false, - stopSprint: false, - startSneak: false, - stopSneak: false - }, - jumpTicks: 0, - jumpQueued: false, - downJump: false - } - - const mcData = require('minecraft-data')('1.16.1') - this.physics = Physics(mcData, this.world) - this.controls = { - forward: false, - back: false, - left: false, - right: false, - jump: false, - sprint: false, - sneak: false - } - this.playerState = new PlayerState(this.player, this.controls) - } - - // This function should be executed each tick (every 0.05 seconds) - // How it works: https://gafferongames.com/post/fix_your_timestep/ - timeAccumulator = 0 - lastPhysicsFrameTime = null - inputQueue = [] - doPhysics() { - const now = performance.now() - const deltaSeconds = (now - this.lastPhysicsFrameTime) / 1000 - this.lastPhysicsFrameTime = now - - this.timeAccumulator += deltaSeconds - - while (this.timeAccumulator >= PHYSICS_TIMESTEP) { - let q = this.inputQueue.shift() - if (q) { - Object.assign(this.playerState.control, q) - if (q.yaw) { this.player.entity.yaw = q.yaw; this.playerState.yaw = q.yaw; } - if (q.pitch) this.player.entity.pitch = q.pitch - } - this.physics.simulatePlayer(this.playerState, this.world.sync).apply(this.player) - this.lastPos = this.playerState.pos - this.requestPosition(PHYSICS_TIMESTEP, { - ascend: false, - descend: false, - // Players bob up and down in water, north jump is true when going up. - // In water this is only true after the player has reached max height before bobbing back down. - north_jump: this.player.jumpTicks > 0, // Jump - jump_down: this.controls.jump, // Jump - sprint_down: this.controls.sprint, - change_height: false, - jumping: this.controls.jump, // Jump - auto_jumping_in_water: false, - sneaking: false, - sneak_down: false, - up: this.controls.forward, - down: this.controls.back, - left: this.controls.left, - right: this.controls.right, - up_left: false, - up_right: false, - want_up: this.controls.jump, // Jump - want_down: false, - want_down_slow: false, - want_up_slow: false, - sprinting: false, - ascend_scaffolding: false, - descend_scaffolding: false, - sneak_toggle_down: false, - persist_sneak: false, - start_sprinting: this.player.events.startSprint || false, - stop_sprinting: this.player.events.stopSprint || false, - start_sneaking: this.player.events.startSneak || false, - stop_sneaking: this.player.events.stopSneak || false, - // Player is Update Aqatic swimming - start_swimming: false, - // Player stops Update Aqatic swimming - stop_swimming: false, - start_jumping: this.player.jumpTicks === 1, // Jump - start_gliding: false, - stop_gliding: false, - }) - this.timeAccumulator -= PHYSICS_TIMESTEP - } - } - - startPhys() { - console.log('Start phys') - this.physicsLoop = setInterval(() => { - this.doPhysics() - }, PHYSICS_INTERVAL_MS) - } - - setControlState(control, state) { - if (this.controls[control] === state) return - if (control === 'sprint') { - this.player.events.startSprint = state - this.player.events.stopSprint = !state - this.controls.sprint = true - } else if (control === 'sneak') { - this.player.events.startSneak = state - this.player.events.stopSneak = !state - this.controls.sprint = true - } - } - - pushInputState(state, yaw, pitch) { - const yawRad = d2r(yaw) - const pitchRad = d2r(pitch) - this.inputQueue.push({ - forward: state.up, - back: state.down,// TODO: left and right switched ??? - left: state.right, - right: state.left, - jump: state.jump_down, - sneak: state.sprint_down, - yaw: yawRad, pitch: pitchRad, - }) - globalThis.yaw = [yaw, yawRad] - if (global.logYaw) console.log('Pushed', yaw, pitch) - } - - pushCamera(state, id = 1) { - let { x, y, z } = state.position - if (id == 1) y -= 1.62 // account for player bb - const pos = vec3({ x, y, z }) - if (state.position) { - viewer.viewer.entities.update({ - name: 'player', - id, pos, width: 0.6, height: 1.8, - yaw: id == 1 ? d2r(state.yaw) : state.yaw - }) - - //viewer.viewer.camera.position.set(x, y, z) - } - - if (state.input_data.sneak_down) { - this.player.entity.position = pos - this.playerState.pos = this.player.entity.position - } - } - - onCameraMovement(newYaw, newPitch, newHeadYaw) { - this.player.yaw = newYaw - this.player.pitch = newPitch - this.player.headYaw = newHeadYaw - } - - stopPhys() { - clearInterval(this.physicsLoop) + this.movements.stopPhys() } } -const d2r = deg => (180 - (deg < 0 ? (360 + deg) : deg)) * (Math.PI / 180) module.exports = { BotProvider } diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js index 7600b0a..a0987e7 100644 --- a/examples/viewer/client/BotViewer.js +++ b/examples/viewer/client/BotViewer.js @@ -1,21 +1,16 @@ /* global THREE */ const { Viewer, MapControls } = require('prismarine-viewer/viewer') -const { Vec3 } = require('vec3') -const { BotProvider } = require('./BotProvider') +// const { Vec3 } = require('vec3') +// const { BotProvider } = require('./BotProvider') const { ProxyProvider } = require('./ProxyProvider') global.THREE = require('three') const MCVER = '1.16.1' class BotViewer { - constructor () { - - } - start () { // this.bot = new BotProvider() this.bot = new ProxyProvider() - // return // Create three.js context, add to page this.renderer = new THREE.WebGLRenderer() this.renderer.setPixelRatio(window.devicePixelRatio || 1) @@ -61,8 +56,6 @@ class BotViewer { onKeyDown = (evt) => { console.log('Key down', evt) - // this.bot.initPhys() - // this.bot.startPhys() } registerBrowserEvents () { diff --git a/examples/viewer/client/Chunk.js b/examples/viewer/client/Chunk.js index b2ecc57..7733cc3 100644 --- a/examples/viewer/client/Chunk.js +++ b/examples/viewer/client/Chunk.js @@ -1,6 +1,4 @@ -const { ChunkColumn, Version } = require('bedrock-provider') -const { SubChunk } = require('bedrock-provider/js/SubChunk') -try { const v8 = require('v8') } catch { } +const { ChunkColumn } = require('bedrock-provider') const Block = require('prismarine-block')('1.16.1') @@ -13,42 +11,6 @@ class ChunkColumnWrapped extends ChunkColumn { // pchunk compatiblity wrapper getBlockStateId (pos) { return super.getBlock(pos.x, pos.y, pos.z)?.stateId } - - // // Serialization - // serialize() { - // if (typeof v8 === 'undefined') { - // return JSON.stringify(this) - // } else { - // const copy = { ...this, sections: [] } - // for (const section of this.sections) { - // copy.sections.push(v8.serialize(section)) - // } - // return v8.serialize(copy) - // } - // } - - // toJson() { return this.serialize() } - - // static deserialize(obj) { - // if (typeof obj === 'string') { - // Oject.assign(this, JSON.parse(obj)) - // } else { // Buffer - // const chunk = new ChunkColumnWrapped() - // const des = v8.deserialize(obj) - // Object.assign(chunk, des) - // chunk.sections = [] - // for (const section of des.sections) { - // const s = new SubChunk() - // chunk.sections.push(Object.assign(s, v8.deserialize(section))) - // } - // // console.log('Des',obj,chunk) - // return chunk - // } - // } - - // static fromJson(obj) { - // return ChunkColumnWrapped.deserialize(obj) - // } } module.exports = (version) => { diff --git a/examples/viewer/client/ClientProvider.js b/examples/viewer/client/ClientProvider.js new file mode 100644 index 0000000..8c13da8 --- /dev/null +++ b/examples/viewer/client/ClientProvider.js @@ -0,0 +1,68 @@ +const { Client } = require('bedrock-protocol') +const { BotProvider } = require('./BotProvider') + +class ClientProvider extends BotProvider { + connect () { + const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', port: 19132, connectTimeout: 100000 }) + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) + + this.client = client + } + + close () { + this.client?.close() + } + + listenToBot () { + this.client.on('connect', () => { + console.log('Bot has connected!') + }) + this.client.on('start_game', packet => { + this.updatePosition(packet.player_position) + }) + + this.client.on('spawn', () => { + // server allows client to render chunks & spawn in world + this.emit('spawn', { position: this.lastPos }) + + this.tickLoop = setInterval(() => { + this.client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) + }) + + this.client.on('level_chunk', packet => { + this.handleChunk(packet) + }) + + this.client.on('move_player', packet => { + if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) + }) + + this.client.on('set_entity_motion', packet => { + if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) + }) + + this.client.on('tick_sync', (packet) => { + this.lastTick = packet.response_time + }) + } +} + +module.exports = { ClientProvider } diff --git a/examples/viewer/client/ProxyProvider.js b/examples/viewer/client/ProxyProvider.js index 0db00df..305b4a4 100644 --- a/examples/viewer/client/ProxyProvider.js +++ b/examples/viewer/client/ProxyProvider.js @@ -1,6 +1,6 @@ const { Relay } = require('bedrock-protocol') const { BotProvider } = require('./BotProvider') -const vec3 = require('vec3') +const { diff } = require('./util') class ProxyProvider extends BotProvider { lastPlayerMovePacket @@ -15,61 +15,36 @@ class ProxyProvider extends BotProvider { port: 19132 } }) - proxy.listen() - console.info('Waiting for connect') - const maxChunks = 40 - proxy.on('join', (client, server) => { client.on('clientbound', ({ name, params }) => { - if (name == 'level_chunk') { - // maxChunks-- - // if (maxChunks >= 0) { - // this.handleChunk(params) - // } + if (name === 'level_chunk') { this.handleChunk(params, true) - } else if (name == 'start_game') { - this.initPhys(params.player_position, null, params.rotation.z, params.rotation.x, 0) + } else if (name === 'start_game') { + this.movements.init('', params.player_position, null, params.rotation.z, params.rotation.x, 0) } else if (name === 'play_status') { - // this.emit('spawn', { position: server.startGameData.player_position }) - - this.startPhys() + this.movements.startPhys() console.info('Started physics!') } else if (name === 'move_player') { - console.log('move_player', packet) - // if (packet.runtime_id === server.entityId) { - // this.updatePosition(packet.position) - // if (this.lastServerMovement.x == packet.position.x && this.lastServerMovement.y == packet.position.y && this.lastServerMovement.z == packet.position.z) { - - // } else { - // console.log('Server computed', packet.position) - // } - // this.lastServerMovement = { ...packet.position } - // } + console.log('move_player', params) + this.movements.updatePosition(params.position, params.yaw, params.pitch, params.head_yaw, params.tick) } + if (name.includes('entity') || name.includes('network_chunk_publisher_update') || name.includes('tick') || name.includes('level')) return console.log('CB', name) }) client.on('serverbound', ({ name, params }) => { // { name, params } - if (name == 'player_auth_input') { - // console.log('player_auth_input', this.lastPlayerMovePacket, params) - - // this.controls.forward = params.input_data.up - // this.controls.back = params.input_data.down - // this.controls.left = params.input_data.left - // this.controls.right = params.input_data.right - // this.player.entity.pitch = params.pitch - // this.player.entity.yaw = params.yaw - this.pushInputState(params.input_data, params.yaw, params.pitch) - this.pushCamera(params) - this.lastMovePacket = params + if (name === 'player_auth_input') { + this.movements.pushInputState(params.input_data, params.yaw, params.pitch) + this.movements.pushCameraControl(params, 1) // Log Movement deltas { + this.lastMovePacket = params if (this.firstPlayerMovePacket) { const id = diff(this.firstPlayerMovePacket.input_data, params.input_data) const md = diff(this.firstPlayerMovePacket.move_vector, params.move_vector) @@ -109,18 +84,5 @@ class ProxyProvider extends BotProvider { } } -const difference = (o1, o2) => Object.keys(o2).reduce((diff, key) => { - if (o1[key] === o2[key]) return diff - return { - ...diff, - [key]: o2[key] - } -}, {}) - -// console.log = () => {} -// console.debug = () => {} - -const diff = (o1, o2) => { const dif = difference(o1, o2); return Object.keys(dif).length ? dif : null } - module.exports = { ProxyProvider } globalThis.logging = true diff --git a/examples/viewer/client/movements.js b/examples/viewer/client/movements.js new file mode 100644 index 0000000..a405722 --- /dev/null +++ b/examples/viewer/client/movements.js @@ -0,0 +1,244 @@ +const { Physics, PlayerState } = require('prismarine-physics') +const { performance } = require('perf_hooks') +const { d2r } = require('./util') +const vec3 = require('vec3') + +const PHYSICS_INTERVAL_MS = 50 +const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000 + +class MovementManager { + // Server auth movement : we send inputs, server calculates position & sends back + serverMovements = false + + constructor (bot) { + this.bot = bot + this.world = bot.world + // Physics tick + this.tick = 0n + } + + get lastPos () { return this.player.entity.position.clone() } + set lastPos (newPos) { this.player.entity.position.set(newPos.x, newPos.y, newPos.z) } + + get lastRot () { return vec3(this.player.entity.yaw, this.player.entity.pitch, this.player.entity.headYaw) } + + set lastRot (rot) { + this.player.entity.yaw = rot.x + this.player.entity.pitch = rot.y + if (rot.z) this.player.entity.headYaw = rot.z + } + + // Ask the server to be in a new position + requestPosition (time, inputState) { + const positionUpdated = !this.lastSentPos || !this.lastPos.equals(this.lastSentPos) + const rotationUpdated = !this.lastSentRot || !this.lastRot.equals(this.lastSentRot) + + if (positionUpdated) { + this.lastSentPos = this.lastPos.clone() + console.log('We computed', this.lastPos) + this.bot.updatePlayerCamera(2, this.lastSentPos, this.playerState.yaw, this.playerState.pitch) + if (this.serverMovements) { + this.client.queue('player_auth_input', { + pitch: this.player.pitch, + yaw: this.player.yaw, + position: { + x: this.lastPos.x, + y: this.lastPos.y, + z: this.lastPos.z + }, + move_vector: { // Minecraft coords, N: Z+1, S: Z-1, W: X+1, E: X-1 + x: inputState.left ? 1 : (inputState.right ? -1 : 0), + z: inputState.up ? 1 : (inputState.down ? -1 : 0) + }, + head_yaw: this.player.headYaw, + input_data: inputState, + input_mode: 'mouse', + play_mode: 'screen', + tick: this.tick, + delta: this.lastSentPos?.minus(this.lastPos) ?? { x: 0, y: 0, z: 0 } + }) + this.positionUpdated = false + } + + this.lastSentPos = this.lastPos + this.lastSentRot = this.lastRot + } + } + + init (movementAuthority, position, velocity, yaw = 0, pitch = 0, headYaw = 0) { + if (movementAuthority.includes('server')) { + this.serverMovements = true + } + this.player = { + version: '1.16.1', + inventory: { + slots: [] + }, + entity: { + effects: {}, + position: vec3(position), + velocity: vec3(velocity), + onGround: false, + isInWater: false, + isInLava: false, + isInWeb: false, + isCollidedHorizontally: false, + isCollidedVertically: false, + yaw, + pitch, + headYaw // bedrock + }, + events: { // Control events to send next tick + startSprint: false, + stopSprint: false, + startSneak: false, + stopSneak: false + }, + jumpTicks: 0, + jumpQueued: false, + downJump: false + } + + const mcData = require('minecraft-data')('1.16.1') + this.physics = Physics(mcData, this.world) + this.controls = { + forward: false, + back: false, + left: false, + right: false, + jump: false, + sprint: false, + sneak: false + } + } + + // This function should be executed each tick (every 0.05 seconds) + // How it works: https://gafferongames.com/post/fix_your_timestep/ + timeAccumulator = 0 + lastPhysicsFrameTime = null + inputQueue = [] + doPhysics () { + const now = performance.now() + const deltaSeconds = (now - this.lastPhysicsFrameTime) / 1000 + this.lastPhysicsFrameTime = now + + this.timeAccumulator += deltaSeconds + + while (this.timeAccumulator >= PHYSICS_TIMESTEP) { + const q = this.inputQueue.shift() + if (q) { + Object.assign(this.playerState.control, q) + if (q.yaw) this.player.entity.yaw = q.yaw + if (q.pitch) this.player.entity.pitch = q.pitch + } + this.playerState = new PlayerState(this.player, this.controls) + this.physics.simulatePlayer(this.playerState, this.world.sync).apply(this.player) + this.lastPos = this.playerState.pos + this.requestPosition(PHYSICS_TIMESTEP, { + ascend: false, + descend: false, + // Players bob up and down in water, north jump is true when going up. + // In water this is only true after the player has reached max height before bobbing back down. + north_jump: this.player.jumpTicks > 0, // Jump + jump_down: this.controls.jump, // Jump + sprint_down: this.controls.sprint, + change_height: false, + jumping: this.controls.jump, // Jump + auto_jumping_in_water: false, + sneaking: false, + sneak_down: false, + up: this.controls.forward, + down: this.controls.back, + left: this.controls.left, + right: this.controls.right, + up_left: false, + up_right: false, + want_up: this.controls.jump, // Jump + want_down: false, + want_down_slow: false, + want_up_slow: false, + sprinting: false, + ascend_scaffolding: false, + descend_scaffolding: false, + sneak_toggle_down: false, + persist_sneak: false, + start_sprinting: this.player.events.startSprint || false, + stop_sprinting: this.player.events.stopSprint || false, + start_sneaking: this.player.events.startSneak || false, + stop_sneaking: this.player.events.stopSneak || false, + // Player is Update Aqatic swimming + start_swimming: false, + // Player stops Update Aqatic swimming + stop_swimming: false, + start_jumping: this.player.jumpTicks === 1, // Jump + start_gliding: false, + stop_gliding: false + }) + this.timeAccumulator -= PHYSICS_TIMESTEP + } + } + + startPhys () { + console.log('Start phys') + this.physicsLoop = setInterval(() => { + this.doPhysics() + }, PHYSICS_INTERVAL_MS) + } + + setControlState (control, state) { + if (this.controls[control] === state) return + if (control === 'sprint') { + this.player.events.startSprint = state + this.player.events.stopSprint = !state + this.controls.sprint = true + } else if (control === 'sneak') { + this.player.events.startSneak = state + this.player.events.stopSneak = !state + this.controls.sprint = true + } + } + + stopPhys () { + clearInterval(this.physicsLoop) + } + + pushInputState (state, yaw, pitch) { + const yawRad = d2r(yaw) + const pitchRad = d2r(pitch) + this.inputQueue.push({ + forward: state.up, + back: state.down, // TODO: left and right switched ??? + left: state.right, + right: state.left, + jump: state.jump_down, + sneak: state.sneak_down, + yaw: yawRad, + pitch: pitchRad + }) + // debug + globalThis.debugYaw = [yaw, yawRad] + } + + pushCameraControl (state, id = 1) { + let { x, y, z } = state.position + if (id === 1) y -= 1.62 // account for player bb + const adjPos = vec3({ x, y, z }) + // Sneak resyncs the position for easy testing + this.bot.updatePlayerCamera(id, adjPos, d2r(state.yaw), d2r(state.pitch), state.input_data.sneak_down) + } + + // Server gives us a new position + updatePosition (pos, yaw, pitch, headYaw, tick) { + this.lastPos = pos + this.lastRot = { x: yaw, y: pitch, z: headYaw } + if (tick) this.tick = tick + } + + onViewerCameraMove (newYaw, newPitch, newHeadYaw) { + this.player.yaw = newYaw + this.player.pitch = newPitch + this.player.headYaw = newHeadYaw + } +} + +module.exports = { MovementManager } diff --git a/examples/viewer/client/util.js b/examples/viewer/client/util.js new file mode 100644 index 0000000..a22a646 --- /dev/null +++ b/examples/viewer/client/util.js @@ -0,0 +1,16 @@ +const difference = (o1, o2) => Object.keys(o2).reduce((diff, key) => { + if (o1[key] === o2[key]) return diff + return { + ...diff, + [key]: o2[key] + } +}, {}) + +const diff = (o1, o2) => { const dif = difference(o1, o2); return Object.keys(dif).length ? dif : null } + +const d2r = deg => (180 - (deg < 0 ? (360 + deg) : deg)) * (Math.PI / 180) + +module.exports = { + diff, + d2r +} diff --git a/src/connection.js b/src/connection.js index 6a55a1a..f4476bc 100644 --- a/src/connection.js +++ b/src/connection.js @@ -24,7 +24,7 @@ class Connection extends EventEmitter { } set status (val) { - this.inLog('* new status', val) + debug('* new status', val) this.#status = val } @@ -126,7 +126,7 @@ class Connection extends EventEmitter { sendEncryptedBatch (batch) { const buf = batch.stream.getBuffer() - debug('Sending encrypted batch', batch) + // debug('Sending encrypted batch', batch) this.encrypt(buf) } diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 07587ae..a409fca 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -104,7 +104,7 @@ async function startServerAndWait (version, withTimeout, options) { if (!module.parent) { // if (process.argv.length < 3) throw Error('Missing version argument') - startServer(process.argv[2] || '1.16.201') + startServer(process.argv[2] || '1.16.201', null, process.argv[3] ? { 'server-port': process.argv[3] } : undefined) } module.exports = { fetchLatestStable, startServer, startServerAndWait } From 7a830317eaf6bd6d7d1f27d4ebcb2d3d8148c3d9 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 4 Apr 2021 03:52:06 -0400 Subject: [PATCH 150/458] viewer: first person views --- examples/viewer/client/BotProvider.js | 22 +++++------------- examples/viewer/client/BotViewer.js | 30 +++++++++++++++++++++++-- examples/viewer/client/ProxyProvider.js | 1 + 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/examples/viewer/client/BotProvider.js b/examples/viewer/client/BotProvider.js index fe225cf..4549959 100644 --- a/examples/viewer/client/BotProvider.js +++ b/examples/viewer/client/BotProvider.js @@ -1,4 +1,3 @@ -/* eslint-disable */ const { Version } = require('bedrock-provider') const { WorldView } = require('prismarine-viewer/viewer') const World = require('prismarine-world')() @@ -10,7 +9,7 @@ class BotProvider extends WorldView { lastSentPos positionUpdated = true - constructor() { + constructor () { super() this.connect() this.listenToBot() @@ -18,7 +17,7 @@ class BotProvider extends WorldView { this.movements = new MovementManager(this) } - handleChunk(packet, render = true) { + handleChunk (packet, render = true) { const hash = (packet.x << 4) + ',' + (packet.z << 4) if (this.loadChunk[hash]) return const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) @@ -31,24 +30,15 @@ class BotProvider extends WorldView { }) } - updatePlayerCamera(id, pos, yaw, pitch, updateState) { - // TODO: do this properly - window.viewer.viewer.entities.update({ - name: 'player', - id, - pos, - width: 0.6, - height: 1.8, - yaw, - pitch - }) + updatePlayerCamera (id, position, yaw, pitch, updateState) { + this.emit('playerMove', id, { position, yaw, pitch }) if (updateState) { - this.movements.updatePosition(pos, yaw, pitch) + this.movements.updatePosition(position, yaw, pitch) } } - stopBot() { + stopBot () { clearInterval(this.tickLoop) this.movements.stopPhys() } diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js index a0987e7..a29cc6f 100644 --- a/examples/viewer/client/BotViewer.js +++ b/examples/viewer/client/BotViewer.js @@ -29,11 +29,33 @@ class BotViewer { // Link WorldView and Viewer this.viewer.listen(this.bot) - this.bot.on('spawn', ({ position }) => { + this.bot.on('spawn', ({ position, firstPerson }) => { // Initialize viewer, load chunks this.bot.init(position) // Start listening for keys this.registerBrowserEvents() + + if (firstPerson && this.bot.movements) { + this.firstPerson = true + } else { + this.viewer.camera.position.set(position.x, position.y, position.z) + } + }) + + this.bot.on('playerMove', (id, pos) => { + if (this.firstPerson && id === 1) { + this.setFirstPersonCamera(pos) + } + + window.viewer.viewer.entities.update({ + name: 'player', + id, + pos: pos.position, + width: 0.6, + height: 1.8, + yaw: pos.yaw, + pitch: pos.pitch + }) }) this.controls.update() @@ -41,7 +63,7 @@ class BotViewer { // Browser animation loop const animate = () => { window.requestAnimationFrame(animate) - if (this.controls) this.controls.update() + if (this.controls && !this.firstPerson) this.controls.update() this.viewer.update() this.renderer.render(this.viewer.scene, this.viewer.camera) } @@ -61,6 +83,10 @@ class BotViewer { registerBrowserEvents () { this.renderer.domElement.parentElement.addEventListener('keydown', this.onKeyDown) } + + setFirstPersonCamera (entity) { + this.viewer.setFirstPersonCamera(entity.position, entity.yaw, entity.pitch * 2) + } } module.exports = { BotViewer } diff --git a/examples/viewer/client/ProxyProvider.js b/examples/viewer/client/ProxyProvider.js index 305b4a4..de97ee6 100644 --- a/examples/viewer/client/ProxyProvider.js +++ b/examples/viewer/client/ProxyProvider.js @@ -26,6 +26,7 @@ class ProxyProvider extends BotProvider { this.movements.init('', params.player_position, null, params.rotation.z, params.rotation.x, 0) } else if (name === 'play_status') { this.movements.startPhys() + this.emit('spawn', { position: this.movements.lastPos, firstPerson: true }) console.info('Started physics!') } else if (name === 'move_player') { console.log('move_player', params) From 01f19164bab4200896eeb5d8889d5b407f8e921e Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 7 Apr 2021 01:56:32 -0400 Subject: [PATCH 151/458] viewer: key control movement --- examples/viewer/client/BotProvider.js | 11 +++++ examples/viewer/client/BotViewer.js | 55 +++++++++++++++++++++--- examples/viewer/client/ClientProvider.js | 52 ++++++++++++++++++++-- examples/viewer/client/movements.js | 22 +++++++--- examples/viewer/index.js | 6 ++- 5 files changed, 129 insertions(+), 17 deletions(-) diff --git a/examples/viewer/client/BotProvider.js b/examples/viewer/client/BotProvider.js index 4549959..4d23377 100644 --- a/examples/viewer/client/BotProvider.js +++ b/examples/viewer/client/BotProvider.js @@ -15,8 +15,19 @@ class BotProvider extends WorldView { this.listenToBot() this.world = new World() this.movements = new MovementManager(this) + + this.onKeyDown = () => {} + this.onKeyUp = () => {} + + this.removeAllListeners('mouseClick') } + raycast () { + // TODO : fix + } + + get entity () { return this.movements.player.entity } + handleChunk (packet, render = true) { const hash = (packet.x << 4) + ',' + (packet.z << 4) if (this.loadChunk[hash]) return diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js index a29cc6f..384008e 100644 --- a/examples/viewer/client/BotViewer.js +++ b/examples/viewer/client/BotViewer.js @@ -1,7 +1,7 @@ /* global THREE */ const { Viewer, MapControls } = require('prismarine-viewer/viewer') // const { Vec3 } = require('vec3') -// const { BotProvider } = require('./BotProvider') +const { ClientProvider } = require('./ClientProvider') const { ProxyProvider } = require('./ProxyProvider') global.THREE = require('three') @@ -9,8 +9,8 @@ const MCVER = '1.16.1' class BotViewer { start () { - // this.bot = new BotProvider() - this.bot = new ProxyProvider() + this.bot = new ClientProvider() + // this.bot = new ProxyProvider() // Create three.js context, add to page this.renderer = new THREE.WebGLRenderer() this.renderer.setPixelRatio(window.devicePixelRatio || 1) @@ -36,15 +36,18 @@ class BotViewer { this.registerBrowserEvents() if (firstPerson && this.bot.movements) { + this.viewer.camera.position.set(position.x, position.y, position.z) this.firstPerson = true + this.controls.enabled = false } else { this.viewer.camera.position.set(position.x, position.y, position.z) } }) this.bot.on('playerMove', (id, pos) => { - if (this.firstPerson && id === 1) { + if (this.firstPerson && id < 10) { this.setFirstPersonCamera(pos) + return } window.viewer.viewer.entities.update({ @@ -58,6 +61,13 @@ class BotViewer { }) }) + this.bot.on('startSprint', () => { + this.viewer.camera.fov += 20 + }) + this.bot.on('stopSprint', () => { + this.viewer.camera.fov -= 20 + }) + this.controls.update() // Browser animation loop @@ -76,12 +86,43 @@ class BotViewer { }) } - onKeyDown = (evt) => { - console.log('Key down', evt) + onMouseMove = (e) => { + if (this.firstPerson) { + this.bot.entity.pitch -= e.movementY * 0.005 + this.bot.entity.yaw -= e.movementX * 0.004 + } + } + + onPointerLockChange = () => { + const e = this.renderer.domElement + if (document.pointerLockElement === e) { + e.parentElement.addEventListener('mousemove', this.onMouseMove, { passive: true }) + } else { + e.parentElement.removeEventListener('mousemove', this.onMouseMove, false) + } + } + + onMouseDown = () => { + if (this.firstPerson && !document.pointerLockElement) { + this.renderer.domElement.requestPointerLock() + } } registerBrowserEvents () { - this.renderer.domElement.parentElement.addEventListener('keydown', this.onKeyDown) + const e = this.renderer.domElement + e.parentElement.addEventListener('keydown', this.bot.onKeyDown) + e.parentElement.addEventListener('keyup', this.bot.onKeyUp) + e.parentElement.addEventListener('mousedown', this.onMouseDown) + document.addEventListener('pointerlockchange', this.onPointerLockChange, false) + } + + unregisterBrowserEvents () { + const e = this.renderer.domElement + e.parentElement.removeEventListener('keydown', this.bot.onKeyDown) + e.parentElement.removeEventListener('keyup', this.bot.onKeyUp) + e.parentElement.removeEventListener('mousemove', this.onMouseMove) + e.parentElement.removeEventListener('mousedown', this.onMouseDown) + document.removeEventListener('pointerlockchange', this.onPointerLockChange, false) } setFirstPersonCamera (entity) { diff --git a/examples/viewer/client/ClientProvider.js b/examples/viewer/client/ClientProvider.js index 8c13da8..62aae74 100644 --- a/examples/viewer/client/ClientProvider.js +++ b/examples/viewer/client/ClientProvider.js @@ -1,7 +1,18 @@ const { Client } = require('bedrock-protocol') const { BotProvider } = require('./BotProvider') +const controlMap = { + forward: ['KeyW', 'KeyZ'], + back: 'KeyS', + left: ['KeyA', 'KeyQ'], + right: 'KeyD', + sneak: 'ShiftLeft', + jump: 'Space' +} + class ClientProvider extends BotProvider { + downKeys = new Set() + connect () { const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', port: 19132, connectTimeout: 100000 }) @@ -20,7 +31,10 @@ class ClientProvider extends BotProvider { client.queue('client_cache_status', { enabled: false }) client.queue('request_chunk_radius', { chunk_radius: 1 }) - client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + + this.heartbeat = setInterval(() => { + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) }) this.client = client @@ -36,11 +50,13 @@ class ClientProvider extends BotProvider { }) this.client.on('start_game', packet => { this.updatePosition(packet.player_position) + this.movements.init('', packet.player_position, null, packet.rotation.z, packet.rotation.x, 0) }) this.client.on('spawn', () => { + this.movements.startPhys() // server allows client to render chunks & spawn in world - this.emit('spawn', { position: this.lastPos }) + this.emit('spawn', { position: this.lastPos, firstPerson: true }) this.tickLoop = setInterval(() => { this.client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) @@ -52,17 +68,45 @@ class ClientProvider extends BotProvider { }) this.client.on('move_player', packet => { - if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) + if (packet.runtime_id === this.client.entityId) { this.movements.updatePosition(packet.position, packet.yaw, packet.pitch, packet.head_yaw, packet.tick) } }) this.client.on('set_entity_motion', packet => { - if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) + // if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) }) this.client.on('tick_sync', (packet) => { this.lastTick = packet.response_time }) } + + onKeyDown = (evt) => { + const code = evt.code + for (const control in controlMap) { + if (controlMap[control].includes(code)) { + this.movements.setControlState(control, true) + break + } + if (evt.ctrlKey) { + this.movements.setControlState('sprint', true) + } + } + this.downKeys.add(code) + } + + onKeyUp = (evt) => { + const code = evt.code + if (code == 'ControlLeft' && this.downKeys.has('ControlLeft')) { + this.movements.setControlState('sprint', false) + } + for (const control in controlMap) { + if (controlMap[control].includes(code)) { + this.movements.setControlState(control, false) + break + } + } + this.downKeys.delete(code) + } } module.exports = { ClientProvider } diff --git a/examples/viewer/client/movements.js b/examples/viewer/client/movements.js index a405722..d5f52c0 100644 --- a/examples/viewer/client/movements.js +++ b/examples/viewer/client/movements.js @@ -19,9 +19,7 @@ class MovementManager { get lastPos () { return this.player.entity.position.clone() } set lastPos (newPos) { this.player.entity.position.set(newPos.x, newPos.y, newPos.z) } - get lastRot () { return vec3(this.player.entity.yaw, this.player.entity.pitch, this.player.entity.headYaw) } - set lastRot (rot) { this.player.entity.yaw = rot.x this.player.entity.pitch = rot.y @@ -33,10 +31,10 @@ class MovementManager { const positionUpdated = !this.lastSentPos || !this.lastPos.equals(this.lastSentPos) const rotationUpdated = !this.lastSentRot || !this.lastRot.equals(this.lastSentRot) - if (positionUpdated) { + if (positionUpdated || rotationUpdated) { this.lastSentPos = this.lastPos.clone() - console.log('We computed', this.lastPos) - this.bot.updatePlayerCamera(2, this.lastSentPos, this.playerState.yaw, this.playerState.pitch) + // console.log('We computed', this.lastPos) + this.bot.updatePlayerCamera(2, this.lastSentPos, this.playerState.yaw, this.playerState.pitch || this.player.entity.pitch) if (this.serverMovements) { this.client.queue('player_auth_input', { pitch: this.player.pitch, @@ -175,6 +173,7 @@ class MovementManager { stop_gliding: false }) this.timeAccumulator -= PHYSICS_TIMESTEP + this.tick++ } } @@ -185,16 +184,29 @@ class MovementManager { }, PHYSICS_INTERVAL_MS) } + /** + * Sets the active control state and also keeps track of key toggles. + * @param {'forward' | 'back' | 'left' | 'right' | 'jump' | 'sprint' | 'sneak'} control + * @param {boolean} state + */ setControlState (control, state) { + // HACK ! switch left and right, fixes control issue + if (control === 'left') control = 'right' + else if (control === 'right') control = 'left' + if (this.controls[control] === state) return if (control === 'sprint') { this.player.events.startSprint = state this.player.events.stopSprint = !state + if (state) this.bot.emit('startSprint') + else this.bot.emit('stopSprint') this.controls.sprint = true } else if (control === 'sneak') { this.player.events.startSneak = state this.player.events.stopSneak = !state this.controls.sprint = true + } else { + this.controls[control] = state } } diff --git a/examples/viewer/index.js b/examples/viewer/index.js index f2a942c..5d17e38 100644 --- a/examples/viewer/index.js +++ b/examples/viewer/index.js @@ -1,5 +1,5 @@ const path = require('path') -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, globalShortcut } = require('electron') function createMainWindow () { const window = new BrowserWindow({ @@ -28,6 +28,10 @@ function createMainWindow () { app.on('ready', () => { createMainWindow() + + globalShortcut.register('CommandOrControl+W', () => { + // no op + }) }) app.on('window-all-closed', function () { From 2aade9403346a18f9d35e8490699ccce4f0ccd5b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 7 Apr 2021 06:56:24 -0400 Subject: [PATCH 152/458] update raknet-native, remove aes-js --- package.json | 3 +-- src/rak.js | 13 ++++++------ src/server/advertisement.js | 39 ++++++++++++++++++++++++++++++++++++ src/transforms/encryption.js | 26 ++++++++---------------- 4 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 src/server/advertisement.js diff --git a/package.json b/package.json index 8090cfa..51cdac9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "@azure/msal-node": "^1.0.0-beta.6", "@jsprismarine/jsbinaryutils": "^2.1.8", "@xboxreplay/xboxlive-auth": "^3.3.3", - "aes-js": "^3.1.2", "asn1": "^0.2.4", "browserify-cipher": "^1.0.1", "debug": "^4.3.1", @@ -35,7 +34,7 @@ "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", "protodef": "^1.11.0", - "raknet-native": "^0.2.0", + "raknet-native": "^1.0.0", "uuid-1345": "^1.0.2" }, "devDependencies": { diff --git a/src/rak.js b/src/rak.js index 88682d6..912df2d 100644 --- a/src/rak.js +++ b/src/rak.js @@ -5,8 +5,9 @@ const Reliability = require('jsp-raknet/protocol/reliability') const RakClient = require('jsp-raknet/client') const ConnWorker = require('./rakWorker') const { waitFor } = require('./datatypes/util') +const ServerName = require('./server/advertisement') try { - var { Client, Server, PacketPriority, PacketReliability, McPingMessage } = require('raknet-native') // eslint-disable-line + var { Client, Server, PacketPriority, PacketReliability } = require('raknet-native') // eslint-disable-line } catch (e) { console.debug('[raknet] native not found, using js', e) } @@ -19,7 +20,7 @@ class RakNativeClient extends EventEmitter { this.onCloseConnection = () => { } this.onEncapsulated = () => { } - this.raknet = new Client(options.hostname, options.port, 'minecraft') + this.raknet = new Client(options.hostname, options.port, { protocolVersion: 10 }) this.raknet.on('encapsulated', ({ buffer, address }) => { this.onEncapsulated(buffer, address) }) @@ -65,16 +66,17 @@ class RakNativeClient extends EventEmitter { } class RakNativeServer extends EventEmitter { - constructor (options = {}) { + constructor (options = {}, server) { super() this.onOpenConnection = () => { } this.onCloseConnection = () => { } this.onEncapsulated = () => { } this.raknet = new Server(options.hostname, options.port, { maxConnections: options.maxConnections || 3, - minecraft: {}, - message: new McPingMessage().toBuffer() + protocolVersion: 10, + message: ServerName.getServerName(server) }) + // TODO: periodically update the server name until we're closed this.raknet.on('openConnection', (client) => { client.sendReliable = function (buffer, immediate) { @@ -91,7 +93,6 @@ class RakNativeServer extends EventEmitter { }) this.raknet.on('encapsulated', ({ buffer, address }) => { - // console.log('ENCAP',thingy) this.onEncapsulated(buffer, address) }) } diff --git a/src/server/advertisement.js b/src/server/advertisement.js new file mode 100644 index 0000000..0b9a401 --- /dev/null +++ b/src/server/advertisement.js @@ -0,0 +1,39 @@ +class ServerName { + motd = 'Bedrock Protocol Server' + name = 'bedrock-protocol' + protocol = 408 + version = '1.16.20' + players = { + online: 0, + max: 5 + } + + gamemode = 'Creative' + serverId = '0' + + toString (version) { + return [ + 'MCPE', + this.motd, + this.protocol, + this.version, + this.players.online, + this.players.max, + this.serverId, + this.name, + this.gamemode + ].join(';') + ';' + } + + toBuffer (version) { + const str = this.toString(version) + return Buffer.concat([Buffer.from([0, str.length]), Buffer.from(str)]) + } +} + +module.exports = { + ServerName, + getServerName (client) { + return new ServerName().toBuffer() + } +} diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 81a70af..f06a279 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,8 +1,7 @@ const { Transform } = require('readable-stream') -const crypto = globalThis.isElectron ? require('browserify-cipher/browser') : require('crypto') -const { createHash } = require('crypto') -const aesjs = require('aes-js') +const crypto = require('crypto') const Zlib = require('zlib') +if (globalThis.isElectron) var { CipherCFB8 } = require('raknet-native') // eslint-ignore-line const CIPHER_ALG = 'aes-256-cfb8' @@ -23,37 +22,28 @@ function createDecipher (secret, initialValue) { class Cipher extends Transform { constructor (secret, iv) { super() - this.aes = new aesjs.ModeOfOperation.cfb(secret, iv, 1) // eslint-disable-line new-cap + this.aes = new CipherCFB8(secret, iv) } _transform (chunk, enc, cb) { - try { - const res = this.aes.encrypt(chunk) - cb(null, res) - } catch (e) { - cb(e) - } + const ciphered = this.aes.cipher(chunk) + cb(null, ciphered) } } class Decipher extends Transform { constructor (secret, iv) { super() - this.aes = new aesjs.ModeOfOperation.cfb(secret, iv, 1) // eslint-disable-line new-cap + this.aes = new CipherCFB8(secret, iv) } _transform (chunk, enc, cb) { - try { - const res = this.aes.decrypt(chunk) - cb(null, res) - } catch (e) { - cb(e) - } + cb(null, this.aes.decipher(chunk)) } } function computeCheckSum (packetPlaintext, sendCounter, secretKeyBytes) { - const digest = createHash('sha256') + const digest = crypto.createHash('sha256') const counter = Buffer.alloc(8) counter.writeBigInt64LE(sendCounter, 0) digest.update(counter) From 41b9f7b383aba7a7fe409a39ff2f8fc7b7c0d617 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 7 Apr 2021 07:10:32 -0400 Subject: [PATCH 153/458] viewer: working first person --- .eslintignore | 1 + examples/viewer/client/BotViewer.js | 2 +- examples/viewer/client/ClientProvider.js | 10 ++++--- examples/viewer/client/movements.js | 35 ++++++++++++------------ examples/viewer/client/util.js | 8 +++++- src/relay.js | 2 +- src/transforms/encryption.js | 2 +- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/.eslintignore b/.eslintignore index e69de29..61743e4 100644 --- a/.eslintignore +++ b/.eslintignore @@ -0,0 +1 @@ +examples/viewer \ No newline at end of file diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js index 384008e..867fccb 100644 --- a/examples/viewer/client/BotViewer.js +++ b/examples/viewer/client/BotViewer.js @@ -95,7 +95,7 @@ class BotViewer { onPointerLockChange = () => { const e = this.renderer.domElement - if (document.pointerLockElement === e) { + if (document.pointerLockElement === e) { e.parentElement.addEventListener('mousemove', this.onMouseMove, { passive: true }) } else { e.parentElement.removeEventListener('mousemove', this.onMouseMove, false) diff --git a/examples/viewer/client/ClientProvider.js b/examples/viewer/client/ClientProvider.js index 62aae74..e8f3ada 100644 --- a/examples/viewer/client/ClientProvider.js +++ b/examples/viewer/client/ClientProvider.js @@ -14,7 +14,7 @@ class ClientProvider extends BotProvider { downKeys = new Set() connect () { - const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', port: 19132, connectTimeout: 100000 }) + const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', username: 'notch', offline: true, port: 19132, connectTimeout: 100000 }) client.once('resource_packs_info', (packet) => { client.write('resource_pack_client_response', { @@ -50,7 +50,7 @@ class ClientProvider extends BotProvider { }) this.client.on('start_game', packet => { this.updatePosition(packet.player_position) - this.movements.init('', packet.player_position, null, packet.rotation.z, packet.rotation.x, 0) + this.movements.init('server', packet.player_position, /* vel */ null, packet.rotation.z || 0, packet.rotation.x || 0, 0) }) this.client.on('spawn', () => { @@ -68,7 +68,9 @@ class ClientProvider extends BotProvider { }) this.client.on('move_player', packet => { - if (packet.runtime_id === this.client.entityId) { this.movements.updatePosition(packet.position, packet.yaw, packet.pitch, packet.head_yaw, packet.tick) } + if (packet.runtime_id === this.client.entityId) { + this.movements.updatePosition(packet.position, packet.yaw, packet.pitch, packet.head_yaw, packet.tick) + } }) this.client.on('set_entity_motion', packet => { @@ -96,7 +98,7 @@ class ClientProvider extends BotProvider { onKeyUp = (evt) => { const code = evt.code - if (code == 'ControlLeft' && this.downKeys.has('ControlLeft')) { + if (code === 'ControlLeft' && this.downKeys.has('ControlLeft')) { this.movements.setControlState('sprint', false) } for (const control in controlMap) { diff --git a/examples/viewer/client/movements.js b/examples/viewer/client/movements.js index d5f52c0..0fdb76e 100644 --- a/examples/viewer/client/movements.js +++ b/examples/viewer/client/movements.js @@ -1,6 +1,6 @@ const { Physics, PlayerState } = require('prismarine-physics') const { performance } = require('perf_hooks') -const { d2r } = require('./util') +const { d2r, r2d } = require('./util') const vec3 = require('vec3') const PHYSICS_INTERVAL_MS = 50 @@ -21,9 +21,9 @@ class MovementManager { set lastPos (newPos) { this.player.entity.position.set(newPos.x, newPos.y, newPos.z) } get lastRot () { return vec3(this.player.entity.yaw, this.player.entity.pitch, this.player.entity.headYaw) } set lastRot (rot) { - this.player.entity.yaw = rot.x - this.player.entity.pitch = rot.y - if (rot.z) this.player.entity.headYaw = rot.z + if (!isNaN(rot.x)) this.player.entity.yaw = rot.x + if (!isNaN(rot.y)) this.player.entity.pitch = rot.y + if (!isNaN(rot.z)) this.player.entity.headYaw = rot.z } // Ask the server to be in a new position @@ -36,28 +36,29 @@ class MovementManager { // console.log('We computed', this.lastPos) this.bot.updatePlayerCamera(2, this.lastSentPos, this.playerState.yaw, this.playerState.pitch || this.player.entity.pitch) if (this.serverMovements) { - this.client.queue('player_auth_input', { - pitch: this.player.pitch, - yaw: this.player.yaw, + globalThis.movePayload = { + pitch: r2d(this.player.entity.pitch), + yaw: r2d(this.player.entity.yaw), // r2d(this.player.entity.yaw), position: { x: this.lastPos.x, - y: this.lastPos.y, + y: this.lastPos.y + 1.62, z: this.lastPos.z }, move_vector: { // Minecraft coords, N: Z+1, S: Z-1, W: X+1, E: X-1 x: inputState.left ? 1 : (inputState.right ? -1 : 0), z: inputState.up ? 1 : (inputState.down ? -1 : 0) }, - head_yaw: this.player.headYaw, + head_yaw: r2d(this.player.entity.yaw), // r2d(this.player.entity.headYaw), input_data: inputState, input_mode: 'mouse', play_mode: 'screen', tick: this.tick, delta: this.lastSentPos?.minus(this.lastPos) ?? { x: 0, y: 0, z: 0 } - }) - this.positionUpdated = false + } + this.bot.client.queue('player_auth_input', globalThis.movePayload) } + this.positionUpdated = false this.lastSentPos = this.lastPos this.lastSentRot = this.lastRot } @@ -126,8 +127,8 @@ class MovementManager { const q = this.inputQueue.shift() if (q) { Object.assign(this.playerState.control, q) - if (q.yaw) this.player.entity.yaw = q.yaw - if (q.pitch) this.player.entity.pitch = q.pitch + if (!isNaN(q.yaw)) this.player.entity.yaw = q.yaw + if (!isNaN(q.pitch)) this.player.entity.pitch = q.pitch } this.playerState = new PlayerState(this.player, this.controls) this.physics.simulatePlayer(this.playerState, this.world.sync).apply(this.player) @@ -147,8 +148,8 @@ class MovementManager { sneak_down: false, up: this.controls.forward, down: this.controls.back, - left: this.controls.left, - right: this.controls.right, + left: this.controls.right, + right: this.controls.left, up_left: false, up_right: false, want_up: this.controls.jump, // Jump @@ -247,9 +248,7 @@ class MovementManager { } onViewerCameraMove (newYaw, newPitch, newHeadYaw) { - this.player.yaw = newYaw - this.player.pitch = newPitch - this.player.headYaw = newHeadYaw + this.lastRot = { x: newYaw, y: newPitch, z: newHeadYaw } } } diff --git a/examples/viewer/client/util.js b/examples/viewer/client/util.js index a22a646..c947af9 100644 --- a/examples/viewer/client/util.js +++ b/examples/viewer/client/util.js @@ -9,8 +9,14 @@ const difference = (o1, o2) => Object.keys(o2).reduce((diff, key) => { const diff = (o1, o2) => { const dif = difference(o1, o2); return Object.keys(dif).length ? dif : null } const d2r = deg => (180 - (deg < 0 ? (360 + deg) : deg)) * (Math.PI / 180) +const r2d = rad => { + let deg = rad * (180 / Math.PI) + deg = deg % 360 + return 180 - deg +} module.exports = { diff, - d2r + d2r, + r2d } diff --git a/src/relay.js b/src/relay.js index 8203ad8..813ec05 100644 --- a/src/relay.js +++ b/src/relay.js @@ -3,7 +3,7 @@ const { Client } = require('./client') const { Server } = require('./server') const { Player } = require('./serverPlayer') const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol relay') -const { serialize } = require('./datatypes/util') +// const { serialize } = require('./datatypes/util') /** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index f06a279..1d4d294 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,7 +1,7 @@ const { Transform } = require('readable-stream') const crypto = require('crypto') const Zlib = require('zlib') -if (globalThis.isElectron) var { CipherCFB8 } = require('raknet-native') // eslint-ignore-line +if (globalThis.isElectron) var { CipherCFB8 } = require('raknet-native') // eslint-disable-line const CIPHER_ALG = 'aes-256-cfb8' From a9ad14008e5dd0f3b647b404d6846833ed3c4fd3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 8 Apr 2021 01:32:20 -0400 Subject: [PATCH 154/458] viewer: add sprint, sneaking --- examples/viewer/client/BotViewer.js | 31 ++++++++--- examples/viewer/client/movements.js | 80 +++++++++++++++++++++++------ examples/viewer/index.js | 9 ++-- package.json | 1 + 4 files changed, 96 insertions(+), 25 deletions(-) diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js index 867fccb..57f9d16 100644 --- a/examples/viewer/client/BotViewer.js +++ b/examples/viewer/client/BotViewer.js @@ -2,7 +2,7 @@ const { Viewer, MapControls } = require('prismarine-viewer/viewer') // const { Vec3 } = require('vec3') const { ClientProvider } = require('./ClientProvider') -const { ProxyProvider } = require('./ProxyProvider') +// const { ProxyProvider } = require('./ProxyProvider') global.THREE = require('three') const MCVER = '1.16.1' @@ -61,12 +61,29 @@ class BotViewer { }) }) - this.bot.on('startSprint', () => { - this.viewer.camera.fov += 20 - }) - this.bot.on('stopSprint', () => { - this.viewer.camera.fov -= 20 - }) + const oldFov = this.viewer.camera.fov + const sprintFov = this.viewer.camera.fov + 20 + const sneakFov = this.viewer.camera.fov - 10 + + const onSprint = () => { + this.viewer.camera.fov = sprintFov + this.viewer.camera.updateProjectionMatrix() + } + + const onSneak = () => { + this.viewer.camera.fov = sneakFov + this.viewer.camera.updateProjectionMatrix() + } + + const onRelease = () => { + this.viewer.camera.fov = oldFov + this.viewer.camera.updateProjectionMatrix() + } + + this.bot.on('startSprint', onSprint) + this.bot.on('startSneak', onSneak) + this.bot.on('stopSprint', onRelease) + this.bot.on('stopSneak', onRelease) this.controls.update() diff --git a/examples/viewer/client/movements.js b/examples/viewer/client/movements.js index 0fdb76e..d359bea 100644 --- a/examples/viewer/client/movements.js +++ b/examples/viewer/client/movements.js @@ -5,6 +5,7 @@ const vec3 = require('vec3') const PHYSICS_INTERVAL_MS = 50 const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000 +const AXES = ['forward', 'back', 'left', 'right'] class MovementManager { // Server auth movement : we send inputs, server calculates position & sends back @@ -38,7 +39,7 @@ class MovementManager { if (this.serverMovements) { globalThis.movePayload = { pitch: r2d(this.player.entity.pitch), - yaw: r2d(this.player.entity.yaw), // r2d(this.player.entity.yaw), + yaw: r2d(this.player.entity.yaw), position: { x: this.lastPos.x, y: this.lastPos.y + 1.62, @@ -48,7 +49,7 @@ class MovementManager { x: inputState.left ? 1 : (inputState.right ? -1 : 0), z: inputState.up ? 1 : (inputState.down ? -1 : 0) }, - head_yaw: r2d(this.player.entity.yaw), // r2d(this.player.entity.headYaw), + head_yaw: r2d(this.player.entity.yaw), input_data: inputState, input_mode: 'mouse', play_mode: 'screen', @@ -93,6 +94,7 @@ class MovementManager { startSneak: false, stopSneak: false }, + sprinting: false, jumpTicks: 0, jumpQueued: false, downJump: false @@ -185,36 +187,80 @@ class MovementManager { }, PHYSICS_INTERVAL_MS) } + get sprinting() { + return this.player.sprinting + } + + set sprinting(val) { + this.player.events.startSprint = val + this.player.events.stopSprint = !val + if (val && !this.player.sprinting) { + this.bot.emit('startSprint') + } else { + this.bot.emit('stopSprint') + } + this.player.sprinting = val + } + + _lastInput = { control: '', time: 0 } + /** * Sets the active control state and also keeps track of key toggles. * @param {'forward' | 'back' | 'left' | 'right' | 'jump' | 'sprint' | 'sneak'} control * @param {boolean} state */ - setControlState (control, state) { + setControlState (control, state, time = Date.now()) { // HACK ! switch left and right, fixes control issue if (control === 'left') control = 'right' else if (control === 'right') control = 'left' if (this.controls[control] === state) return - if (control === 'sprint') { - this.player.events.startSprint = state - this.player.events.stopSprint = !state - if (state) this.bot.emit('startSprint') - else this.bot.emit('stopSprint') - this.controls.sprint = true - } else if (control === 'sneak') { - this.player.events.startSneak = state - this.player.events.stopSneak = !state - this.controls.sprint = true - } else { - this.controls[control] = state + + const isAxis = AXES.includes(control) + let hasOtherAxisKeyDown = false + for (const c of AXES) { + if (this.controls[c] && c != control) { + hasOtherAxisKeyDown = true + } } + + if (control === 'sprint') { + if (state && hasOtherAxisKeyDown) { // sprint down + a axis movement key + this.sprinting = true + } else if ((!state || !hasOtherAxisKeyDown) && this.sprinting) { // sprint up or movement key up & current sprinting + this.bot.emit('stopSprint') + this.sprinting = false + } + } else if (isAxis && this.controls.sprint) { + if (!state && !hasOtherAxisKeyDown) { + this.sprinting = false + } else if (state && !hasOtherAxisKeyDown) { + this.sprinting = true + } + } else if (control === 'sneak') { + if (state) { + this.player.events.startSneak = true + this.bot.emit('startSneak') + } else { + this.player.events.stopSneak = true + this.bot.emit('stopSneak') + } + } else if (control === 'forward' && this._lastInput.control === 'forward' && (Date.now() - this._lastInput.time) < 100 && !this.controls.sprint) { + // double tap forward within 0.5 seconds, toggle sprint + // this.controls.sprint = true + // this.sprinting = true + } + + this._lastInput = { control, time } + this.controls[control] = state } stopPhys () { clearInterval(this.physicsLoop) } + // Called when a proxy player sends a PlayerInputPacket. We need to apply these inputs tick-by-tick + // as these packets are sent by the client every tick. pushInputState (state, yaw, pitch) { const yawRad = d2r(yaw) const pitchRad = d2r(pitch) @@ -232,6 +278,9 @@ class MovementManager { globalThis.debugYaw = [yaw, yawRad] } + + // Called when a proxy player sends a PlayerInputPacket. We need to apply these inputs tick-by-tick + // as these packets are sent by the client every tick. pushCameraControl (state, id = 1) { let { x, y, z } = state.position if (id === 1) y -= 1.62 // account for player bb @@ -247,6 +296,7 @@ class MovementManager { if (tick) this.tick = tick } + // User has moved the camera. Update the movements stored. onViewerCameraMove (newYaw, newPitch, newHeadYaw) { this.lastRot = { x: newYaw, y: newPitch, z: newHeadYaw } } diff --git a/examples/viewer/index.js b/examples/viewer/index.js index 5d17e38..954d4b6 100644 --- a/examples/viewer/index.js +++ b/examples/viewer/index.js @@ -1,7 +1,7 @@ const path = require('path') const { app, BrowserWindow, globalShortcut } = require('electron') -function createMainWindow () { +function createMainWindow() { const window = new BrowserWindow({ webPreferences: { nodeIntegration: true, @@ -27,10 +27,13 @@ function createMainWindow () { } app.on('ready', () => { - createMainWindow() + const win = createMainWindow() globalShortcut.register('CommandOrControl+W', () => { - // no op + win.webContents.sendInputEvent({ + type: 'keyDown', + keyCode: 'W' + }) }) }) diff --git a/package.json b/package.json index 51cdac9..e6371bd 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@xboxreplay/xboxlive-auth": "^3.3.3", "asn1": "^0.2.4", "browserify-cipher": "^1.0.1", + "bedrock-provider": "^1.0.0", "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", From ed2dbcc568a6eb10817b0c9f3a57c82f4294404a Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Sun, 11 Apr 2021 00:48:08 -0400 Subject: [PATCH 155/458] Add packet dumper with same format as java dumper --- tools/dumpPackets.js | 96 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 tools/dumpPackets.js diff --git a/tools/dumpPackets.js b/tools/dumpPackets.js new file mode 100644 index 0000000..8c7b68b --- /dev/null +++ b/tools/dumpPackets.js @@ -0,0 +1,96 @@ +// dumps (up to 5 of each) packet encountered until 'spawn' event +// uses the same format as prismarine-packet-dumper +const fs = require('fs') +const vanillaServer = require('../tools/startVanillaServer') +const { Client } = require('../src/client') +const { serialize, waitFor } = require('../src/datatypes/util') +const { CURRENT_VERSION } = require('../src/options') +const path = require('path') + +const output = path.resolve('output') + +let loop + +async function dump (version) { + const random = ((Math.random() * 100) | 0) + const port = 19130 + random + + const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port }) + + console.log('Started server') + const client = new Client({ + hostname: '127.0.0.1', + port, + username: 'dumpBot', + offline: true + }) + + return waitFor(async res => { + await fs.promises.mkdir(output) + await fs.promises.mkdir(path.join(output, 'from-server')) + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: 1 }) + + clearInterval(loop) + loop = setInterval(() => { + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: BigInt(Date.now()) }) + }, 200) + }) + + const kindCounter = {} + const MAX_PACKETS_PER_TYPE = 5 + client.on('packet', async packet => { // Packet dumping + const { fullBuffer, data: { name, params } } = packet + if (!packet.data.name) return + if (!kindCounter[packet.name]) { + await fs.promises.mkdir(path.join(output, 'from-server', name), { recursive: true }) + kindCounter[name] = 0 + } + if (kindCounter[name] === MAX_PACKETS_PER_TYPE) return + kindCounter[name]++ + + await fs.promises.writeFile(path.join(output, 'from-server', name, `${kindCounter[name]}.bin`), fullBuffer) + + try { + fs.writeFileSync(path.join(output, 'from-server', name, `${kindCounter[name]}.json`), serialize(params, 2)) + } catch (e) { + console.log(e) + } + }) + + console.log('Awaiting join...') + + client.on('spawn', () => { + console.log('Spawned!') + clearInterval(loop) + client.close() + handle.kill() + res() + }) + }, 1000 * 60, () => { + clearInterval(loop) + handle.kill() + throw Error('timed out') + }) +} +async function main () { + if (fs.existsSync(output)) fs.promises.rm(output, { force: true, recursive: true }) + await dump(null, true) + console.log('Successfully dumped packets') +} + +main() From 880b05209373cfa944626ce14ada5f8d5b34e1ab Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 11 Apr 2021 18:47:38 -0400 Subject: [PATCH 156/458] Add CONTRIBUTING.md (#59) * Create CONTRIBUTING.md * Update CONTRIBUTING.md * Update CONTRIBUTING.md --- CONTRIBUTING.md | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d4129d2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,152 @@ +CONTRIBUTING.md + +Contributions are always welcome :) + +## Updating + +Good sources for the Minecraft bedrock protocol are [gophertunnel](https://github.com/Sandertv/gophertunnel/tree/master/minecraft/protocol/packet), [ClouburstMC's protocol library](https://github.com/CloudburstMC/Protocol) and [PocketMine](https://github.com/pmmp/PocketMine-MP/tree/stable/src/pocketmine/network/mcpe/protocol). + +Steps to update: +* Add the version to src/options.js +* Open [data/latest/proto.yml](https://github.com/PrismarineJS/bedrock-protocol/tree/new/data/latest) and add, remove or modify the updated packets (see the [Packet serialization](#Packet_serialization) notes at the bottom for info on syntax) +* Save and make sure to update the !version field at the top of the file +* Run `npm run build` and `npm test` to test + + +## Packet serialization + +This project uses ProtoDef to serialize and deserialize Minecraft packets. See the documentation [here](https://github.com/ProtoDef-io/node-protodef). +The ProtoDef schema is JSON can be found [here](https://github.com/PrismarineJS/bedrock-protocol/blob/4169453835790de7eeaa8fb6f5a6b4344f71036b/data/1.16.210/protocol.json) for use in other languages. + +In bedrock-protocol, JavaScript code is generated from the JSON through the node-protodef compiler. + +#### YAML syntax + +For easier maintainability, the JSON is generated from a more human readable YAML format. You can read more [here](https://github.com/extremeheat/protodef-yaml). + Some documentation is below. + +Packets should go in proto.yml and extra types should go in types.yml. + +```yml +# This defines a new data structure, a ProtoDef container. +PlayerPosition: + # Variable `x` in this struct has a type of `li32`, a little-endian 32-bit integer + x: li32 + # `z` is a 32-bit LE *unsigned* integer + z: lu32 + # `b` is a 32-bit LE floating point + y: lf32 + +# Fields starting with `packet_` are structs representing Minecraft packets +packet_player_position: + # Fields starting with ! are ignored by the parser. '!id' is used by the parser when generating the packet map + !id: 0x29 # This packet is ID #0x29 + !bound: client # `client` or `server` bound, just for documentation purposes. This has no other effect. + + # Read `on_ground` as a boolean + on_ground: bool + # Read `position` as custom data type `PlayerPosition` defined above. + position: Position + + # Reads a 8-bit unsigned integer, then maps it to a string + movement_reason: u8 => + 0: player_jump + 1: player_autojump + 2: player_sneak + 3: player_sprint + 4: player_fall + + # A `_` as a field name declares an anonymous data structure which will be inlined. Adding a '?' at the end will start a `switch` statement + _: movement_reason ? + # if the condition matches to the string "player_jump" or "player_autojump", there is a data struct that needs to be read + if player_jump or player_autojump: + # read `original_position` as a `Position` + original_position: Position + jump_tick: li64 + # if the condition matches "player_fall", read the containing field + if player_fall: + original_position: Position + default: void + + # Another way to declare a switch, without an anonymous structure. `player_hunger` will be read as a 8-bit int if movement_reason == "player_sprint" + player_hunger: movement_reason ? + if player_sprint: u8 + # The default statement as in a switch statement + default: void + + # Square brackets notate an array. At the left is the type of the array values, at the right is the type of + # the length prefix. If no type at the left is specified, the type is defined below. + + # Reads an array of `Position`, length-prefixed with a ProtoBuf-type unsigned variable length integer (VarInt) + last_positions: Position[]varint + + # Reads an array, length-prefixed with a zigzag-encoded signed VarInt + # The data structure for the array is defined underneath + keys_down: []zigzag32 + up: bool + down: bool + shift: bool +``` + +The above roughly translates to the following JavaScript code to read a packet: +```js +function read_player_position(stream) { + const ret = {} + ret.x = stream.readSignedInt32LE() + ret.z = stream.readUnsignedInt32LE() + ret.y = stream.readFloat32LE() + return ret +} + +function read_player_position(stream) { + const ret = {} + ret.on_ground = Boolean(stream.readU8()) + ret.position = read_player_position(stream) + let __movement_reason = stream.readU8() + let movement_reason = { 0: 'player_jump', 1: 'player_autojump', 2: 'player_sneak', 3: 'player_sprint', 4: 'player_fall' }[__movement_reason] + switch (movement_reason) { + case 'player_jump': + case 'player_autojump': + ret.original_position = read_player_position(stream) + ret.jump_tick = stream.readInt64LE(stream) + break + case 'player_fall': + ret.original_position = read_player_position(stream) + break + default: break + } + ret.player_hunger = undefined + if (movement_reason == 'player_sprint') ret.player_hunger = stream.readU8() + ret.last_positions = [] + for (let i = 0; i < stream.readUnsignedVarInt(); i++) { + ret.last_positions.push(read_player_position(stream)) + } + ret.keys_down = [] + for (let i = 0; i < stream.readZigZagVarInt(); i++) { + const ret1 = {} + ret1.up = Boolean(stream.readU8()) + ret1.down = Boolean(stream.readU8()) + ret1.shift = Boolean(stream.readU8()) + ret.keys_down.push(ret1) + } + return ret +} +``` + +and the results in the following JSON for the packet: +```json +{ + "on_ground": false, + "position": { "x": 0, "y": 2, "z": 0 }, + "movement_reason": "player_jump", + "original_position": { "x": 0, "y": 0, "z": 0 }, + "jump_tick": 494894984, + "last_positions": [{ "x": 0, "y": 1, "z": 0 }], + "keys_down": [] +} +``` + +Custom ProtoDef types can be inlined as JSON: +```yml +string: ["pstring",{"countType":"varint"}] +``` From 5499f956b994e86112ed03882bbd04d67e160f9b Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Wed, 14 Apr 2021 04:19:45 -0400 Subject: [PATCH 157/458] Refactor data-provider use in server ex (#64) --- examples/serverTest.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/serverTest.js b/examples/serverTest.js index 58b083e..c060954 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -27,7 +27,7 @@ async function startServer (version = '1.16.210', ok) { let loop const getPath = (packetPath) => DataProvider(server.options.protocolVersion).getPath(packetPath) - const get = (packetPath) => require(getPath('sample/' + packetPath)) + const get = (packetName) => require(getPath(`sample/packets/${packetName}.json`)) server.listen() console.log('Started server') @@ -71,25 +71,25 @@ async function startServer (version = '1.16.210', ok) { client.queue('inventory_slot', { window_id: 120, slot: 0, item: new Item().toBedrock() }) } - client.write('player_list', get('packets/player_list.json')) - client.write('start_game', get('packets/start_game.json')) + client.write('player_list', get('player_list')) + client.write('start_game', get('start_game')) client.write('item_component', { entries: [] }) - client.write('set_spawn_position', get('packets/set_spawn_position.json')) + client.write('set_spawn_position', get('set_spawn_position')) client.write('set_time', { time: 5433771 }) client.write('set_difficulty', { difficulty: 1 }) client.write('set_commands_enabled', { enabled: true }) - client.write('adventure_settings', get('packets/adventure_settings.json')) - client.write('biome_definition_list', get('packets/biome_definition_list.json')) - client.write('available_entity_identifiers', get('packets/available_entity_identifiers.json')) - client.write('update_attributes', get('packets/update_attributes.json')) - client.write('creative_content', get('packets/creative_content.json')) - client.write('inventory_content', get('packets/inventory_content.json')) + client.write('adventure_settings', get('adventure_settings')) + client.write('biome_definition_list', get('biome_definition_list')) + client.write('available_entity_identifiers', get('available_entity_identifiers')) + client.write('update_attributes', get('update_attributes')) + client.write('creative_content', get('creative_content')) + client.write('inventory_content', get('inventory_content')) client.write('player_hotbar', { selected_slot: 3, window_id: 'inventory', select_slot: true }) - client.write('crafting_data', get('packets/crafting_data.json')) - client.write('available_commands', get('packets/available_commands.json')) + client.write('crafting_data', get('crafting_data')) + client.write('available_commands', get('available_commands')) client.write('chunk_radius_update', { chunk_radius: 1 }) - client.write('game_rules_changed', get('packets/game_rules_changed.json')) - client.write('respawn', get('packets/respawn.json')) + client.write('game_rules_changed', get('game_rules_changed')) + client.write('respawn', get('respawn')) for (const chunk of chunks) { client.queue('level_chunk', chunk) From 21a0dcd39326ff039178c092624589adbb5c995a Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Wed, 14 Apr 2021 04:23:04 -0400 Subject: [PATCH 158/458] Add metadata dumping to dumpPackets.js (#63) --- tools/dumpPackets.js | 75 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/tools/dumpPackets.js b/tools/dumpPackets.js index 8c7b68b..8ef569a 100644 --- a/tools/dumpPackets.js +++ b/tools/dumpPackets.js @@ -1,5 +1,6 @@ // dumps (up to 5 of each) packet encountered until 'spawn' event // uses the same format as prismarine-packet-dumper +const assert = require('assert') const fs = require('fs') const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') @@ -7,7 +8,7 @@ const { serialize, waitFor } = require('../src/datatypes/util') const { CURRENT_VERSION } = require('../src/options') const path = require('path') -const output = path.resolve('output') +const output = path.resolve(process.argv[3] ?? 'output') let loop @@ -79,7 +80,7 @@ async function dump (version) { clearInterval(loop) client.close() handle.kill() - res() + res(kindCounter) }) }, 1000 * 60, () => { clearInterval(loop) @@ -87,9 +88,77 @@ async function dump (version) { throw Error('timed out') }) } + +const makeDropdownStart = (name, arr) => { + arr.push(`
${name}`) + arr.push('

') + arr.push('') +} +const makeDropdownEnd = (arr) => { + arr.push('') + arr.push('

') + arr.push('
') +} + +function makeMarkdown (data) { + const str = [] + const { collected, missing } = data + + makeDropdownStart(`Collected (${collected.length})`, str) + str.push('| Packet |') + str.push('| --- |') + collected.forEach(elem => { + str.push(`| ${elem} |`) + }) + makeDropdownEnd(str) + + makeDropdownStart(`Missing (${missing.length})`, str) + str.push('| Packet |') + str.push('| --- |') + missing.forEach(elem => { + str.push(`| ${elem} |`) + }) + makeDropdownEnd(str) + + return str.join('\n') +} + +function parsePacketCounter (version, kindCounter) { + const protocol = require(`../data/${version}/protocol.json`) + // record packets + return { + collectedPackets: Object.keys(kindCounter), + allPackets: Object.keys(protocol) + .filter(o => o.startsWith('packet_')) + .map(o => o.replace('packet_', '')) + } +} + +async function makeStats (kindCounter, version) { + const { collectedPackets, allPackets } = parsePacketCounter(version, kindCounter) + // write packet data + const data = { + collected: collectedPackets, + missing: allPackets.filter(o => !collectedPackets.includes(o)) + } + const metadataFolder = path.join(output, 'metadata') + + await fs.promises.writeFile(path.join(output, 'README.md'), makeMarkdown(data)) + await fs.promises.mkdir(metadataFolder) + await fs.promises.writeFile(path.join(metadataFolder, 'packets_info.json'), JSON.stringify(data, null, 2)) +} + async function main () { + const version = process.argv[2] + if (!version) { + console.error('Usage: node dumpPackets.js [outputPath]') + } + const vers = Object.keys(require('../src/options').Versions) + assert(vers.includes(version), 'Version not supported') if (fs.existsSync(output)) fs.promises.rm(output, { force: true, recursive: true }) - await dump(null, true) + const kindCounter = await dump(version) + await fs.promises.rm(path.join(output, '..', `bds-${version}`), { recursive: true }) + await makeStats(kindCounter, version) console.log('Successfully dumped packets') } From fc39d697989461cd65036917cdec9656fb07d950 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 14 Apr 2021 07:23:42 -0400 Subject: [PATCH 159/458] protocol: inventory, recipe updates --- data/1.16.210/protocol.json | 155 ++++++++++++++++++++---------------- data/latest/proto.yml | 6 +- data/latest/types.yaml | 100 +++++++++++++---------- examples/createRelay.js | 2 +- 4 files changed, 147 insertions(+), 116 deletions(-) diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 9a61484..47043ad 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -1074,8 +1074,8 @@ "container", [ { - "name": "runtime_id", - "type": "zigzag32" + "name": "stack_id", + "type": "varint" }, { "name": "item", @@ -1256,7 +1256,7 @@ }, { "name": "network_id", - "type": "zigzag32" + "type": "varint" } ] ], @@ -1301,7 +1301,7 @@ }, { "name": "network_id", - "type": "zigzag32" + "type": "varint" } ] ], @@ -1346,7 +1346,7 @@ }, { "name": "network_id", - "type": "zigzag32" + "type": "varint" } ] ], @@ -1405,7 +1405,7 @@ }, { "name": "network_id", - "type": "zigzag32" + "type": "varint" } ] ], @@ -1464,7 +1464,7 @@ }, { "name": "network_id", - "type": "zigzag32" + "type": "varint" } ] ], @@ -1515,7 +1515,7 @@ }, { "name": "network_id", - "type": "zigzag32" + "type": "varint" } ] ] @@ -2049,7 +2049,7 @@ "22": "stop_swimming", "23": "start_spin_attack", "24": "stop_spin_attack", - "25": "ineract_block", + "25": "interact_block", "26": "predict_break", "27": "continue_break" } @@ -2059,11 +2059,11 @@ "container", [ { - "name": "container_id", - "type": "u8" + "name": "slot_type", + "type": "ContainerSlotType" }, { - "name": "slot_id", + "name": "slot", "type": "u8" }, { @@ -2077,7 +2077,7 @@ [ { "name": "request_id", - "type": "zigzag32" + "type": "varint" }, { "name": "actions", @@ -2273,7 +2273,7 @@ "container", [ { - "name": "creative_item_network_id", + "name": "item_id", "type": "varint32" } ] @@ -2358,58 +2358,75 @@ "type": "varint32" }, { - "name": "containers", + "anon": true, "type": [ - "array", + "switch", { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot", - "type": "u8" - }, - { - "name": "hotbar_slot", - "type": "u8" - }, - { - "name": "count", - "type": "u8" - }, - { - "name": "item_stack_id", - "type": "varint32" - }, - { - "name": "custom_name", - "type": "string" - }, - { - "name": "durability_correction", - "type": "zigzag32" - } + "compareTo": "status", + "fields": { + "ok": [ + "container", + [ + { + "name": "containers", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot", + "type": "u8" + }, + { + "name": "hotbar_slot", + "type": "u8" + }, + { + "name": "count", + "type": "u8" + }, + { + "name": "item_stack_id", + "type": "varint32" + }, + { + "name": "custom_name", + "type": "string" + }, + { + "name": "durability_correction", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] ] - ] - } - ] - } + } + ] + } + ] ] - ] + }, + "default": "void" } ] } @@ -2575,7 +2592,7 @@ "WindowType": [ "mapper", { - "type": "u8", + "type": "i8", "mappings": { "0": "container", "1": "workbench", @@ -2610,7 +2627,9 @@ "30": "cartography", "31": "hud", "32": "jigsaw_editor", - "33": "smithing_table" + "33": "smithing_table", + "-9": "none", + "-1": "inventory" } } ], @@ -4442,7 +4461,7 @@ "type": "u8" }, { - "name": "windows_id", + "name": "window_id", "type": "WindowID" } ] @@ -4490,7 +4509,7 @@ ] }, { - "name": "target_runtime_entity_id", + "name": "target_entity_id", "type": "varint64" }, { @@ -4748,8 +4767,8 @@ "container", [ { - "name": "inventory_id", - "type": "varint" + "name": "window_id", + "type": "WindowIDVarint" }, { "name": "input", diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 0d8db35..e46463d 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -769,7 +769,7 @@ packet_mob_equipment: item: Item slot: u8 selected_slot: u8 - windows_id: WindowID + window_id: WindowID packet_mob_armor_equipment: !id: 0x20 @@ -793,7 +793,7 @@ packet_interact: 6: open_inventory # TargetEntityRuntimeID is the runtime ID of the entity that the player interacted with. This is empty # for the InteractActionOpenInventory action type. - target_runtime_entity_id: varint64 + target_entity_id: varint64 # Position associated with the ActionType above. For the InteractActionMouseOverEntity, this is the # position relative to the entity moused over over which the player hovered with its mouse/touch. For the # InteractActionLeaveVehicle, this is the position that the player spawns at after leaving the vehicle. @@ -947,7 +947,7 @@ packet_inventory_content: !bound: both # WindowID is the ID that identifies one of the windows that the client currently has opened, or one of # the consistent windows such as the main inventory. - inventory_id: varint + window_id: WindowIDVarint # Content is the new content of the inventory. The length of this slice must be equal to the full size of # the inventory window updated. input: ItemStacks diff --git a/data/latest/types.yaml b/data/latest/types.yaml index b2d8730..7d85243 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -548,7 +548,7 @@ ItemStack: # StackNetworkID is the network ID of the item stack. If the stack is empty, 0 is always written for this # field. If not, the field should be set to 1 if the server authoritative inventories are disabled in the # StartGame packet, or to a unique stack ID if it is enabled. - runtime_id: zigzag32 + stack_id: varint # Stack is the actual item stack of the item instance. item: Item @@ -577,16 +577,16 @@ PotionContainerChangeRecipes: []varint Recipes: []varint type: zigzag32 => - '0': 'shapeless' #'ENTRY_SHAPELESS', - '1': 'shaped' #'ENTRY_SHAPED', - '2': 'furnace' # 'ENTRY_FURNACE', + 0: shapeless #'ENTRY_SHAPELESS', + 1: shaped #'ENTRY_SHAPED', + 2: furnace # 'ENTRY_FURNACE', # `furnace_with_metadata` is a recipe specifically used for furnace-type crafting stations. It is equal to # `furnace`, except it has an input item with a specific metadata value, instead of any metadata value. - '3': 'furnace_with_metadata' # 'ENTRY_FURNACE_DATA', // has metadata - '4': 'multi' #'ENTRY_MULTI', //TODO - '5': 'shulker_box' #'ENTRY_SHULKER_BOX', //TODO - '6': 'shapeless_chemistry' #'ENTRY_SHAPELESS_CHEMISTRY', //TODO - '7': 'shaped_chemistry' #'ENTRY_SHAPED_CHEMISTRY', //TODO + 3: furnace_with_metadata # 'ENTRY_FURNACE_DATA', // has metadata + 4: multi #'ENTRY_MULTI', //TODO + 5: shulker_box #'ENTRY_SHULKER_BOX', //TODO + 6: shapeless_chemistry #'ENTRY_SHAPELESS_CHEMISTRY', //TODO + 7: shaped_chemistry #'ENTRY_SHAPED_CHEMISTRY', //TODO recipe: type? if shapeless or shulker_box or shapeless_chemistry: recipe_id: string @@ -595,7 +595,7 @@ Recipes: []varint uuid: uuid block: string priority: zigzag32 - network_id: zigzag32 + network_id: varint if shaped or shaped_chemistry: recipe_id: string width: zigzag32 @@ -608,7 +608,7 @@ Recipes: []varint uuid: uuid block: string priority: zigzag32 - network_id: zigzag32 + network_id: varint if furnace: input_id: zigzag32 output: Item @@ -620,7 +620,7 @@ Recipes: []varint block: string if multi: uuid: uuid - network_id: zigzag32 + network_id: varint SkinImage: width: li32 @@ -748,13 +748,20 @@ Action: zigzag32 => 22: stop_swimming 23: start_spin_attack 24: stop_spin_attack - 25: ineract_block + 25: interact_block 26: predict_break 27: continue_break +# Source and Destination point to the source slot from which Count of the item stack were taken and the +# destination slot to which this item was moved. StackRequestSlotInfo: - container_id: u8 - slot_id: u8 + # ContainerID is the ID of the container that the slot was in. + slot_type: ContainerSlotType + # Slot is the index of the slot within the container with the ContainerID above. + slot: u8 + # StackNetworkID is the unique stack ID that the client assumes to be present in this slot. The server + # must check if these IDs match. If they do not match, servers should reject the stack request that the + # action holding this info was in. stack_id: zigzag32 # ItemStackRequest is sent by the client to change item stacks in an inventory. It is essentially a @@ -764,7 +771,7 @@ StackRequestSlotInfo: ItemStackRequest: # RequestID is a unique ID for the request. This ID is used by the server to send a response for this # specific request in the ItemStackResponse packet. - request_id: zigzag32 + request_id: varint actions: []varint type_id: u8 => # TakeStackRequestAction is sent by the client to the server to take x amount of items from one slot in a @@ -872,9 +879,9 @@ ItemStackRequest: # of 1.16. recipe_network_id: varint if craft_creative: - # CreativeItemNetworkID is the network ID of the creative item that is being created. This is one of the - # creative item network IDs sent in the CreativeContent packet. - creative_item_network_id: varint32 + # The stack ID of the creative item that is being created. This is one of the + # creative item stack IDs sent in the CreativeContent packet. + item_id: varint32 if optional: # For the cartography table, if a certain MULTI recipe is being called, this points to the network ID that was assigned. recipe_network_id: varint @@ -901,30 +908,32 @@ ItemStackResponses: []varint # RequestID is the unique ID of the request that this response is in reaction to. If rejected, the client # will undo the actions from the request with this ID. request_id: varint32 - # ContainerInfo holds information on the containers that had their contents changed as a result of the - # request. - containers: []varint - # ContainerID is the container ID of the container that the slots that follow are in. For the main - # inventory, this value seems to be 0x1b. For the cursor, this value seems to be 0x3a. For the crafting - # grid, this value seems to be 0x0d. - # * actually, this is ContainerSlotType - used by the inventory system that specifies the type of slot - slot_type: ContainerSlotType - # SlotInfo holds information on what item stack should be present in specific slots in the container. - slots: []varint - # Slot and HotbarSlot seem to be the same value every time: The slot that was actually changed. I'm not - # sure if these slots ever differ. - slot: u8 - hotbar_slot: u8 - # Count is the total count of the item stack. This count will be shown client-side after the response is - # sent to the client. - count: u8 - # StackNetworkID is the network ID of the new stack at a specific slot. - item_stack_id: varint32 - # CustomName is the custom name of the item stack. It is used in relation to text filtering. - custom_name: string - # DurabilityCorrection is the current durability of the item stack. This durability will be shown - # client-side after the response is sent to the client. - durability_correction: zigzag32 + _: status ? + if ok: + # ContainerInfo holds information on the containers that had their contents changed as a result of the + # request. + containers: []varint + # ContainerID is the container ID of the container that the slots that follow are in. For the main + # inventory, this value seems to be 0x1b. For the cursor, this value seems to be 0x3a. For the crafting + # grid, this value seems to be 0x0d. + # * actually, this is ContainerSlotType - used by the inventory system that specifies the type of slot + slot_type: ContainerSlotType + # SlotInfo holds information on what item stack should be present in specific slots in the container. + slots: []varint + # Slot and HotbarSlot seem to be the same value every time: The slot that was actually changed. I'm not + # sure if these slots ever differ. + slot: u8 + hotbar_slot: u8 + # Count is the total count of the item stack. This count will be shown client-side after the response is + # sent to the client. + count: u8 + # StackNetworkID is the network ID of the new stack at a specific slot. + item_stack_id: varint32 + # CustomName is the custom name of the item stack. It is used in relation to text filtering. + custom_name: string + # DurabilityCorrection is the current durability of the item stack. This durability will be shown + # client-side after the response is sent to the client. + durability_correction: zigzag32 ItemComponentList: []varint @@ -1025,7 +1034,9 @@ WindowIDVarint: varint => 123: fixed_inventory 124: ui -WindowType: u8 => +WindowType: i8 => + -9: none + -1: inventory 0: container 1: workbench 2: furnace @@ -1061,6 +1072,7 @@ WindowType: u8 => 32: jigsaw_editor 33: smithing_table +# Used in inventory transactions. ContainerSlotType: u8 => - anvil_input - anvil_material diff --git a/examples/createRelay.js b/examples/createRelay.js index 31d8553..d3b76ad 100644 --- a/examples/createRelay.js +++ b/examples/createRelay.js @@ -32,7 +32,7 @@ function createRelay () { } }) - relay.create() + relay.listen() } createRelay() From 8663247a2aa77bd9f9648715a35acfef922fd139 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 14 Apr 2021 07:42:36 -0400 Subject: [PATCH 160/458] Lessen logging, fix JWT param --- src/auth/loginVerify.js | 7 ++++--- src/client/tokens.js | 2 +- src/datatypes/BatchPacket.js | 2 -- src/serverPlayer.js | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/auth/loginVerify.js b/src/auth/loginVerify.js index e1c2743..0809269 100644 --- a/src/auth/loginVerify.js +++ b/src/auth/loginVerify.js @@ -1,5 +1,6 @@ const JWT = require('jsonwebtoken') const constants = require('./constants') +const debug = require('debug')('minecraft-protocol') module.exports = (client, server, options) => { // Refer to the docs: @@ -19,14 +20,14 @@ module.exports = (client, server, options) => { let finalKey = null // console.log(pubKey) for (const token of chain) { - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + const decoded = JWT.verify(token, pubKey, { algorithms: ['ES384'] }) // console.log('Decoded', decoded) // Check if signed by Mojang key const x5u = getX5U(token) if (x5u === constants.PUBLIC_KEY && !data.extraData?.XUID) { // didVerify = true - console.log('verified with mojang key!', x5u) + debug('Verified client with mojang key', x5u) } // TODO: Handle `didVerify` = false @@ -41,7 +42,7 @@ module.exports = (client, server, options) => { function verifySkin (publicKey, token) { const pubKey = mcPubKeyToPem(publicKey) - const decoded = JWT.verify(token, pubKey, { algorithms: 'ES384' }) + const decoded = JWT.verify(token, pubKey, { algorithms: ['ES384'] }) return decoded } diff --git a/src/client/tokens.js b/src/client/tokens.js index af82f45..6603df9 100644 --- a/src/client/tokens.js +++ b/src/client/tokens.js @@ -244,7 +244,7 @@ class MinecraftTokenManager { const token = this.cache.mca debug('[mc] token cache', this.cache) if (!token) return - console.log('TOKEN', token) + debug('Auth token', token) const jwt = token.chain[0] const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) // eslint-disable-line diff --git a/src/datatypes/BatchPacket.js b/src/datatypes/BatchPacket.js index cdfb292..8c1094c 100644 --- a/src/datatypes/BatchPacket.js +++ b/src/datatypes/BatchPacket.js @@ -38,10 +38,8 @@ class BatchPacket { encode () { const buf = this.stream.getBuffer() - console.log('Encoding payload', buf) const def = Zlib.deflateRawSync(buf, { level: this.compressionLevel }) const ret = Buffer.concat([Buffer.from([0xfe]), def]) - console.log('Compressed', ret) return ret } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index b11d8f4..d2a6d93 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -57,7 +57,7 @@ class Player extends Connection { // TODO: disconnect user throw new Error('Failed to verify user') } - console.log('Verified user', 'got pub key', key, userData) + debug('Verified user pub key', key, userData) this.emit('login', { user: userData.extraData }) // emit events for user this.emit('server.client_handshake', { key }) // internal so we start encryption From d8ff48258c36ee59f3bb7fd2c16241cba2fc15d7 Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Wed, 14 Apr 2021 17:39:05 -0400 Subject: [PATCH 161/458] Add createClient (#61) * Initial commit * remove comment * export obj * fix export * add to api.md * fix old refs to nmp --- docs/api.md | 16 ++++++++++++ examples/createClientExample.js | 9 +++++++ index.js | 3 ++- src/createClient.js | 45 +++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 docs/api.md create mode 100644 examples/createClientExample.js create mode 100644 src/createClient.js diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..f5f6564 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,16 @@ +# Documentation + +## be.createClient(options) + +Returns a `Client` instance and starts listening. All clients will be +automatically logged in and validated against microsoft's auth. + +`options` is an object containing the properties : + * host : default to undefined which means listen to all available ipv4 and ipv6 adresses + * port (optional) : default to 25565 + (see https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback for details) + * kickTimeout (optional) : default to `10*1000` (10s), kick client that doesn't answer to keepalive after that time + * version (optional) : default to latest stable version, version of server + * autoInitPlayer (optional) : default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. + * offline (optional) : default to false, whether to auth with microsoft + * connectTimeout (optional) : default to 9000, ms to wait before aborting connection attempt diff --git a/examples/createClientExample.js b/examples/createClientExample.js new file mode 100644 index 0000000..6de4b9b --- /dev/null +++ b/examples/createClientExample.js @@ -0,0 +1,9 @@ +const { createClient } = require('bedrock-protocol') + +const client = createClient({ hostname: '127.0.0.1' }) + +let ix = 0 +client.on('packet', (args) => { + console.log(`Packet ${ix} recieved`) + ix++ +}) diff --git a/index.js b/index.js index 6169a77..d6ba9b1 100644 --- a/index.js +++ b/index.js @@ -2,5 +2,6 @@ module.exports = { ...require('./src/client'), ...require('./src/server'), ...require('./src/serverPlayer'), - ...require('./src/relay') + ...require('./src/relay'), + ...require('./src/createClient') } diff --git a/src/createClient.js b/src/createClient.js new file mode 100644 index 0000000..612fd48 --- /dev/null +++ b/src/createClient.js @@ -0,0 +1,45 @@ +const { Client } = require('./client') +const assert = require('assert') + +module.exports = { createClient } + +/** @param {{ version?: number, hostname: string, port?: number }} options */ +function createClient (options) { + assert(options && options.hostname) + const client = new Client({ port: 19132, ...options }) + + client.once('resource_packs_info', (packet) => { + handleResourcePackInfo(client) + disableClientCache(client) + handleRenderDistance(client) + handleTickSync(client) + }) + + return client +} + +function handleResourcePackInfo (client) { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) +} + +function handleRenderDistance (client) { + client.queue('request_chunk_radius', { chunk_radius: 1 }) +} + +function disableClientCache (client) { + client.queue('client_cache_status', { enabled: false }) +} + +function handleTickSync (client) { + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) +} From d3723ef42a87387afbd2131b47f60a69e62e85a9 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 16 Apr 2021 16:40:38 -0400 Subject: [PATCH 162/458] 1.16.220 support (#66) * 1.16.220 initial support * 1.16.220 fixes, electron gcm * 1.16.220 item stack fix --- data/1.16.220/protocol.json | 8315 +++++++++++++++++++++++++++ data/latest/proto.yml | 53 +- data/latest/types.yaml | 445 +- package.json | 13 +- src/connection.js | 14 +- src/datatypes/compiler-minecraft.js | 42 +- src/datatypes/minecraft.js | 26 +- src/options.js | 3 +- src/transforms/encryption.js | 53 +- test/internal.js | 10 +- test/internal.test.js | 6 +- test/vanilla.js | 5 +- tools/compileProtocol.js | 1 + tools/genPacketDumps.js | 1 + tools/startVanillaServer.js | 8 +- types/Item.js | 58 +- 16 files changed, 8920 insertions(+), 133 deletions(-) create mode 100644 data/1.16.220/protocol.json diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json new file mode 100644 index 0000000..d12afd5 --- /dev/null +++ b/data/1.16.220/protocol.json @@ -0,0 +1,8315 @@ +{ + "types": { + "varint32": "varint", + "bool": "native", + "zigzag32": "native", + "zigzag64": "native", + "uuid": "native", + "byterot": "native", + "MapInfo": "native", + "nbt": "native", + "BehaviourPackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + } + ] + ] + } + ], + "TexturePackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "rtx_enabled", + "type": "bool" + } + ] + ] + } + ], + "ResourcePackIdVersions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "ResourcePackIds": [ + "array", + { + "countType": "li16", + "type": "string" + } + ], + "Experiment": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "enabled", + "type": "bool" + } + ] + ], + "Experiments": [ + "array", + { + "countType": "li32", + "type": "Experiment" + } + ], + "GameMode": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "survival", + "1": "creative", + "2": "adventure", + "3": "survival_spectator", + "4": "creative_spectator", + "5": "fallback" + } + } + ], + "GameRule": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "bool", + "2": "int", + "3": "float" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "bool": "bool", + "int": "zigzag32", + "float": "lf32" + }, + "default": "void" + } + ] + } + ] + ], + "GameRules": [ + "array", + { + "countType": "varint", + "type": "GameRule" + } + ], + "Blob": [ + "container", + [ + { + "name": "hash", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "BlockPalette": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "state", + "type": "nbt" + } + ] + ] + } + ], + "Itemstates": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "runtime_id", + "type": "li16" + }, + { + "name": "component_based", + "type": "bool" + } + ] + ] + } + ], + "ItemExtraDataWithBlockingTick": [ + "container", + [ + { + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "false", + "65535": "true" + } + } + ] + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "true": [ + "container", + [ + { + "name": "version", + "type": "u8" + }, + { + "name": "nbt", + "type": "lnbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "blocking_tick", + "type": "li64" + } + ] + ], + "ItemExtraDataWithoutBlockingTick": [ + "container", + [ + { + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "false", + "65535": "true" + } + } + ] + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "true": [ + "container", + [ + { + "name": "version", + "type": "u8" + }, + { + "name": "nbt", + "type": "lnbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + } + ] + ], + "ItemLegacy": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "count", + "type": "lu16" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "block_runtime_id", + "type": "zigzag32" + }, + { + "name": "extra", + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "355": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithBlockingTick" + } + ] + }, + "default": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithoutBlockingTick" + } + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "Item": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "count", + "type": "lu16" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "has_stack_id", + "type": "u8" + }, + { + "name": "stack_id", + "type": [ + "switch", + { + "compareTo": "has_stack_id", + "fields": { + "0": "void" + }, + "default": "zigzag32" + } + ] + }, + { + "name": "block_runtime_id", + "type": "zigzag32" + }, + { + "name": "extra", + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "355": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithBlockingTick" + } + ] + }, + "default": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithoutBlockingTick" + } + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "vec3i": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "vec3u": [ + "container", + [ + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + } + ] + ], + "vec3f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "vec2f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "MetadataDictionary": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "key", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "flags", + "1": "health", + "2": "variant", + "3": "color", + "4": "nametag", + "5": "owner_eid", + "6": "target_eid", + "7": "air", + "8": "potion_color", + "9": "potion_ambient", + "10": "jump_duration", + "11": "hurt_time", + "12": "hurt_direction", + "13": "paddle_time_left", + "14": "paddle_time_right", + "15": "experience_value", + "16": "minecart_display_block", + "17": "minecart_display_offset", + "18": "minecart_has_display", + "20": "old_swell", + "21": "swell_dir", + "22": "charge_amount", + "23": "enderman_held_runtime_id", + "24": "entity_age", + "26": "player_flags", + "27": "player_index", + "28": "player_bed_position", + "29": "fireball_power_x", + "30": "fireball_power_y", + "31": "fireball_power_z", + "32": "aux_power", + "33": "fish_x", + "34": "fish_z", + "35": "fish_angle", + "36": "potion_aux_value", + "37": "lead_holder_eid", + "38": "scale", + "39": "interactive_tag", + "40": "npc_skin_id", + "41": "url_tag", + "42": "max_airdata_max_air", + "43": "mark_variant", + "44": "container_type", + "45": "container_base_size", + "46": "container_extra_slots_per_strength", + "47": "block_target", + "48": "wither_invulnerable_ticks", + "49": "wither_target_1", + "50": "wither_target_2", + "51": "wither_target_3", + "52": "aerial_attack", + "53": "boundingbox_width", + "54": "boundingbox_height", + "55": "fuse_length", + "56": "rider_seat_position", + "57": "rider_rotation_locked", + "58": "rider_max_rotation", + "59": "rider_min_rotation", + "60": "rider_rotation_offset", + "61": "area_effect_cloud_radius", + "62": "area_effect_cloud_waiting", + "63": "area_effect_cloud_particle_id", + "64": "shulker_peek_id", + "65": "shulker_attach_face", + "66": "shulker_attached", + "67": "shulker_attach_pos", + "68": "trading_player_eid", + "69": "trading_career", + "70": "has_command_block", + "71": "command_block_command", + "72": "command_block_last_output", + "73": "command_block_track_output", + "74": "controlling_rider_seat_number", + "75": "strength", + "76": "max_strength", + "77": "spell_casting_color", + "78": "limited_life", + "79": "armor_stand_pose_index", + "80": "ender_crystal_time_offset", + "81": "always_show_nametag", + "82": "color_2", + "83": "name_author", + "84": "score_tag", + "85": "balloon_attached_entity", + "86": "pufferfish_size", + "87": "bubble_time", + "88": "agent", + "89": "sitting_amount", + "90": "sitting_amount_previous", + "91": "eating_counter", + "92": "flags_extended", + "93": "laying_amount", + "94": "laying_amount_previous", + "95": "duration", + "96": "spawn_time", + "97": "change_rate", + "98": "change_on_pickup", + "99": "pickup_count", + "100": "interact_text", + "101": "trade_tier", + "102": "max_trade_tier", + "103": "trade_experience", + "104": "skin_id", + "105": "spawning_frames", + "106": "command_block_tick_delay", + "107": "command_block_execute_on_first_tick", + "108": "ambient_sound_interval", + "109": "ambient_sound_interval_range", + "110": "ambient_sound_event_name", + "111": "fall_damage_multiplier", + "112": "name_raw_text", + "113": "can_ride_target", + "114": "low_tier_cured_discount", + "115": "high_tier_cured_discount", + "116": "nearby_cured_discount", + "117": "nearby_cured_discount_timestamp", + "118": "hitbox", + "119": "is_buoyant", + "120": "buoyancy_data", + "121": "goat_horn_count" + } + } + ] + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "byte", + "1": "short", + "2": "int", + "3": "float", + "4": "string", + "5": "compound", + "6": "vec3i", + "7": "long", + "8": "vec3f" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "key", + "fields": { + "flags": "MetadataFlags1", + "flags_extended": "MetadataFlags2" + }, + "default": [ + "switch", + { + "compareTo": "type", + "fields": { + "byte": "i8", + "short": "li16", + "int": "zigzag32", + "float": "lf32", + "string": "string", + "compound": "nbt", + "vec3i": "vec3i", + "long": "zigzag64", + "vec3f": "vec3f" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ], + "Link": [ + "container", + [ + { + "name": "ridden_entity_id", + "type": "zigzag64" + }, + { + "name": "rider_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "immediate", + "type": "bool" + }, + { + "name": "rider_initiated", + "type": "bool" + } + ] + ], + "Links": [ + "array", + { + "countType": "varint", + "type": "Link" + } + ], + "EntityAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "min", + "type": "lf32" + }, + { + "name": "value", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + } + ] + ] + } + ], + "Rotation": [ + "container", + [ + { + "name": "yaw", + "type": "byterot" + }, + { + "name": "pitch", + "type": "byterot" + }, + { + "name": "head_yaw", + "type": "byterot" + } + ] + ], + "BlockCoordinates": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "PlayerAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "min", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + }, + { + "name": "current", + "type": "lf32" + }, + { + "name": "default", + "type": "lf32" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "TransactionUseItem": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "click_block", + "1": "click_air", + "2": "break_block" + } + } + ] + }, + { + "name": "block_position", + "type": "vec3i" + }, + { + "name": "face", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "varint" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + }, + { + "name": "block_runtime_id", + "type": "varint" + } + ] + ], + "TransactionActions": [ + "container", + [ + { + "name": "actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "source_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "container", + "1": "global", + "2": "world_interaction", + "3": "creative", + "100": "craft_slot", + "99999": "craft" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "container": [ + "container", + [ + { + "name": "inventory_id", + "type": "varint" + } + ] + ], + "craft": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "world_interaction": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "craft_slot": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + } + ] + ] + } + ] + } + ] + ], + "TransactionLegacy": [ + "container", + [ + { + "name": "legacy_request_id", + "type": "zigzag32" + }, + { + "name": "legacy_transactions", + "type": [ + "switch", + { + "compareTo": "legacy_request_id", + "fields": { + "0": "void" + }, + "default": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "changed_slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_id", + "type": "u8" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + } + ] + ], + "Transaction": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "transaction_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "inventory_mismatch", + "2": "item_use", + "3": "item_use_on_entity", + "4": "item_release" + } + } + ] + }, + { + "name": "actions", + "type": "TransactionActions" + }, + { + "name": "transaction_data", + "type": [ + "switch", + { + "compareTo": "transaction_type", + "fields": { + "normal": "void", + "inventory_mismatch": "void", + "item_use": "TransactionUseItem", + "item_use_on_entity": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "interact", + "1": "attack" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + } + ] + ], + "item_release": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "release", + "1": "consume" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "head_pos", + "type": "vec3f" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "ItemStacks": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ], + "RecipeIngredient": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "network_data", + "type": "zigzag32" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ], + "PotionTypeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "input_item_meta", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "ingredient_meta", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + }, + { + "name": "output_item_meta", + "type": "zigzag32" + } + ] + ] + } + ], + "PotionContainerChangeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + } + ] + ] + } + ], + "Recipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "shapeless", + "1": "shaped", + "2": "furnace", + "3": "furnace_with_metadata", + "4": "multi", + "5": "shulker_box", + "6": "shapeless_chemistry", + "7": "shaped_chemistry" + } + } + ] + }, + { + "name": "recipe", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "shapeless": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shulker_box": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shapeless_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shaped": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shaped_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "furnace": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "output", + "type": "ItemLegacy" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "furnace_with_metadata": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "input_meta", + "type": "zigzag32" + }, + { + "name": "output", + "type": "ItemLegacy" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "multi": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ], + "SkinImage": [ + "container", + [ + { + "name": "width", + "type": "li32" + }, + { + "name": "height", + "type": "li32" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "Skin": [ + "container", + [ + { + "name": "skin_id", + "type": "string" + }, + { + "name": "play_fab_id", + "type": "string" + }, + { + "name": "skin_resource_pack", + "type": "string" + }, + { + "name": "skin_data", + "type": "SkinImage" + }, + { + "name": "animations", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "skin_image", + "type": "SkinImage" + }, + { + "name": "animation_type", + "type": "li32" + }, + { + "name": "animation_frames", + "type": "lf32" + }, + { + "name": "expression_type", + "type": "lf32" + } + ] + ] + } + ] + }, + { + "name": "cape_data", + "type": "SkinImage" + }, + { + "name": "geometry_data", + "type": "string" + }, + { + "name": "animation_data", + "type": "string" + }, + { + "name": "premium", + "type": "string" + }, + { + "name": "persona", + "type": "bool" + }, + { + "name": "cape_on_classic", + "type": "bool" + }, + { + "name": "cape_id", + "type": "string" + }, + { + "name": "full_skin_id", + "type": "string" + }, + { + "name": "arm_size", + "type": "string" + }, + { + "name": "skin_color", + "type": "string" + }, + { + "name": "personal_pieces", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_id", + "type": "string" + }, + { + "name": "piece_type", + "type": "string" + }, + { + "name": "pack_id", + "type": "string" + }, + { + "name": "is_default_piece", + "type": "bool" + }, + { + "name": "product_id", + "type": "string" + } + ] + ] + } + ] + }, + { + "name": "piece_tint_colors", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_type", + "type": "string" + }, + { + "name": "colors", + "type": [ + "array", + { + "countType": "li32", + "type": "string" + } + ] + } + ] + ] + } + ] + } + ] + ], + "PlayerRecords": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "remove" + } + } + ] + }, + { + "name": "records_count", + "type": "varint" + }, + { + "name": "records", + "type": [ + "array", + { + "count": "records_count", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "xbox_user_id", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "build_platform", + "type": "li32" + }, + { + "name": "skin_data", + "type": "Skin" + }, + { + "name": "is_teacher", + "type": "bool" + }, + { + "name": "is_host", + "type": "bool" + } + ] + ], + "remove": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + }, + { + "name": "verified", + "type": [ + "array", + { + "count": "records_count", + "type": "bool" + } + ] + } + ] + ], + "ScoreEntries": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "change", + "1": "remove" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "remove": [ + "container", + [ + { + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": "zigzag64", + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "custom_name", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "fake_player": "string" + }, + "default": "void" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "ScoreboardIdentityEntries": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "TYPE_REGISTER_IDENTITY", + "1": "TYPE_CLEAR_IDENTITY" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "TYPE_REGISTER_IDENTITY": "zigzag64" + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "Enchant": [ + "container", + [ + { + "name": "id", + "type": "u8" + }, + { + "name": "level", + "type": "u8" + } + ] + ], + "EnchantOptions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "cost", + "type": "varint" + }, + { + "name": "slot_flags", + "type": "li32" + }, + { + "name": "equip_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "held_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "self_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "name", + "type": "string" + }, + { + "name": "option_id", + "type": "zigzag32" + } + ] + ] + } + ], + "Action": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "start_break", + "1": "abort_break", + "2": "stop_break", + "3": "get_updated_block", + "4": "drop_item", + "5": "start_sleeping", + "6": "stop_sleeping", + "7": "respawn", + "8": "jump", + "9": "start_sprint", + "10": "stop_sprint", + "11": "start_sneak", + "12": "stop_sneak", + "13": "creative_player_destroy_block", + "14": "dimension_change_ack", + "15": "start_glide", + "16": "stop_glide", + "17": "build_denied", + "18": "crack_break", + "19": "change_skin", + "20": "set_enchatnment_seed", + "21": "swimming", + "22": "stop_swimming", + "23": "start_spin_attack", + "24": "stop_spin_attack", + "25": "interact_block", + "26": "predict_break", + "27": "continue_break" + } + } + ], + "StackRequestSlotInfo": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "stack_id", + "type": "zigzag32" + } + ] + ], + "ItemStackRequest": [ + "container", + [ + { + "name": "request_id", + "type": "varint" + }, + { + "name": "actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "take", + "1": "place", + "2": "swap", + "3": "drop", + "4": "destroy", + "5": "consume", + "6": "create", + "7": "lab_table_combine", + "8": "beacon_payment", + "9": "mine_block", + "10": "craft_recipe", + "11": "craft_recipe_auto", + "12": "craft_creative", + "13": "optional", + "14": "non_implemented", + "15": "results_deprecated" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type_id", + "fields": { + "take": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "place": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "swap": [ + "container", + [ + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "drop": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "randomly", + "type": "bool" + } + ] + ], + "destroy": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "consume": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "create": [ + "container", + [ + { + "name": "result_slot_id", + "type": "u8" + } + ] + ], + "beacon_payment": [ + "container", + [ + { + "name": "primary_effect", + "type": "zigzag32" + }, + { + "name": "secondary_effect", + "type": "zigzag32" + } + ] + ], + "mine_block": [ + "container", + [ + { + "name": "unknown1", + "type": "zigzag32" + }, + { + "name": "predicted_durability", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "craft_recipe": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_recipe_auto": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_creative": [ + "container", + [ + { + "name": "item_id", + "type": "varint32" + } + ] + ], + "optional": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + }, + { + "name": "filtered_string_index", + "type": "li32" + } + ] + ], + "non_implemented": "void", + "results_deprecated": [ + "container", + [ + { + "name": "result_items", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "times_crafted", + "type": "u8" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + { + "name": "custom_names", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "ItemStackResponses": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "ok", + "1": "error" + } + } + ] + }, + { + "name": "request_id", + "type": "varint32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "status", + "fields": { + "ok": [ + "container", + [ + { + "name": "containers", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot", + "type": "u8" + }, + { + "name": "hotbar_slot", + "type": "u8" + }, + { + "name": "count", + "type": "u8" + }, + { + "name": "item_stack_id", + "type": "varint32" + }, + { + "name": "custom_name", + "type": "string" + }, + { + "name": "durability_correction", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ], + "ItemComponentList": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + } + ], + "CommandOrigin": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "player", + "1": "block", + "2": "minecart_block", + "3": "dev_console", + "4": "test", + "5": "automation_player", + "6": "client_automation", + "7": "dedicated_server", + "8": "entity", + "9": "virtual", + "10": "game_argument", + "11": "entity_server", + "12": "precompiled", + "13": "game_director_entity_server", + "14": "script" + } + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "request_id", + "type": "string" + }, + { + "name": "player_entity_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "dev_console": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ], + "test": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "WindowID": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], + "WindowIDVarint": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], + "WindowType": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "container", + "1": "workbench", + "2": "furnace", + "3": "enchantment", + "4": "brewing_stand", + "5": "anvil", + "6": "dispenser", + "7": "dropper", + "8": "hopper", + "9": "cauldron", + "10": "minecart_chest", + "11": "minecart_hopper", + "12": "horse", + "13": "beacon", + "14": "structure_editor", + "15": "trading", + "16": "command_block", + "17": "jukebox", + "18": "armor", + "19": "hand", + "20": "compound_creator", + "21": "element_constructor", + "22": "material_reducer", + "23": "lab_table", + "24": "loom", + "25": "lectern", + "26": "grindstone", + "27": "blast_furnace", + "28": "smoker", + "29": "stonecutter", + "30": "cartography", + "31": "hud", + "32": "jigsaw_editor", + "33": "smithing_table", + "-9": "none", + "-1": "inventory" + } + } + ], + "ContainerSlotType": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "anvil_input", + "1": "anvil_material", + "2": "anvil_result", + "3": "smithing_table_input", + "4": "smithing_table_material", + "5": "smithing_table_result", + "6": "armor", + "7": "container", + "8": "beacon_payment", + "9": "brewing_input", + "10": "brewing_result", + "11": "brewing_fuel", + "12": "hotbar_and_inventory", + "13": "crafting_input", + "14": "crafting_output", + "15": "recipe_construction", + "16": "recipe_nature", + "17": "recipe_items", + "18": "recipe_search", + "19": "recipe_search_bar", + "20": "recipe_equipment", + "21": "enchanting_input", + "22": "enchanting_lapis", + "23": "furnace_fuel", + "24": "furnace_ingredient", + "25": "furnace_output", + "26": "horse_equip", + "27": "hotbar", + "28": "inventory", + "29": "shulker", + "30": "trade_ingredient1", + "31": "trade_ingredient2", + "32": "trade_result", + "33": "offhand", + "34": "compcreate_input", + "35": "compcreate_output", + "36": "elemconstruct_output", + "37": "matreduce_input", + "38": "matreduce_output", + "39": "labtable_input", + "40": "loom_input", + "41": "loom_dye", + "42": "loom_material", + "43": "loom_result", + "44": "blast_furnace_ingredient", + "45": "smoker_ingredient", + "46": "trade2_ingredient1", + "47": "trade2_ingredient2", + "48": "trade2_result", + "49": "grindstone_input", + "50": "grindstone_additional", + "51": "grindstone_result", + "52": "stonecutter_input", + "53": "stonecutter_result", + "54": "cartography_input", + "55": "cartography_additional", + "56": "cartography_result", + "57": "barrel", + "58": "cursor", + "59": "creative_output" + } + } + ], + "SoundType": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "ItemUseOn", + "1": "Hit", + "2": "Step", + "3": "Fly", + "4": "Jump", + "5": "Break", + "6": "Place", + "7": "HeavyStep", + "8": "Gallop", + "9": "Fall", + "10": "Ambient", + "11": "AmbientBaby", + "12": "AmbientInWater", + "13": "Breathe", + "14": "Death", + "15": "DeathInWater", + "16": "DeathToZombie", + "17": "Hurt", + "18": "HurtInWater", + "19": "Mad", + "20": "Boost", + "21": "Bow", + "22": "SquishBig", + "23": "SquishSmall", + "24": "FallBig", + "25": "FallSmall", + "26": "Splash", + "27": "Fizz", + "28": "Flap", + "29": "Swim", + "30": "Drink", + "31": "Eat", + "32": "Takeoff", + "33": "Shake", + "34": "Plop", + "35": "Land", + "36": "Saddle", + "37": "Armor", + "38": "MobArmorStandPlace", + "39": "AddChest", + "40": "Throw", + "41": "Attack", + "42": "AttackNoDamage", + "43": "AttackStrong", + "44": "Warn", + "45": "Shear", + "46": "Milk", + "47": "Thunder", + "48": "Explode", + "49": "Fire", + "50": "Ignite", + "51": "Fuse", + "52": "Stare", + "53": "Spawn", + "54": "Shoot", + "55": "BreakBlock", + "56": "Launch", + "57": "Blast", + "58": "LargeBlast", + "59": "Twinkle", + "60": "Remedy", + "61": "Infect", + "62": "LevelUp", + "63": "BowHit", + "64": "BulletHit", + "65": "ExtinguishFire", + "66": "ItemFizz", + "67": "ChestOpen", + "68": "ChestClosed", + "69": "ShulkerBoxOpen", + "70": "ShulkerBoxClosed", + "71": "EnderChestOpen", + "72": "EnderChestClosed", + "73": "PowerOn", + "74": "PowerOff", + "75": "Attach", + "76": "Detach", + "77": "Deny", + "78": "Tripod", + "79": "Pop", + "80": "DropSlot", + "81": "Note", + "82": "Thorns", + "83": "PistonIn", + "84": "PistonOut", + "85": "Portal", + "86": "Water", + "87": "LavaPop", + "88": "Lava", + "89": "Burp", + "90": "BucketFillWater", + "91": "BucketFillLava", + "92": "BucketEmptyWater", + "93": "BucketEmptyLava", + "94": "ArmorEquipChain", + "95": "ArmorEquipDiamond", + "96": "ArmorEquipGeneric", + "97": "ArmorEquipGold", + "98": "ArmorEquipIron", + "99": "ArmorEquipLeather", + "100": "ArmorEquipElytra", + "101": "Record13", + "102": "RecordCat", + "103": "RecordBlocks", + "104": "RecordChirp", + "105": "RecordFar", + "106": "RecordMall", + "107": "RecordMellohi", + "108": "RecordStal", + "109": "RecordStrad", + "110": "RecordWard", + "111": "Record11", + "112": "RecordWait", + "113": "unknown1", + "114": "Flop", + "115": "ElderGuardianCurse", + "116": "MobWarning", + "117": "MobWarningBaby", + "118": "Teleport", + "119": "ShulkerOpen", + "120": "ShulkerClose", + "121": "Haggle", + "122": "HaggleYes", + "123": "HaggleNo", + "124": "HaggleIdle", + "125": "ChorusGrow", + "126": "ChorusDeath", + "127": "Glass", + "128": "PotionBrewed", + "129": "CastSpell", + "130": "PrepareAttack", + "131": "PrepareSummon", + "132": "PrepareWololo", + "133": "Fang", + "134": "Charge", + "135": "CameraTakePicture", + "136": "LeashKnotPlace", + "137": "LeashKnotBreak", + "138": "Growl", + "139": "Whine", + "140": "Pant", + "141": "Purr", + "142": "Purreow", + "143": "DeathMinVolume", + "144": "DeathMidVolume", + "145": "unknown2", + "146": "ImitateCaveSpider", + "147": "ImitateCreeper", + "148": "ImitateElderGuardian", + "149": "ImitateEnderDragon", + "150": "ImitateEnderman", + "151": "unknown3", + "152": "ImitateEvocationIllager", + "153": "ImitateGhast", + "154": "ImitateHusk", + "155": "ImitateIllusionIllager", + "156": "ImitateMagmaCube", + "157": "ImitatePolarBear", + "158": "ImitateShulker", + "159": "ImitateSilverfish", + "160": "ImitateSkeleton", + "161": "ImitateSlime", + "162": "ImitateSpider", + "163": "ImitateStray", + "164": "ImitateVex", + "165": "ImitateVindicationIllager", + "166": "ImitateWitch", + "167": "ImitateWither", + "168": "ImitateWitherSkeleton", + "169": "ImitateWolf", + "170": "ImitateZombie", + "171": "ImitateZombiePigman", + "172": "ImitateZombieVillager", + "173": "BlockEndPortalFrameFill", + "174": "BlockEndPortalSpawn", + "175": "RandomAnvilUse", + "176": "BottleDragonBreath", + "177": "PortalTravel", + "178": "ItemTridentHit", + "179": "ItemTridentReturn", + "180": "ItemTridentRiptide1", + "181": "ItemTridentRiptide2", + "182": "ItemTridentRiptide3", + "183": "ItemTridentThrow", + "184": "ItemTridentThunder", + "185": "ItemTridentHitGround", + "186": "Default", + "187": "BlockFletchingTableUse", + "188": "ElemConstructOpen", + "189": "IceBombHit", + "190": "BalloonPop", + "191": "LtReactionIceBomb", + "192": "LtReactionBleach", + "193": "LtReactionEPaste", + "194": "LtReactionEPaste2", + "195": "LtReactionFertilizer", + "196": "LtReactionFireball", + "197": "LtReactionMgsalt", + "198": "LtReactionMiscfire", + "199": "LtReactionFire", + "200": "LtReactionMiscexplosion", + "201": "LtReactionMiscmystical", + "202": "LtReactionMiscmystical2", + "203": "LtReactionProduct", + "204": "SparklerUse", + "205": "GlowstickUse", + "206": "SparklerActive", + "207": "ConvertToDrowned", + "208": "BucketFillFish", + "209": "BucketEmptyFish", + "210": "BubbleUp", + "211": "BubbleDown", + "212": "BubblePop", + "213": "BubbleUpInside", + "214": "BubbleDownInside", + "215": "HurtBaby", + "216": "DeathBaby", + "217": "StepBaby", + "218": "BabySpawn", + "219": "Born", + "220": "BlockTurtleEggBreak", + "221": "BlockTurtleEggCrack", + "222": "BlockTurtleEggHatch", + "223": "TurtleLayEgg", + "224": "BlockTurtleEggAttack", + "225": "BeaconActivate", + "226": "BeaconAmbient", + "227": "BeaconDeactivate", + "228": "BeaconPower", + "229": "ConduitActivate", + "230": "ConduitAmbient", + "231": "ConduitAttack", + "232": "ConduitDeactivate", + "233": "ConduitShort", + "234": "Swoop", + "235": "BlockBambooSaplingPlace", + "236": "PreSneeze", + "237": "Sneeze", + "238": "AmbientTame", + "239": "Scared", + "240": "BlockScaffoldingClimb", + "241": "CrossbowLoadingStart", + "242": "CrossbowLoadingMiddle", + "243": "CrossbowLoadingEnd", + "244": "CrossbowShoot", + "245": "CrossbowQuickChargeStart", + "246": "CrossbowQuickChargeMiddle", + "247": "CrossbowQuickChargeEnd", + "248": "AmbientAggressive", + "249": "AmbientWorried", + "250": "CantBreed", + "251": "ItemShieldBlock", + "252": "ItemBookPut", + "253": "BlockGrindstoneUse", + "254": "BlockBellHit", + "255": "BlockCampfireCrackle", + "256": "Roar", + "257": "Stun", + "258": "BlockSweetBerryBushHurt", + "259": "BlockSweetBerryBushPick", + "260": "UICartographyTableTakeResult", + "261": "UIStoneCutterTakeResult", + "262": "BlockComposterEmpty", + "263": "BlockComposterFill", + "264": "BlockComposterFillSuccess", + "265": "BlockComposterReady", + "266": "BlockBarrelOpen", + "267": "BlockBarrelClose", + "268": "RaidHorn", + "269": "BlockLoomUse", + "270": "AmbientRaid", + "271": "UICartographyTableUse", + "272": "UIStoneCutterUse", + "273": "UILoomUse", + "274": "SmokerUse", + "275": "BlastFurnaceUse", + "276": "SmithingTableUse", + "277": "Screech", + "278": "Sleep", + "279": "FurnaceUse", + "280": "MooshroomConvert", + "281": "MilkSuspiciously", + "282": "Celebrate", + "283": "JumpPrevent", + "284": "AmbientPollinate", + "285": "BeeHiveDrip", + "286": "BeeHiveEnter", + "287": "BeeHiveExit", + "288": "BeeHiveWork", + "289": "BeeHiveShear", + "290": "HoneyBottleDrink", + "291": "AmbientCave", + "292": "Retreat", + "293": "ConvertToZombified", + "294": "Admire", + "295": "StepLava", + "296": "Tempt", + "297": "Panic", + "298": "Angry", + "299": "AmbientWarpedForest", + "300": "AmbientSoulsandValley", + "301": "AmbientNetherWastes", + "302": "AmbientBasaltDeltas", + "303": "AmbientCrimsonForest", + "304": "RespawnAnchorCharge", + "305": "RespawnAnchorDeplete", + "306": "RespawnAnchorSetSpawn", + "307": "RespawnAnchorAmbient", + "308": "SoulEscapeQuiet", + "309": "SoulEscapeLoud", + "310": "RecordPigstep", + "311": "LinkCompassToLodestone", + "312": "BlockSmithingTableUse", + "313": "EquipNetherite", + "314": "AmbientLoopWarpedForest", + "315": "AmbientLoopSoulsandValley", + "316": "AmbientLoopNetherWastes", + "317": "AmbientLoopBasaltDeltas", + "318": "AmbientLoopCrimsonForest", + "319": "AmbientAdditionWarpedForest", + "320": "AmbientAdditionSoulsandValley", + "321": "AmbientAdditionNetherWastes", + "322": "AmbientAdditionBasaltDeltas", + "323": "AmbientAdditionCrimsonForest", + "324": "SculkSensorPowerOn", + "325": "SculkSensorPowerOff", + "326": "BucketFillPowderSnow", + "327": "BucketEmptyPowderSnow", + "328": "PointedDripstoneCauldronDripWater", + "329": "PointedDripstoneCauldronDripLava", + "330": "PointedDripstoneDripWater", + "331": "PointedDripstoneDripLava", + "332": "CaveVinesPickBerries", + "333": "BigDripleafTiltDown", + "334": "BigDripleafTiltUp", + "335": "Undefined" + } + } + ], + "LegacyEntityType": [ + "mapper", + { + "type": "li32", + "mappings": { + "10": "chicken", + "11": "cow", + "12": "pig", + "13": "sheep", + "14": "wolf", + "15": "villager", + "16": "mooshroom", + "17": "squid", + "18": "rabbit", + "19": "bat", + "20": "iron_golem", + "21": "snow_golem", + "22": "ocelot", + "23": "horse", + "24": "donkey", + "25": "mule", + "26": "skeleton_horse", + "27": "zombie_horse", + "28": "polar_bear", + "29": "llama", + "30": "parrot", + "31": "dolphin", + "32": "zombie", + "33": "creeper", + "34": "skeleton", + "35": "spider", + "36": "zombie_pigman", + "37": "slime", + "38": "enderman", + "39": "silverfish", + "40": "cave_spider", + "41": "ghast", + "42": "magma_cube", + "43": "blaze", + "44": "zombie_villager", + "45": "witch", + "46": "stray", + "47": "husk", + "48": "wither_skeleton", + "49": "guardian", + "50": "elder_guardian", + "51": "npc", + "52": "wither", + "53": "ender_dragon", + "54": "shulker", + "55": "endermite", + "56": "agent", + "57": "vindicator", + "58": "phantom", + "61": "armor_stand", + "62": "tripod_camera", + "63": "player", + "64": "item", + "65": "tnt", + "66": "falling_block", + "67": "moving_block", + "68": "xp_bottle", + "69": "xp_orb", + "70": "eye_of_ender_signal", + "71": "ender_crystal", + "72": "fireworks_rocket", + "73": "thrown_trident", + "74": "turtle", + "75": "cat", + "76": "shulker_bullet", + "77": "fishing_hook", + "78": "chalkboard", + "79": "dragon_fireball", + "80": "arrow", + "81": "snowball", + "82": "egg", + "83": "painting", + "84": "minecart", + "85": "fireball", + "86": "splash_potion", + "87": "ender_pearl", + "88": "leash_knot", + "89": "wither_skull", + "90": "boat", + "91": "wither_skull_dangerous", + "93": "lightning_bolt", + "94": "small_fireball", + "95": "area_effect_cloud", + "96": "hopper_minecart", + "97": "tnt_minecart", + "98": "chest_minecart", + "100": "command_block_minecart", + "101": "lingering_potion", + "102": "llama_spit", + "103": "evocation_fang", + "104": "evocation_illager", + "105": "vex", + "106": "ice_bomb", + "107": "balloon", + "108": "pufferfish", + "109": "salmon", + "110": "drowned", + "111": "tropicalfish", + "112": "cod", + "113": "panda" + } + } + ], + "mcpe_packet": [ + "container", + [ + { + "name": "name", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "login", + "2": "play_status", + "3": "server_to_client_handshake", + "4": "client_to_server_handshake", + "5": "disconnect", + "6": "resource_packs_info", + "7": "resource_pack_stack", + "8": "resource_pack_client_response", + "9": "text", + "10": "set_time", + "11": "start_game", + "12": "add_player", + "13": "add_entity", + "14": "remove_entity", + "15": "add_item_entity", + "17": "take_item_entity", + "18": "move_entity", + "19": "move_player", + "20": "rider_jump", + "21": "update_block", + "22": "add_painting", + "23": "tick_sync", + "24": "level_sound_event_old", + "25": "level_event", + "26": "block_event", + "27": "entity_event", + "28": "mob_effect", + "29": "update_attributes", + "30": "inventory_transaction", + "31": "mob_equipment", + "32": "mob_armor_equipment", + "33": "interact", + "34": "block_pick_request", + "35": "entity_pick_request", + "36": "player_action", + "38": "hurt_armor", + "39": "set_entity_data", + "40": "set_entity_motion", + "41": "set_entity_link", + "42": "set_health", + "43": "set_spawn_position", + "44": "animate", + "45": "respawn", + "46": "container_open", + "47": "container_close", + "48": "player_hotbar", + "49": "inventory_content", + "50": "inventory_slot", + "51": "container_set_data", + "52": "crafting_data", + "53": "crafting_event", + "54": "gui_data_pick_item", + "55": "adventure_settings", + "56": "block_entity_data", + "57": "player_input", + "58": "level_chunk", + "59": "set_commands_enabled", + "60": "set_difficulty", + "61": "change_dimension", + "62": "set_player_game_type", + "63": "player_list", + "64": "simple_event", + "65": "event", + "66": "spawn_experience_orb", + "67": "clientbound_map_item_data", + "68": "map_info_request", + "69": "request_chunk_radius", + "70": "chunk_radius_update", + "71": "item_frame_drop_item", + "72": "game_rules_changed", + "73": "camera", + "74": "boss_event", + "75": "show_credits", + "76": "available_commands", + "77": "command_request", + "78": "command_block_update", + "79": "command_output", + "80": "update_trade", + "81": "update_equipment", + "82": "resource_pack_data_info", + "83": "resource_pack_chunk_data", + "84": "resource_pack_chunk_request", + "85": "transfer", + "86": "play_sound", + "87": "stop_sound", + "88": "set_title", + "89": "add_behavior_tree", + "90": "structure_block_update", + "91": "show_store_offer", + "92": "purchase_receipt", + "93": "player_skin", + "94": "sub_client_login", + "95": "initiate_web_socket_connection", + "96": "set_last_hurt_by", + "97": "book_edit", + "98": "npc_request", + "99": "photo_transfer", + "100": "modal_form_request", + "101": "modal_form_response", + "102": "server_settings_request", + "103": "server_settings_response", + "104": "show_profile", + "105": "set_default_game_type", + "106": "remove_objective", + "107": "set_display_objective", + "108": "set_score", + "109": "lab_table", + "110": "update_block_synced", + "111": "move_entity_delta", + "112": "set_scoreboard_identity", + "113": "set_local_player_as_initialized", + "114": "update_soft_enum", + "115": "network_stack_latency", + "117": "script_custom_event", + "118": "spawn_particle_effect", + "119": "available_entity_identifiers", + "120": "level_sound_event_v2", + "121": "network_chunk_publisher_update", + "122": "biome_definition_list", + "123": "level_sound_event", + "124": "level_event_generic", + "125": "lectern_update", + "126": "video_stream_connect", + "127": "add_ecs_entity", + "128": "remove_ecs_entity", + "129": "client_cache_status", + "130": "on_screen_texture_animation", + "131": "map_create_locked_copy", + "132": "structure_template_data_export_request", + "133": "structure_template_data_export_response", + "134": "update_block_properties", + "135": "client_cache_blob_status", + "136": "client_cache_miss_response", + "137": "education_settings", + "139": "multiplayer_settings", + "140": "settings_command", + "141": "anvil_damage", + "142": "completed_using_item", + "143": "network_settings", + "144": "player_auth_input", + "145": "creative_content", + "146": "player_enchant_options", + "147": "item_stack_request", + "148": "item_stack_response", + "149": "player_armor_damage", + "151": "update_player_game_type", + "153": "position_tracking_db_broadcast", + "154": "position_tracking_db_request", + "156": "packet_violation_warning", + "157": "motion_prediction_hints", + "158": "animate_entity", + "159": "camera_shake", + "160": "player_fog", + "161": "correct_player_move_prediction", + "162": "item_component", + "163": "filter_text_packet", + "164": "debug_renderer" + } + } + ] + }, + { + "name": "params", + "type": [ + "switch", + { + "compareTo": "name", + "fields": { + "login": "packet_login", + "play_status": "packet_play_status", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", + "disconnect": "packet_disconnect", + "resource_packs_info": "packet_resource_packs_info", + "resource_pack_stack": "packet_resource_pack_stack", + "resource_pack_client_response": "packet_resource_pack_client_response", + "text": "packet_text", + "set_time": "packet_set_time", + "start_game": "packet_start_game", + "add_player": "packet_add_player", + "add_entity": "packet_add_entity", + "remove_entity": "packet_remove_entity", + "add_item_entity": "packet_add_item_entity", + "take_item_entity": "packet_take_item_entity", + "move_entity": "packet_move_entity", + "move_player": "packet_move_player", + "rider_jump": "packet_rider_jump", + "update_block": "packet_update_block", + "add_painting": "packet_add_painting", + "tick_sync": "packet_tick_sync", + "level_sound_event_old": "packet_level_sound_event_old", + "level_event": "packet_level_event", + "block_event": "packet_block_event", + "entity_event": "packet_entity_event", + "mob_effect": "packet_mob_effect", + "update_attributes": "packet_update_attributes", + "inventory_transaction": "packet_inventory_transaction", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", + "interact": "packet_interact", + "block_pick_request": "packet_block_pick_request", + "entity_pick_request": "packet_entity_pick_request", + "player_action": "packet_player_action", + "hurt_armor": "packet_hurt_armor", + "set_entity_data": "packet_set_entity_data", + "set_entity_motion": "packet_set_entity_motion", + "set_entity_link": "packet_set_entity_link", + "set_health": "packet_set_health", + "set_spawn_position": "packet_set_spawn_position", + "animate": "packet_animate", + "respawn": "packet_respawn", + "container_open": "packet_container_open", + "container_close": "packet_container_close", + "player_hotbar": "packet_player_hotbar", + "inventory_content": "packet_inventory_content", + "inventory_slot": "packet_inventory_slot", + "container_set_data": "packet_container_set_data", + "crafting_data": "packet_crafting_data", + "crafting_event": "packet_crafting_event", + "gui_data_pick_item": "packet_gui_data_pick_item", + "adventure_settings": "packet_adventure_settings", + "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", + "level_chunk": "packet_level_chunk", + "set_commands_enabled": "packet_set_commands_enabled", + "set_difficulty": "packet_set_difficulty", + "change_dimension": "packet_change_dimension", + "set_player_game_type": "packet_set_player_game_type", + "player_list": "packet_player_list", + "simple_event": "packet_simple_event", + "event": "packet_event", + "spawn_experience_orb": "packet_spawn_experience_orb", + "clientbound_map_item_data": "packet_clientbound_map_item_data", + "map_info_request": "packet_map_info_request", + "request_chunk_radius": "packet_request_chunk_radius", + "chunk_radius_update": "packet_chunk_radius_update", + "item_frame_drop_item": "packet_item_frame_drop_item", + "game_rules_changed": "packet_game_rules_changed", + "camera": "packet_camera", + "boss_event": "packet_boss_event", + "show_credits": "packet_show_credits", + "available_commands": "packet_available_commands", + "command_request": "packet_command_request", + "command_block_update": "packet_command_block_update", + "command_output": "packet_command_output", + "update_trade": "packet_update_trade", + "update_equipment": "packet_update_equipment", + "resource_pack_data_info": "packet_resource_pack_data_info", + "resource_pack_chunk_data": "packet_resource_pack_chunk_data", + "resource_pack_chunk_request": "packet_resource_pack_chunk_request", + "transfer": "packet_transfer", + "play_sound": "packet_play_sound", + "stop_sound": "packet_stop_sound", + "set_title": "packet_set_title", + "add_behavior_tree": "packet_add_behavior_tree", + "structure_block_update": "packet_structure_block_update", + "show_store_offer": "packet_show_store_offer", + "purchase_receipt": "packet_purchase_receipt", + "player_skin": "packet_player_skin", + "sub_client_login": "packet_sub_client_login", + "initiate_web_socket_connection": "packet_initiate_web_socket_connection", + "set_last_hurt_by": "packet_set_last_hurt_by", + "book_edit": "packet_book_edit", + "npc_request": "packet_npc_request", + "photo_transfer": "packet_photo_transfer", + "modal_form_request": "packet_modal_form_request", + "modal_form_response": "packet_modal_form_response", + "server_settings_request": "packet_server_settings_request", + "server_settings_response": "packet_server_settings_response", + "show_profile": "packet_show_profile", + "set_default_game_type": "packet_set_default_game_type", + "remove_objective": "packet_remove_objective", + "set_display_objective": "packet_set_display_objective", + "set_score": "packet_set_score", + "lab_table": "packet_lab_table", + "update_block_synced": "packet_update_block_synced", + "move_entity_delta": "packet_move_entity_delta", + "set_scoreboard_identity": "packet_set_scoreboard_identity", + "set_local_player_as_initialized": "packet_set_local_player_as_initialized", + "update_soft_enum": "packet_update_soft_enum", + "network_stack_latency": "packet_network_stack_latency", + "script_custom_event": "packet_script_custom_event", + "spawn_particle_effect": "packet_spawn_particle_effect", + "available_entity_identifiers": "packet_available_entity_identifiers", + "level_sound_event_v2": "packet_level_sound_event_v2", + "network_chunk_publisher_update": "packet_network_chunk_publisher_update", + "biome_definition_list": "packet_biome_definition_list", + "level_sound_event": "packet_level_sound_event", + "level_event_generic": "packet_level_event_generic", + "lectern_update": "packet_lectern_update", + "video_stream_connect": "packet_video_stream_connect", + "add_ecs_entity": "packet_add_ecs_entity", + "remove_ecs_entity": "packet_remove_ecs_entity", + "client_cache_status": "packet_client_cache_status", + "on_screen_texture_animation": "packet_on_screen_texture_animation", + "map_create_locked_copy": "packet_map_create_locked_copy", + "structure_template_data_export_request": "packet_structure_template_data_export_request", + "structure_template_data_export_response": "packet_structure_template_data_export_response", + "update_block_properties": "packet_update_block_properties", + "client_cache_blob_status": "packet_client_cache_blob_status", + "client_cache_miss_response": "packet_client_cache_miss_response", + "education_settings": "packet_education_settings", + "multiplayer_settings": "packet_multiplayer_settings", + "settings_command": "packet_settings_command", + "anvil_damage": "packet_anvil_damage", + "completed_using_item": "packet_completed_using_item", + "network_settings": "packet_network_settings", + "player_auth_input": "packet_player_auth_input", + "creative_content": "packet_creative_content", + "player_enchant_options": "packet_player_enchant_options", + "item_stack_request": "packet_item_stack_request", + "item_stack_response": "packet_item_stack_response", + "player_armor_damage": "packet_player_armor_damage", + "update_player_game_type": "packet_update_player_game_type", + "position_tracking_db_request": "packet_position_tracking_db_request", + "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", + "packet_violation_warning": "packet_packet_violation_warning", + "motion_prediction_hints": "packet_motion_prediction_hints", + "animate_entity": "packet_animate_entity", + "camera_shake": "packet_camera_shake", + "player_fog": "packet_player_fog", + "correct_player_move_prediction": "packet_correct_player_move_prediction", + "item_component": "packet_item_component", + "filter_text_packet": "packet_filter_text_packet", + "debug_renderer": "packet_debug_renderer" + }, + "default": "void" + } + ] + } + ] + ], + "packet_login": [ + "container", + [ + { + "name": "protocol_version", + "type": "i32" + }, + { + "name": "payload_size", + "type": "varint" + }, + { + "name": "chain", + "type": "LittleString" + }, + { + "name": "client_data", + "type": "LittleString" + } + ] + ], + "packet_play_status": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "i32", + "mappings": { + "0": "login_success", + "1": "failed_client", + "2": "failed_spawn", + "3": "player_spawn", + "4": "failed_invalid_tenant", + "5": "failed_vanilla_edu", + "6": "failed_edu_vanilla", + "7": "failed_server_full" + } + } + ] + } + ] + ], + "packet_server_to_client_handshake": [ + "container", + [ + { + "name": "token", + "type": "string" + } + ] + ], + "packet_client_to_server_handshake": [ + "container", + [] + ], + "packet_disconnect": [ + "container", + [ + { + "name": "hide_disconnect_reason", + "type": "bool" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "packet_resource_packs_info": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "behaviour_packs", + "type": "BehaviourPackInfos" + }, + { + "name": "texture_packs", + "type": "TexturePackInfos" + } + ] + ], + "packet_resource_pack_stack": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behavior_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "resource_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + } + ] + ], + "packet_resource_pack_client_response": [ + "container", + [ + { + "name": "response_status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "refused", + "2": "send_packs", + "3": "have_all_packs", + "4": "completed" + } + } + ] + }, + { + "name": "resourcepackids", + "type": "ResourcePackIds" + } + ] + ], + "packet_text": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "raw", + "1": "chat", + "2": "translation", + "3": "popup", + "4": "jukebox_popup", + "5": "tip", + "6": "system", + "7": "whisper", + "8": "announcement", + "9": "json_whisper", + "10": "json" + } + } + ] + }, + { + "name": "needs_translation", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "chat": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "whisper": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "announcement": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "raw": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "tip": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "system": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json_whisper": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "translation": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "jukebox_popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "xuid", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + } + ] + ], + "packet_set_time": [ + "container", + [ + { + "name": "time", + "type": "zigzag32" + } + ] + ], + "packet_start_game": [ + "container", + [ + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "player_gamemode", + "type": "GameMode" + }, + { + "name": "player_position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "vec2f" + }, + { + "name": "seed", + "type": "zigzag32" + }, + { + "name": "biome_type", + "type": "li16" + }, + { + "name": "biome_name", + "type": "string" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "generator", + "type": "zigzag32" + }, + { + "name": "world_gamemode", + "type": "GameMode" + }, + { + "name": "difficulty", + "type": "zigzag32" + }, + { + "name": "spawn_position", + "type": "BlockCoordinates" + }, + { + "name": "achievements_disabled", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", + "type": "zigzag32" + }, + { + "name": "edu_offer", + "type": "zigzag32" + }, + { + "name": "edu_features_enabled", + "type": "bool" + }, + { + "name": "edu_product_uuid", + "type": "string" + }, + { + "name": "rain_level", + "type": "lf32" + }, + { + "name": "lightning_level", + "type": "lf32" + }, + { + "name": "has_confirmed_platform_locked_content", + "type": "bool" + }, + { + "name": "is_multiplayer", + "type": "bool" + }, + { + "name": "broadcast_to_lan", + "type": "bool" + }, + { + "name": "xbox_live_broadcast_mode", + "type": "varint" + }, + { + "name": "platform_broadcast_mode", + "type": "varint" + }, + { + "name": "enable_commands", + "type": "bool" + }, + { + "name": "is_texturepacks_required", + "type": "bool" + }, + { + "name": "gamerules", + "type": "GameRules" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + }, + { + "name": "bonus_chest", + "type": "bool" + }, + { + "name": "map_enabled", + "type": "bool" + }, + { + "name": "permission_level", + "type": "zigzag32" + }, + { + "name": "server_chunk_tick_range", + "type": "li32" + }, + { + "name": "has_locked_behavior_pack", + "type": "bool" + }, + { + "name": "has_locked_resource_pack", + "type": "bool" + }, + { + "name": "is_from_locked_world_template", + "type": "bool" + }, + { + "name": "msa_gamertags_only", + "type": "bool" + }, + { + "name": "is_from_world_template", + "type": "bool" + }, + { + "name": "is_world_template_option_locked", + "type": "bool" + }, + { + "name": "only_spawn_v1_villagers", + "type": "bool" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "limited_world_width", + "type": "li32" + }, + { + "name": "limited_world_length", + "type": "li32" + }, + { + "name": "is_new_nether", + "type": "bool" + }, + { + "name": "experimental_gameplay_override", + "type": "bool" + }, + { + "name": "level_id", + "type": "string" + }, + { + "name": "world_name", + "type": "string" + }, + { + "name": "premium_world_template_id", + "type": "string" + }, + { + "name": "is_trial", + "type": "bool" + }, + { + "name": "movement_authority", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "client", + "1": "server", + "2": "server_with_rewind" + } + } + ] + }, + { + "name": "rewind_history_size", + "type": "zigzag32" + }, + { + "name": "server_authoritative_block_breaking", + "type": "bool" + }, + { + "name": "current_tick", + "type": "li64" + }, + { + "name": "enchantment_seed", + "type": "zigzag32" + }, + { + "name": "block_palette", + "type": "BlockPalette" + }, + { + "name": "itemstates", + "type": "Itemstates" + }, + { + "name": "multiplayer_correlation_id", + "type": "string" + }, + { + "name": "server_authoritative_inventory", + "type": "bool" + } + ] + ], + "packet_add_player": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "flags", + "type": "varint" + }, + { + "name": "command_permission", + "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + }, + { + "name": "links", + "type": "Links" + }, + { + "name": "device_id", + "type": "string" + }, + { + "name": "device_os", + "type": "li32" + } + ] + ], + "packet_add_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "attributes", + "type": "EntityAttributes" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "links", + "type": "Links" + } + ] + ], + "packet_remove_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + } + ] + ], + "packet_add_item_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "speed_x", + "type": "lf32" + }, + { + "name": "speed_y", + "type": "lf32" + }, + { + "name": "speed_z", + "type": "lf32" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "is_from_fishing", + "type": "bool" + } + ] + ], + "packet_take_item_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "target", + "type": "varint" + } + ] + ], + "packet_move_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "Rotation" + } + ] + ], + "packet_move_player": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "mode", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "normal", + "1": "reset", + "2": "teleport", + "3": "rotation" + } + } + ] + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "ridden_runtime_id", + "type": "varint" + }, + { + "name": "teleport", + "type": [ + "switch", + { + "compareTo": "mode", + "fields": { + "teleport": [ + "container", + [ + { + "name": "cause", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "unknown", + "1": "projectile", + "2": "chorus_fruit", + "3": "command", + "4": "behavior" + } + } + ] + }, + { + "name": "source_entity_type", + "type": "LegacyEntityType" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_rider_jump": [ + "container", + [ + { + "name": "jump_strength", + "type": "zigzag32" + } + ] + ], + "packet_update_block": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + } + ] + ], + "packet_add_painting": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "direction", + "type": "zigzag32" + }, + { + "name": "title", + "type": "string" + } + ] + ], + "packet_tick_sync": [ + "container", + [ + { + "name": "request_time", + "type": "li64" + }, + { + "name": "response_time", + "type": "li64" + } + ] + ], + "packet_level_sound_event_old": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "zigzag32" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event": [ + "container", + [ + { + "name": "event", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "1000": "sound_click", + "1001": "sound_click_fail", + "1002": "sound_shoot", + "1003": "sound_door", + "1004": "sound_fizz", + "1005": "sound_ignite", + "1007": "sound_ghast", + "1008": "sound_ghast_shoot", + "1009": "sound_blaze_shoot", + "1010": "sound_door_bump", + "1012": "sound_door_crash", + "1018": "sound_enderman_teleport", + "1020": "sound_anvil_break", + "1021": "sound_anvil_use", + "1022": "sound_anvil_fall", + "1030": "sound_pop", + "1032": "sound_portal", + "1040": "sound_itemframe_add_item", + "1041": "sound_itemframe_remove", + "1042": "sound_itemframe_place", + "1043": "sound_itemframe_remove_item", + "1044": "sound_itemframe_rotate_item", + "1050": "sound_camera", + "1051": "sound_orb", + "1052": "sound_totem", + "1060": "sound_armor_stand_break", + "1061": "sound_armor_stand_hit", + "1062": "sound_armor_stand_fall", + "1063": "sound_armor_stand_place", + "1064": "pointed_dripstone_land", + "1065": "dye_used", + "1066": "ink_sack_used", + "2000": "particle_shoot", + "2001": "particle_destroy", + "2002": "particle_splash", + "2003": "particle_eye_despawn", + "2004": "particle_spawn", + "2005": "particle_crop_growth", + "2006": "particle_guardian_curse", + "2007": "particle_death_smoke", + "2008": "particle_block_force_field", + "2009": "particle_projectile_hit", + "2010": "particle_dragon_egg_teleport", + "2011": "particle_crop_eaten", + "2012": "particle_critical", + "2013": "particle_enderman_teleport", + "2014": "particle_punch_block", + "2015": "particle_bubble", + "2016": "particle_evaporate", + "2017": "particle_destroy_armor_stand", + "2018": "particle_breaking_egg", + "2019": "particle_destroy_egg", + "2020": "particle_evaporate_water", + "2021": "particle_destroy_block_no_sound", + "2022": "particle_knockback_roar", + "2023": "particle_teleport_trail", + "2024": "particle_point_cloud", + "2025": "particle_explosion", + "2026": "particle_block_explosion", + "2027": "particle_vibration_signal", + "2028": "particle_dripstone_drip", + "2029": "particle_fizz_effect", + "2030": "particle_wax_on", + "2031": "particle_wax_off", + "2032": "particle_scrape", + "2033": "particle_electric_spark", + "3001": "start_rain", + "3002": "start_thunder", + "3003": "stop_rain", + "3004": "stop_thunder", + "3005": "pause_game", + "3006": "pause_game_no_screen", + "3007": "set_game_speed", + "3500": "redstone_trigger", + "3501": "cauldron_explode", + "3502": "cauldron_dye_armor", + "3503": "cauldron_clean_armor", + "3504": "cauldron_fill_potion", + "3505": "cauldron_take_potion", + "3506": "cauldron_fill_water", + "3507": "cauldron_take_water", + "3508": "cauldron_add_dye", + "3509": "cauldron_clean_banner", + "3600": "block_start_break", + "3601": "block_stop_break", + "4000": "set_data", + "9800": "players_sleeping", + "16384": "add_particle_mask" + } + } + ] + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_block_event": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "sound", + "1": "change_state" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_entity_event": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "event_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "jump", + "2": "hurt_animation", + "3": "death_animation", + "4": "arm_swing", + "5": "stop_attack", + "6": "tame_fail", + "7": "tame_success", + "8": "shake_wet", + "9": "use_item", + "10": "eat_grass_animation", + "11": "fish_hook_bubble", + "12": "fish_hook_position", + "13": "fish_hook_hook", + "14": "fish_hook_tease", + "15": "squid_ink_cloud", + "16": "zombie_villager_cure", + "18": "respawn", + "19": "iron_golem_offer_flower", + "20": "iron_golem_withdraw_flower", + "21": "love_particles", + "22": "villager_angry", + "23": "villager_happy", + "24": "witch_spell_particles", + "25": "firework_particles", + "26": "in_love_particles", + "27": "silverfish_spawn_animation", + "28": "guardian_attack", + "29": "witch_drink_potion", + "30": "witch_throw_potion", + "31": "minecart_tnt_prime_fuse", + "32": "creeper_prime_fuse", + "33": "air_supply_expired", + "34": "player_add_xp_levels", + "35": "elder_guardian_curse", + "36": "agent_arm_swing", + "37": "ender_dragon_death", + "38": "dust_particles", + "39": "arrow_shake", + "57": "eating_item", + "60": "baby_animal_feed", + "61": "death_smoke_cloud", + "62": "complete_trade", + "63": "remove_leash", + "65": "consume_totem", + "66": "player_check_treasure_hunter_achievement", + "67": "entity_spawn", + "68": "dragon_puke", + "69": "item_entity_merge", + "70": "start_swim", + "71": "balloon_pop", + "72": "treasure_hunt", + "73": "agent_summon", + "74": "charged_crossbow", + "75": "fall" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_mob_effect": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "effect_id", + "type": "zigzag32" + }, + { + "name": "amplifier", + "type": "zigzag32" + }, + { + "name": "particles", + "type": "bool" + }, + { + "name": "duration", + "type": "zigzag32" + } + ] + ], + "packet_update_attributes": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "attributes", + "type": "PlayerAttributes" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_inventory_transaction": [ + "container", + [ + { + "name": "transaction", + "type": "Transaction" + } + ] + ], + "packet_mob_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "selected_slot", + "type": "u8" + }, + { + "name": "window_id", + "type": "WindowID" + } + ] + ], + "packet_mob_armor_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "helmet", + "type": "Item" + }, + { + "name": "chestplate", + "type": "Item" + }, + { + "name": "leggings", + "type": "Item" + }, + { + "name": "boots", + "type": "Item" + } + ] + ], + "packet_interact": [ + "container", + [ + { + "name": "action_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "3": "leave_vehicle", + "4": "mouse_over_entity", + "6": "open_inventory" + } + } + ] + }, + { + "name": "target_entity_id", + "type": "varint64" + }, + { + "name": "position", + "type": [ + "switch", + { + "compareTo": "action_id", + "fields": { + "mouse_over_entity": "vec3f", + "leave_vehicle": "vec3f" + }, + "default": "void" + } + ] + } + ] + ], + "packet_block_pick_request": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "add_user_data", + "type": "bool" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_entity_pick_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "lu64" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_player_action": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "action", + "type": "Action" + }, + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "packet_hurt_armor": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_entity_data": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "tick", + "type": "varint" + } + ] + ], + "packet_set_entity_motion": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + } + ] + ], + "packet_set_entity_link": [ + "container", + [ + { + "name": "link", + "type": "Link" + } + ] + ], + "packet_set_health": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_spawn_position": [ + "container", + [ + { + "name": "spawn_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "player", + "1": "world" + } + } + ] + }, + { + "name": "player_position", + "type": "BlockCoordinates" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "world_position", + "type": "BlockCoordinates" + } + ] + ], + "packet_animate": [ + "container", + [ + { + "name": "action_id", + "type": "zigzag32" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_respawn": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + }, + { + "name": "state", + "type": "u8" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_container_open": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "runtime_entity_id", + "type": "zigzag64" + } + ] + ], + "packet_container_close": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "server", + "type": "bool" + } + ] + ], + "packet_player_hotbar": [ + "container", + [ + { + "name": "selected_slot", + "type": "varint" + }, + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "select_slot", + "type": "bool" + } + ] + ], + "packet_inventory_content": [ + "container", + [ + { + "name": "window_id", + "type": "WindowIDVarint" + }, + { + "name": "input", + "type": "ItemStacks" + } + ] + ], + "packet_inventory_slot": [ + "container", + [ + { + "name": "window_id", + "type": "WindowIDVarint" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "item", + "type": "Item" + } + ] + ], + "packet_container_set_data": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "property", + "type": "zigzag32" + }, + { + "name": "value", + "type": "zigzag32" + } + ] + ], + "packet_crafting_data": [ + "container", + [ + { + "name": "recipes", + "type": "Recipes" + }, + { + "name": "potion_type_recipes", + "type": "PotionTypeRecipes" + }, + { + "name": "potion_container_recipes", + "type": "PotionContainerChangeRecipes" + }, + { + "name": "is_clean", + "type": "bool" + } + ] + ], + "packet_crafting_event": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "recipe_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "inventory", + "1": "crafting", + "2": "workbench" + } + } + ] + }, + { + "name": "recipe_id", + "type": "uuid" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "result", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + } + ] + ], + "packet_gui_data_pick_item": [ + "container", + [ + { + "name": "item_name", + "type": "string" + }, + { + "name": "item_effects", + "type": "string" + }, + { + "name": "hotbar_slot", + "type": "li32" + } + ] + ], + "packet_adventure_settings": [ + "container", + [ + { + "name": "flags", + "type": "AdventureFlags" + }, + { + "name": "command_permission", + "type": [ + "mapper", + { + "type": "varint32", + "mappings": { + "0": "normal", + "1": "operator", + "2": "host", + "3": "automation", + "4": "admin" + } + } + ] + }, + { + "name": "action_permissions", + "type": "ActionPermissions" + }, + { + "name": "permission_level", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "visitor", + "1": "member", + "2": "operator", + "3": "custom" + } + } + ] + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + } + ] + ], + "packet_block_entity_data": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_player_input": [ + "container", + [ + { + "name": "motion_x", + "type": "lf32" + }, + { + "name": "motion_z", + "type": "lf32" + }, + { + "name": "jumping", + "type": "bool" + }, + { + "name": "sneaking", + "type": "bool" + } + ] + ], + "packet_level_chunk": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "sub_chunk_count", + "type": "varint" + }, + { + "name": "cache_enabled", + "type": "bool" + }, + { + "name": "blobs", + "type": [ + "switch", + { + "compareTo": "cache_enabled", + "fields": { + "true": [ + "container", + [ + { + "name": "hashes", + "type": [ + "array", + { + "countType": "varint", + "type": "lu64" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_set_commands_enabled": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_set_difficulty": [ + "container", + [ + { + "name": "difficulty", + "type": "varint" + } + ] + ], + "packet_change_dimension": [ + "container", + [ + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "respawn", + "type": "bool" + } + ] + ], + "packet_set_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_player_list": [ + "container", + [ + { + "name": "records", + "type": "PlayerRecords" + } + ] + ], + "packet_simple_event": [ + "container", + [ + { + "name": "event_type", + "type": "lu16" + } + ] + ], + "packet_event": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint64" + }, + { + "name": "event_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "achievement_awarded", + "1": "entity_interact", + "2": "portal_built", + "3": "portal_used", + "4": "mob_killed", + "5": "cauldron_used", + "6": "player_death", + "7": "boss_killed", + "8": "agent_command", + "9": "agent_created", + "10": "banner_pattern_removed", + "11": "commaned_executed", + "12": "fish_bucketed", + "13": "mob_born", + "14": "pet_died", + "15": "cauldron_block_used", + "16": "composter_block_used", + "17": "bell_block_used", + "18": "actor_definition", + "19": "raid_update", + "20": "player_movement_anomaly", + "21": "player_moement_corrected", + "22": "honey_harvested", + "23": "target_block_hit", + "24": "piglin_barter" + } + } + ] + }, + { + "name": "use_player_id", + "type": "u8" + }, + { + "name": "event_data", + "type": "restBuffer" + } + ] + ], + "packet_spawn_experience_orb": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ], + "packet_clientbound_map_item_data": [ + "container", + [ + { + "name": "mapinfo", + "type": "MapInfo" + } + ] + ], + "packet_map_info_request": [ + "container", + [ + { + "name": "map_id", + "type": "zigzag64" + } + ] + ], + "packet_request_chunk_radius": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_chunk_radius_update": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_item_frame_drop_item": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + } + ] + ], + "packet_game_rules_changed": [ + "container", + [ + { + "name": "rules", + "type": "GameRules" + } + ] + ], + "packet_camera": [ + "container", + [ + { + "name": "camera_entity_unique_id", + "type": "zigzag64" + }, + { + "name": "target_player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_boss_event": [ + "container", + [ + { + "name": "boss_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "show_bar", + "1": "register_player", + "2": "hide_bar", + "3": "unregister_player", + "4": "set_bar_progress", + "5": "set_bar_title", + "6": "update_properties", + "7": "texture" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "register_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "unregister_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "show": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "bar_progress", + "type": "lf32" + } + ] + ], + "update_properties": [ + "container", + [ + { + "name": "darkness_factor", + "type": "li16" + } + ] + ], + "texture": [ + "container", + [ + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], + "set_bar_progress": [ + "container", + [ + { + "name": "bar_progress", + "type": "lf32" + } + ] + ], + "set_bar_title": [ + "container", + [ + { + "name": "title", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_show_credits": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "status", + "type": "zigzag32" + } + ] + ], + "packet_available_commands": [ + "container", + [ + { + "name": "values_len", + "type": "varint" + }, + { + "name": "_enum_type", + "type": [ + "enum_size_based_on_values_len" + ] + }, + { + "name": "enum_values", + "type": [ + "array", + { + "count": "values_len", + "type": "string" + } + ] + }, + { + "name": "suffixes", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + }, + { + "name": "enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "switch", + { + "compareTo": "../_enum_type", + "fields": { + "byte": "u8", + "short": "lu16", + "int": "lu32" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "command_data", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "description", + "type": "string" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "permission_level", + "type": "u8" + }, + { + "name": "alias", + "type": "li32" + }, + { + "name": "overloads", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "paramater_name", + "type": "string" + }, + { + "name": "value_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "1": "int", + "2": "float", + "3": "value", + "4": "wildcard_int", + "5": "operator", + "6": "target", + "16": "file_path", + "32": "string", + "40": "position", + "44": "message", + "46": "raw_text", + "50": "json", + "63": "command" + } + } + ] + }, + { + "name": "enum_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "16": "valid", + "32": "enum", + "256": "suffixed", + "1024": "soft_enum" + } + } + ] + }, + { + "name": "optional", + "type": "bool" + }, + { + "name": "options", + "type": "CommandFlags" + } + ] + ] + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "dynamic_enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "enum_constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "value_index", + "type": "li32" + }, + { + "name": "enum_index", + "type": "li32" + }, + { + "name": "constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "constraint", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "cheats_enabled", + "1": "operator_permissions", + "2": "host_permissions" + } + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_command_request": [ + "container", + [ + { + "name": "command", + "type": "string" + }, + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "interval", + "type": "bool" + } + ] + ], + "packet_command_block_update": [ + "container", + [ + { + "name": "is_block", + "type": "bool" + } + ] + ], + "packet_command_output": [ + "container", + [ + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "output_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "last", + "2": "silent", + "3": "all", + "4": "data_set" + } + } + ] + }, + { + "name": "success_count", + "type": "varint" + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "success", + "type": "bool" + }, + { + "name": "message_id", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "data_set", + "type": [ + "switch", + { + "compareTo": "output_type", + "fields": { + "data_set": "string" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_trade": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "varint" + }, + { + "name": "trade_tier", + "type": "varint" + }, + { + "name": "villager_unique_id", + "type": "varint64" + }, + { + "name": "entity_unique_id", + "type": "varint64" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "new_trading_ui", + "type": "bool" + }, + { + "name": "economic_trades", + "type": "bool" + }, + { + "name": "offers", + "type": "nbt" + } + ] + ], + "packet_update_equipment": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "inventory", + "type": "nbt" + } + ] + ], + "packet_resource_pack_data_info": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "max_chunk_size", + "type": "lu32" + }, + { + "name": "chunk_count", + "type": "lu32" + }, + { + "name": "compressed_package_size", + "type": "lu64" + }, + { + "name": "hash", + "type": "ByteArray" + }, + { + "name": "is_premium", + "type": "bool" + }, + { + "name": "pack_type", + "type": "u8" + } + ] + ], + "packet_resource_pack_chunk_data": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + }, + { + "name": "progress", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_resource_pack_chunk_request": [ + "container", + [ + { + "name": "package_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + } + ] + ], + "packet_transfer": [ + "container", + [ + { + "name": "server_address", + "type": "string" + }, + { + "name": "port", + "type": "lu16" + } + ] + ], + "packet_play_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "volume", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + } + ] + ], + "packet_stop_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "stop_all", + "type": "bool" + } + ] + ], + "packet_set_title": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "clear", + "1": "reset", + "2": "set_title", + "3": "set_subtitle", + "4": "action_bar_message", + "5": "set_durations", + "6": "set_title_json", + "7": "set_subtitle_json", + "8": "action_bar_message_json" + } + } + ] + }, + { + "name": "text", + "type": "string" + }, + { + "name": "fade_in_time", + "type": "zigzag32" + }, + { + "name": "stay_time", + "type": "zigzag32" + }, + { + "name": "fade_out_time", + "type": "zigzag32" + } + ] + ], + "packet_add_behavior_tree": [ + "container", + [ + { + "name": "behaviortree", + "type": "string" + } + ] + ], + "packet_structure_block_update": [ + "container", + [] + ], + "packet_show_store_offer": [ + "container", + [ + { + "name": "unknown0", + "type": "string" + }, + { + "name": "unknown1", + "type": "bool" + } + ] + ], + "packet_purchase_receipt": [ + "container", + [] + ], + "packet_player_skin": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "skin", + "type": "Skin" + }, + { + "name": "skin_name", + "type": "string" + }, + { + "name": "old_skin_name", + "type": "string" + }, + { + "name": "is_verified", + "type": "bool" + } + ] + ], + "packet_sub_client_login": [ + "container", + [] + ], + "packet_initiate_web_socket_connection": [ + "container", + [ + { + "name": "server", + "type": "string" + } + ] + ], + "packet_set_last_hurt_by": [ + "container", + [ + { + "name": "unknown", + "type": "varint" + } + ] + ], + "packet_book_edit": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "replace_page", + "1": "add_page", + "2": "delete_page", + "3": "swap_pages", + "4": "sign" + } + } + ] + }, + { + "name": "slot", + "type": "u8" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "replace_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "add_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "delete_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + } + ] + ], + "swap_pages": [ + "container", + [ + { + "name": "page1", + "type": "u8" + }, + { + "name": "page2", + "type": "u8" + } + ] + ], + "sign": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "author", + "type": "string" + }, + { + "name": "xuid", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_npc_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "unknown0", + "type": "u8" + }, + { + "name": "unknown1", + "type": "string" + }, + { + "name": "unknown2", + "type": "u8" + } + ] + ], + "packet_photo_transfer": [ + "container", + [ + { + "name": "file_name", + "type": "string" + }, + { + "name": "image_data", + "type": "string" + }, + { + "name": "unknown2", + "type": "string" + } + ] + ], + "packet_modal_form_request": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_modal_form_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_server_settings_request": [ + "container", + [] + ], + "packet_server_settings_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_show_profile": [ + "container", + [ + { + "name": "xuid", + "type": "string" + } + ] + ], + "packet_set_default_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_remove_objective": [ + "container", + [ + { + "name": "objective_name", + "type": "string" + } + ] + ], + "packet_set_display_objective": [ + "container", + [ + { + "name": "display_slot", + "type": "string" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "criteria_name", + "type": "string" + }, + { + "name": "sort_order", + "type": "zigzag32" + } + ] + ], + "packet_set_score": [ + "container", + [ + { + "name": "entries", + "type": "ScoreEntries" + } + ] + ], + "packet_lab_table": [ + "container", + [ + { + "name": "useless_byte", + "type": "u8" + }, + { + "name": "lab_table_x", + "type": "varint" + }, + { + "name": "lab_table_y", + "type": "varint" + }, + { + "name": "lab_table_z", + "type": "varint" + }, + { + "name": "reaction_type", + "type": "u8" + } + ] + ], + "packet_update_block_synced": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "transition_type", + "type": [ + "mapper", + { + "type": "varint64", + "mappings": { + "0": "entity", + "1": "create", + "2": "destroy" + } + } + ] + } + ] + ], + "packet_move_entity_delta": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "flags", + "type": "DeltaMoveFlags" + }, + { + "name": "x", + "type": [ + "switch", + { + "compareTo": "flags.has_x", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "y", + "type": [ + "switch", + { + "compareTo": "flags.has_y", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "z", + "type": [ + "switch", + { + "compareTo": "flags.has_z", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "rot_x", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_x", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_y", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_y", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_z", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_z", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + } + ] + ], + "packet_set_scoreboard_identity": [ + "container", + [ + { + "name": "entries", + "type": "ScoreboardIdentityEntries" + } + ] + ], + "packet_set_local_player_as_initialized": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_update_soft_enum": [ + "container", + [] + ], + "packet_network_stack_latency": [ + "container", + [ + { + "name": "timestamp", + "type": "lu64" + }, + { + "name": "unknown_flag", + "type": "u8" + } + ] + ], + "packet_script_custom_event": [ + "container", + [ + { + "name": "event_name", + "type": "string" + }, + { + "name": "event_data", + "type": "string" + } + ] + ], + "packet_spawn_particle_effect": [ + "container", + [ + { + "name": "dimension_id", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "particle_name", + "type": "string" + } + ] + ], + "packet_available_entity_identifiers": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event_v2": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_network_chunk_publisher_update": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "radius", + "type": "varint" + } + ] + ], + "packet_biome_definition_list": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event": [ + "container", + [ + { + "name": "sound_id", + "type": "SoundType" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event_generic": [ + "container", + [ + { + "name": "event_id", + "type": "varint" + }, + { + "name": "nbt", + "type": "nbtLoop" + } + ] + ], + "packet_lectern_update": [ + "container", + [ + { + "name": "page", + "type": "u8" + }, + { + "name": "page_count", + "type": "u8" + }, + { + "name": "position", + "type": "vec3i" + }, + { + "name": "drop_book", + "type": "bool" + } + ] + ], + "packet_video_stream_connect": [ + "container", + [ + { + "name": "server_uri", + "type": "string" + }, + { + "name": "frame_send_frequency", + "type": "lf32" + }, + { + "name": "action", + "type": "u8" + }, + { + "name": "resolution_x", + "type": "li32" + }, + { + "name": "resolution_y", + "type": "li32" + } + ] + ], + "packet_add_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_remove_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_client_cache_status": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_on_screen_texture_animation": [ + "container", + [] + ], + "packet_map_create_locked_copy": [ + "container", + [] + ], + "packet_structure_template_data_export_request": [ + "container", + [] + ], + "packet_structure_template_data_export_response": [ + "container", + [] + ], + "packet_update_block_properties": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_client_cache_blob_status": [ + "container", + [ + { + "name": "misses", + "type": "varint" + }, + { + "name": "haves", + "type": "varint" + }, + { + "name": "missing", + "type": [ + "array", + { + "count": "misses", + "type": "lu64" + } + ] + }, + { + "name": "have", + "type": [ + "array", + { + "count": "haves", + "type": "lu64" + } + ] + } + ] + ], + "packet_client_cache_miss_response": [ + "container", + [ + { + "name": "blobs", + "type": [ + "array", + { + "countType": "varint", + "type": "Blob" + } + ] + } + ] + ], + "packet_education_settings": [ + "container", + [ + { + "name": "CodeBuilderDefaultURI", + "type": "string" + }, + { + "name": "CodeBuilderTitle", + "type": "string" + }, + { + "name": "CanResizeCodeBuilder", + "type": "bool" + }, + { + "name": "HasOverrideURI", + "type": "bool" + }, + { + "name": "OverrideURI", + "type": [ + "switch", + { + "compareTo": "HasOverrideURI", + "fields": { + "true": "string" + }, + "default": "void" + } + ] + }, + { + "name": "HasQuiz", + "type": "bool" + } + ] + ], + "packet_multiplayer_settings": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "enable_multiplayer", + "1": "disable_multiplayer", + "2": "refresh_join_code" + } + } + ] + } + ] + ], + "packet_settings_command": [ + "container", + [ + { + "name": "command_line", + "type": "string" + }, + { + "name": "suppress_output", + "type": "bool" + } + ] + ], + "packet_anvil_damage": [ + "container", + [ + { + "name": "damage", + "type": "u8" + }, + { + "name": "position", + "type": "BlockCoordinates" + } + ] + ], + "packet_completed_using_item": [ + "container", + [ + { + "name": "used_item_id", + "type": "li16" + }, + { + "name": "use_method", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "equip_armor", + "1": "eat", + "2": "attack", + "3": "consume", + "4": "throw", + "5": "shoot", + "6": "place", + "7": "fill_bottle", + "8": "fill_bucket", + "9": "pour_bucket", + "10": "use_tool", + "11": "interact", + "12": "retrieved", + "13": "dyed", + "14": "traded" + } + } + ] + } + ] + ], + "packet_network_settings": [ + "container", + [ + { + "name": "compression_threshold", + "type": "u16" + } + ] + ], + "packet_player_auth_input": [ + "container", + [ + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "move_vector", + "type": "vec2f" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "input_data", + "type": "InputFlag" + }, + { + "name": "input_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "unknown", + "1": "mouse", + "2": "touch", + "3": "game_pad", + "4": "motion_controller" + } + } + ] + }, + { + "name": "play_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "teaser", + "2": "screen", + "3": "viewer", + "4": "reality", + "5": "placement", + "6": "living_room", + "7": "exit_level", + "8": "exit_level_living_room", + "9": "num_modes" + } + } + ] + }, + { + "name": "gaze_direction", + "type": [ + "switch", + { + "compareTo": "play_mode", + "fields": { + "reality": "vec3f" + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "transaction", + "type": [ + "switch", + { + "compareTo": "input_data.item_interact", + "fields": { + "true": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "actions", + "type": "TransactionActions" + }, + { + "name": "data", + "type": "TransactionUseItem" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "item_stack_request", + "type": [ + "switch", + { + "compareTo": "input_data.item_stack_request", + "fields": { + "true": "ItemStackRequest" + }, + "default": "void" + } + ] + }, + { + "name": "block_action", + "type": [ + "switch", + { + "compareTo": "input_data.block_action", + "fields": { + "true": [ + "array", + { + "countType": "zigzag32", + "type": [ + "container", + [ + { + "name": "action", + "type": "Action" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "action", + "fields": { + "start_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "abort_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "crack_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "predict_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "continue_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_creative_content": [ + "container", + [ + { + "name": "items", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "entry_id", + "type": "varint" + }, + { + "name": "item", + "type": "ItemLegacy" + } + ] + ] + } + ] + } + ] + ], + "packet_player_enchant_options": [ + "container", + [ + { + "name": "enchant_options", + "type": "EnchantOptions" + } + ] + ], + "packet_item_stack_request": [ + "container", + [ + { + "name": "requests", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemStackRequest" + } + ] + } + ] + ], + "packet_item_stack_response": [ + "container", + [ + { + "name": "responses", + "type": "ItemStackResponses" + } + ] + ], + "packet_player_armor_damage": [ + "container", + [ + { + "name": "type", + "type": "ArmorDamageType" + }, + { + "name": "helmet_damage", + "type": [ + "switch", + { + "compareTo": "type.head", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "chestplate_damage", + "type": [ + "switch", + { + "compareTo": "type.chest", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "leggings_damage", + "type": [ + "switch", + { + "compareTo": "type.legs", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "boots_damage", + "type": [ + "switch", + { + "compareTo": "type.feet", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + }, + { + "name": "player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_position_tracking_db_request": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "query" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + } + ] + ], + "packet_position_tracking_db_broadcast": [ + "container", + [ + { + "name": "broadcast_action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "update", + "1": "destory", + "2": "not_found" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_packet_violation_warning": [ + "container", + [ + { + "name": "violation_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "malformed" + } + } + ] + }, + { + "name": "severity", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "warning", + "1": "final_warning", + "2": "terminating" + } + } + ] + }, + { + "name": "packet_id", + "type": "zigzag32" + }, + { + "name": "reason", + "type": "string" + } + ] + ], + "packet_motion_prediction_hints": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + } + ] + ], + "packet_animate_entity": [ + "container", + [ + { + "name": "animation", + "type": "string" + }, + { + "name": "next_state", + "type": "string" + }, + { + "name": "stop_condition", + "type": "string" + }, + { + "name": "controller", + "type": "string" + }, + { + "name": "blend_out_time", + "type": "lf32" + }, + { + "name": "runtime_entity_ids", + "type": [ + "array", + { + "countType": "varint", + "type": "varint64" + } + ] + } + ] + ], + "packet_camera_shake": [ + "container", + [ + { + "name": "intensity", + "type": "lf32" + }, + { + "name": "duration", + "type": "lf32" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "stop" + } + } + ] + } + ] + ], + "packet_player_fog": [ + "container", + [ + { + "name": "stack", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "packet_correct_player_move_prediction": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_item_component": [ + "container", + [ + { + "name": "entries", + "type": "ItemComponentList" + } + ] + ], + "packet_filter_text_packet": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "from_server", + "type": "bool" + } + ] + ], + "packet_debug_renderer": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "1": "clear", + "2": "add_cube" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "clear": "void", + "add_cube": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "red", + "type": "lf32" + }, + { + "name": "green", + "type": "lf32" + }, + { + "name": "blue", + "type": "lf32" + }, + { + "name": "alpha", + "type": "lf32" + }, + { + "name": "duration", + "type": "li64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "string": [ + "pstring", + { + "countType": "varint" + } + ], + "ByteArray": [ + "buffer", + { + "countType": "varint" + } + ], + "SignedByteArray": [ + "buffer", + { + "countType": "zigzag32" + } + ], + "LittleString": [ + "pstring", + { + "countType": "li32" + } + ], + "ShortArray": [ + "buffer", + { + "countType": "li16" + } + ], + "MetadataFlags1": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "flags": [ + "onfire", + "sneaking", + "riding", + "sprinting", + "action", + "invisible", + "tempted", + "inlove", + "saddled", + "powered", + "ignited", + "baby", + "converting", + "critical", + "can_show_nametag", + "always_show_nametag", + "no_ai", + "silent", + "wallclimbing", + "can_climb", + "swimmer", + "can_fly", + "walker", + "resting", + "sitting", + "angry", + "interested", + "charged", + "tamed", + "orphaned", + "leashed", + "sheared", + "gliding", + "elder", + "moving", + "breathing", + "chested", + "stackable", + "showbase", + "rearing", + "vibrating", + "idling", + "evoker_spell", + "charge_attack", + "wasd_controlled", + "can_power_jump", + "linger", + "has_collision", + "affected_by_gravity", + "fire_immune", + "dancing", + "enchanted", + "show_trident_rope", + "container_private", + "transforming", + "spin_attack", + "swimming", + "bribed", + "pregnant", + "laying_egg", + "rider_can_pick", + "transition_sitting", + "eating", + "laying_down" + ] + } + ], + "MetadataFlags2": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "flags": [ + "sneezing", + "trusting", + "rolling", + "scared", + "in_scaffolding", + "over_scaffolding", + "fall_through_scaffolding", + "blocking", + "transition_blocking", + "blocked_using_shield", + "blocked_using_damaged_shield", + "sleeping", + "wants_to_wake", + "trade_interest", + "door_breaker", + "breaking_obstruction", + "door_opener", + "illager_captain", + "stunned", + "roaring", + "delayed_attacking", + "avoiding_mobs", + "avoiding_block", + "facing_target_to_range_attack", + "hidden_when_invisible", + "is_in_ui", + "stalking", + "emoting", + "celebrating", + "admiring", + "celebrating_special" + ] + } + ], + "UpdateBlockFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "neighbors": 1, + "network": 2, + "no_graphic": 4, + "unused": 8, + "priority": 16 + } + } + ], + "AdventureFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "world_immutable": 1, + "no_pvp": 2, + "auto_jump": 32, + "allow_flight": 64, + "no_clip": 128, + "world_builder": 256, + "flying": 512, + "muted": 1024 + } + } + ], + "ActionPermissions": [ + "bitflags", + { + "type": "varint", + "flags": { + "mine": 65537, + "doors_and_switches": 65538, + "open_containers": 65540, + "attack_players": 65544, + "attack_mobs": 65552, + "operator": 65568, + "teleport": 65664, + "build": 65792, + "default": 66048 + } + } + ], + "CommandFlags": [ + "bitfield", + [ + { + "name": "unused", + "size": 6, + "signed": false + }, + { + "name": "has_semantic_constraint", + "size": 1, + "signed": false + }, + { + "name": "collapse_enum", + "size": 1, + "signed": false + } + ] + ], + "DeltaMoveFlags": [ + "bitflags", + { + "type": "lu16", + "flags": { + "has_x": 1, + "has_y": 2, + "has_z": 4, + "has_rot_x": 8, + "has_rot_y": 16, + "has_rot_z": 32, + "on_ground": 64, + "teleport": 128, + "force_move": 256 + } + } + ], + "InputFlag": [ + "bitflags", + { + "type": "varint64", + "big": true, + "flags": [ + "ascend", + "descend", + "north_jump", + "jump_down", + "sprint_down", + "change_height", + "jumping", + "auto_jumping_in_water", + "sneaking", + "sneak_down", + "up", + "down", + "left", + "right", + "up_left", + "up_right", + "want_up", + "want_down", + "want_down_slow", + "want_up_slow", + "sprinting", + "ascend_scaffolding", + "descend_scaffolding", + "sneak_toggle_down", + "persist_sneak", + "start_sprinting", + "stop_sprinting", + "start_sneaking", + "stop_sneaking", + "start_swimming", + "stop_swimming", + "start_jumping", + "start_gliding", + "stop_gliding", + "item_interact", + "block_action", + "item_stack_request" + ] + } + ], + "ArmorDamageType": [ + "bitflags", + { + "type": "u8", + "flags": { + "head": 1, + "chest": 2, + "legs": 4, + "feet": 8 + } + } + ] + } +} \ No newline at end of file diff --git a/data/latest/proto.yml b/data/latest/proto.yml index e46463d..da3a9e1 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -1,13 +1,14 @@ # Created from MiNET and gophertunnel docs # The version below is the latest version this protocol schema was updated for. # The output protocol.json will be in the folder for the version -!version: 1.16.210 +!version: 1.16.220 # Some ProtoDef aliases string: ["pstring",{"countType":"varint"}] ByteArray: ["buffer",{"countType":"varint"}] SignedByteArray: ["buffer",{"countType":"zigzag32"}] LittleString: ["pstring",{"countType":"li32"}] +ShortArray: ["buffer",{"countType":"li16"}] varint32: varint bool: native zigzag32: native @@ -622,17 +623,45 @@ packet_level_event: 1060: sound_armor_stand_break 1061: sound_armor_stand_hit 1062: sound_armor_stand_fall - 1063: sound_armor_stand_place + 1063: sound_armor_stand_place + 1064: pointed_dripstone_land + 1065: dye_used + 1066: ink_sack_used 2000: particle_shoot #TODO: check 2000-2017 2001: particle_destroy 2002: particle_splash 2003: particle_eye_despawn 2004: particle_spawn - 2006: guardian_curse + 2005: particle_crop_growth + 2006: particle_guardian_curse + 2007: particle_death_smoke 2008: particle_block_force_field - 2009: particle_projectile_hit + 2009: particle_projectile_hit + 2010: particle_dragon_egg_teleport + 2011: particle_crop_eaten + 2012: particle_critical 2013: particle_enderman_teleport - 2014: particle_punch_block + 2014: particle_punch_block + 2015: particle_bubble + 2016: particle_evaporate + 2017: particle_destroy_armor_stand + 2018: particle_breaking_egg + 2019: particle_destroy_egg + 2020: particle_evaporate_water + 2021: particle_destroy_block_no_sound + 2022: particle_knockback_roar + 2023: particle_teleport_trail + 2024: particle_point_cloud + 2025: particle_explosion + 2026: particle_block_explosion + 2027: particle_vibration_signal + 2028: particle_dripstone_drip + 2029: particle_fizz_effect + 2030: particle_wax_on + 2031: particle_wax_off + 2032: particle_scrape + 2033: particle_electric_spark + 3001: start_rain 3002: start_thunder 3003: stop_rain @@ -966,7 +995,7 @@ packet_inventory_slot: slot: varint # NewItem is the item to be put in the slot at Slot. It will overwrite any item that may currently # be present in that slot. - item: ItemStack + item: Item # ContainerSetData is sent by the server to update specific data of a single container, meaning a block such # as a furnace or a brewing stand. This data is usually used by the client to display certain features @@ -1385,6 +1414,8 @@ packet_available_commands: constraints: []varint constraint: u8 => 0: cheats_enabled + 1: operator_permissions + 2: host_permissions # ParamOptionCollapseEnum specifies if the enum (only if the Type is actually an enum type. If not, # setting this to true has no effect) should be collapsed. This means that the options of the enum are @@ -1878,10 +1909,14 @@ packet_biome_definition_list: !bound: client nbt: nbt +# LevelSoundEvent is sent by the server to make any kind of built-in sound heard to a player. It is sent to, +# for example, play a stepping sound or a shear sound. The packet is also sent by the client, in which case +# it could be forwarded by the server to the other players online. If possible, the packets from the client +# should be ignored however, and the server should play them on its own accord. packet_level_sound_event: !id: 0x7b !bound: both - sound_id: varint + sound_id: SoundType position: vec3f block_id: zigzag32 entity_type: string @@ -2210,7 +2245,9 @@ InputFlag: [ "bitflags", { packet_creative_content: !id: 0x91 !bound: client - items: ItemStacks + items: []varint + entry_id: varint + item: ItemLegacy packet_player_enchant_options: !id: 0x92 diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 7d85243..d633c70 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -75,25 +75,72 @@ Itemstates: []varint runtime_id: li16 component_based: bool +# Start of item crap ... + +ItemExtraDataWithBlockingTick: + has_nbt: lu16 => + 0xffff: 'true' + 0x0000: 'false' + nbt: has_nbt ? + if true: + version: u8 + nbt: lnbt + default: void + can_place_on: ShortArray[]li32 + can_destroy: ShortArray[]li32 + blocking_tick: li64 + +ItemExtraDataWithoutBlockingTick: + has_nbt: lu16 => + 0xffff: 'true' + 0x0000: 'false' + nbt: has_nbt ? + if true: + version: u8 + nbt: lnbt + default: void + can_place_on: ShortArray[]li32 + can_destroy: ShortArray[]li32 + +# Same as below but without a "networkStackID" boolean ... +ItemLegacy: + network_id: zigzag32 + _: network_id? + if 0: void + default: + count: lu16 + metadata: varint + block_runtime_id: zigzag32 + extra: network_id ? + if 355: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' + default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]' + +# An "ItemStack" here represents an Item instance. You can think about it like a pointer +# to an item class. The data for the class gets updated with the data in the `item` field +# As of 1.16.220, now functionally the same as `Item` just without an extra boolean when +# server auth inventories is disabled. Item: network_id: zigzag32 _: network_id? if 0: void default: - auxiliary_value: zigzag32 - has_nbt: lu16 => - 0xffff: 'true' - 0x0000: 'false' - nbt: has_nbt? - if true: - version: u8 - nbt: nbt - default: void - can_place_on: string[]zigzag32 - can_destroy: string[]zigzag32 - _: network_id? - if 355: - blocking_tick: zigzag64 + count: lu16 + metadata: varint + # When server authoritative inventory is enabled, all allocated items have a unique ID used to identify + # a specifc item instance. + has_stack_id: u8 + # StackNetworkID is the network ID of the item stack. If the stack is empty, 0 is always written for this + # field. If not, the field should be set to 1 if the server authoritative inventories are disabled in the + # StartGame packet, or to a unique stack ID if it is enabled. + stack_id: has_stack_id ? + if 0: void + default: zigzag32 + block_runtime_id: zigzag32 + extra: network_id ? + if 355: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' + default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]' + +# end of item crap vec3i: x: zigzag32 @@ -413,7 +460,7 @@ TransactionUseItem: 2: break_block # BlockPosition is the position of the block that was interacted with. This is only really a correct # block position if ActionType is not UseItemActionClickAir. - block_position: BlockCoordinates + block_position: vec3i # BlockFace is the face of the block that was interacted with. When clicking the block, it is the face # clicked. When breaking the block, it is the face that was last being hit until the block broke. face: varint @@ -438,7 +485,6 @@ TransactionUseItem: # all of these actions results in a balanced inventory transaction. This should be checked to ensure that # no items are cheated into the inventory. TransactionActions: - network_ids: bool actions: []varint source_type: varint => 0: container @@ -458,9 +504,6 @@ TransactionActions: slot: varint old_item: Item new_item: Item - new_item_stack_id: ../network_ids? - if true: zigzag32 - default: void # The Minecraft bedrock inventory system was refactored, but not all inventory actions use the new packet. # This data structure holds actions that have not been updated to the new system. @@ -542,17 +585,7 @@ Transaction: # mainly for purposes such as spawning eating particles at that position. head_pos: vec3f -# An "ItemStack" here represents an Item instance. You can think about it like a pointer -# to an item class. The data for the class gets updated with the data in the `item` field -ItemStack: - # StackNetworkID is the network ID of the item stack. If the stack is empty, 0 is always written for this - # field. If not, the field should be set to 1 if the server authoritative inventories are disabled in the - # StartGame packet, or to a unique stack ID if it is enabled. - stack_id: varint - # Stack is the actual item stack of the item instance. - item: Item - -ItemStacks: ItemStack[]varint +ItemStacks: Item[]varint RecipeIngredient: network_id: zigzag32 @@ -591,7 +624,7 @@ Recipes: []varint if shapeless or shulker_box or shapeless_chemistry: recipe_id: string input: RecipeIngredient[]varint - output: Item[]varint + output: ItemLegacy[]varint uuid: uuid block: string priority: zigzag32 @@ -604,19 +637,19 @@ Recipes: []varint # RecipeIngredient[$height][$width] or RecipeIngredient[]$height[]$width ? input: []$width _: RecipeIngredient[]$height - output: Item[]varint + output: ItemLegacy[]varint uuid: uuid block: string priority: zigzag32 network_id: varint if furnace: input_id: zigzag32 - output: Item + output: ItemLegacy block: string if furnace_with_metadata: input_id: zigzag32 input_meta: zigzag32 - output: Item + output: ItemLegacy block: string if multi: uuid: uuid @@ -889,7 +922,7 @@ ItemStackRequest: filtered_string_index: li32 if non_implemented: void if results_deprecated: - result_items: Item[]varint + result_items: ItemLegacy[]varint times_crafted: u8 # CustomNames is a list of custom names involved in the request. This is typically filled with one string # when an anvil is used. @@ -959,6 +992,10 @@ CommandOrigin: 9: virtual 10: game_argument 11: entity_server + 12: precompiled + 13: game_director_entity_server # ? + 14: script + # UUID is the UUID of the command called. This UUID is a bit odd as it is not specified by the server. It # is not clear what exactly this UUID is meant to identify, but it is unique for each command called. uuid: uuid @@ -1135,6 +1172,344 @@ ContainerSlotType: u8 => - cursor - creative_output +SoundType: varint => + - ItemUseOn + - Hit + - Step + - Fly + - Jump + - Break + - Place + - HeavyStep + - Gallop + - Fall + - Ambient + - AmbientBaby + - AmbientInWater + - Breathe + - Death + - DeathInWater + - DeathToZombie + - Hurt + - HurtInWater + - Mad + - Boost + - Bow + - SquishBig + - SquishSmall + - FallBig + - FallSmall + - Splash + - Fizz + - Flap + - Swim + - Drink + - Eat + - Takeoff + - Shake + - Plop + - Land + - Saddle + - Armor + - MobArmorStandPlace + - AddChest + - Throw + - Attack + - AttackNoDamage + - AttackStrong + - Warn + - Shear + - Milk + - Thunder + - Explode + - Fire + - Ignite + - Fuse + - Stare + - Spawn + - Shoot + - BreakBlock + - Launch + - Blast + - LargeBlast + - Twinkle + - Remedy + - Infect + - LevelUp + - BowHit + - BulletHit + - ExtinguishFire + - ItemFizz + - ChestOpen + - ChestClosed + - ShulkerBoxOpen + - ShulkerBoxClosed + - EnderChestOpen + - EnderChestClosed + - PowerOn + - PowerOff + - Attach + - Detach + - Deny + - Tripod + - Pop + - DropSlot + - Note + - Thorns + - PistonIn + - PistonOut + - Portal + - Water + - LavaPop + - Lava + - Burp + - BucketFillWater + - BucketFillLava + - BucketEmptyWater + - BucketEmptyLava + - ArmorEquipChain + - ArmorEquipDiamond + - ArmorEquipGeneric + - ArmorEquipGold + - ArmorEquipIron + - ArmorEquipLeather + - ArmorEquipElytra + - Record13 + - RecordCat + - RecordBlocks + - RecordChirp + - RecordFar + - RecordMall + - RecordMellohi + - RecordStal + - RecordStrad + - RecordWard + - Record11 + - RecordWait + - unknown1 + - Flop + - ElderGuardianCurse + - MobWarning + - MobWarningBaby + - Teleport + - ShulkerOpen + - ShulkerClose + - Haggle + - HaggleYes + - HaggleNo + - HaggleIdle + - ChorusGrow + - ChorusDeath + - Glass + - PotionBrewed + - CastSpell + - PrepareAttack + - PrepareSummon + - PrepareWololo + - Fang + - Charge + - CameraTakePicture + - LeashKnotPlace + - LeashKnotBreak + - Growl + - Whine + - Pant + - Purr + - Purreow + - DeathMinVolume + - DeathMidVolume + - unknown2 + - ImitateCaveSpider + - ImitateCreeper + - ImitateElderGuardian + - ImitateEnderDragon + - ImitateEnderman + - unknown3 + - ImitateEvocationIllager + - ImitateGhast + - ImitateHusk + - ImitateIllusionIllager + - ImitateMagmaCube + - ImitatePolarBear + - ImitateShulker + - ImitateSilverfish + - ImitateSkeleton + - ImitateSlime + - ImitateSpider + - ImitateStray + - ImitateVex + - ImitateVindicationIllager + - ImitateWitch + - ImitateWither + - ImitateWitherSkeleton + - ImitateWolf + - ImitateZombie + - ImitateZombiePigman + - ImitateZombieVillager + - BlockEndPortalFrameFill + - BlockEndPortalSpawn + - RandomAnvilUse + - BottleDragonBreath + - PortalTravel + - ItemTridentHit + - ItemTridentReturn + - ItemTridentRiptide1 + - ItemTridentRiptide2 + - ItemTridentRiptide3 + - ItemTridentThrow + - ItemTridentThunder + - ItemTridentHitGround + - Default + - BlockFletchingTableUse + - ElemConstructOpen + - IceBombHit + - BalloonPop + - LtReactionIceBomb + - LtReactionBleach + - LtReactionEPaste + - LtReactionEPaste2 + - LtReactionFertilizer + - LtReactionFireball + - LtReactionMgsalt + - LtReactionMiscfire + - LtReactionFire + - LtReactionMiscexplosion + - LtReactionMiscmystical + - LtReactionMiscmystical2 + - LtReactionProduct + - SparklerUse + - GlowstickUse + - SparklerActive + - ConvertToDrowned + - BucketFillFish + - BucketEmptyFish + - BubbleUp + - BubbleDown + - BubblePop + - BubbleUpInside + - BubbleDownInside + - HurtBaby + - DeathBaby + - StepBaby + - BabySpawn + - Born + - BlockTurtleEggBreak + - BlockTurtleEggCrack + - BlockTurtleEggHatch + - TurtleLayEgg + - BlockTurtleEggAttack + - BeaconActivate + - BeaconAmbient + - BeaconDeactivate + - BeaconPower + - ConduitActivate + - ConduitAmbient + - ConduitAttack + - ConduitDeactivate + - ConduitShort + - Swoop + - BlockBambooSaplingPlace + - PreSneeze + - Sneeze + - AmbientTame + - Scared + - BlockScaffoldingClimb + - CrossbowLoadingStart + - CrossbowLoadingMiddle + - CrossbowLoadingEnd + - CrossbowShoot + - CrossbowQuickChargeStart + - CrossbowQuickChargeMiddle + - CrossbowQuickChargeEnd + - AmbientAggressive + - AmbientWorried + - CantBreed + - ItemShieldBlock + - ItemBookPut + - BlockGrindstoneUse + - BlockBellHit + - BlockCampfireCrackle + - Roar + - Stun + - BlockSweetBerryBushHurt + - BlockSweetBerryBushPick + - UICartographyTableTakeResult + - UIStoneCutterTakeResult + - BlockComposterEmpty + - BlockComposterFill + - BlockComposterFillSuccess + - BlockComposterReady + - BlockBarrelOpen + - BlockBarrelClose + - RaidHorn + - BlockLoomUse + - AmbientRaid + - UICartographyTableUse + - UIStoneCutterUse + - UILoomUse + - SmokerUse + - BlastFurnaceUse + - SmithingTableUse + - Screech + - Sleep + - FurnaceUse + - MooshroomConvert + - MilkSuspiciously + - Celebrate + - JumpPrevent + - AmbientPollinate + - BeeHiveDrip + - BeeHiveEnter + - BeeHiveExit + - BeeHiveWork + - BeeHiveShear + - HoneyBottleDrink + - AmbientCave + - Retreat + - ConvertToZombified + - Admire + - StepLava + - Tempt + - Panic + - Angry + - AmbientWarpedForest + - AmbientSoulsandValley + - AmbientNetherWastes + - AmbientBasaltDeltas + - AmbientCrimsonForest + - RespawnAnchorCharge + - RespawnAnchorDeplete + - RespawnAnchorSetSpawn + - RespawnAnchorAmbient + - SoulEscapeQuiet + - SoulEscapeLoud + - RecordPigstep + - LinkCompassToLodestone + - BlockSmithingTableUse + - EquipNetherite + - AmbientLoopWarpedForest + - AmbientLoopSoulsandValley + - AmbientLoopNetherWastes + - AmbientLoopBasaltDeltas + - AmbientLoopCrimsonForest + - AmbientAdditionWarpedForest + - AmbientAdditionSoulsandValley + - AmbientAdditionNetherWastes + - AmbientAdditionBasaltDeltas + - AmbientAdditionCrimsonForest + - SculkSensorPowerOn + - SculkSensorPowerOff + - BucketFillPowderSnow + - BucketEmptyPowderSnow + - PointedDripstoneCauldronDripWater + - PointedDripstoneCauldronDripLava + - PointedDripstoneDripWater + - PointedDripstoneDripLava + - CaveVinesPickBerries + - BigDripleafTiltDown + - BigDripleafTiltUp + - Undefined + # TODO: remove? LegacyEntityType: li32 => 10: chicken diff --git a/package.json b/package.json index e6371bd..cea9e9d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "bedrock-protocol", "version": "3.0.0", - "description": "Parse and serialize Minecraft Bedrock Edition packets", + "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { "build": "cd tools && node compileProtocol.js", @@ -15,6 +15,7 @@ }, "keywords": [ "minecraft", + "bedrock", "pocket-edition", "protocol" ], @@ -24,27 +25,25 @@ "@jsprismarine/jsbinaryutils": "^2.1.8", "@xboxreplay/xboxlive-auth": "^3.3.3", "asn1": "^0.2.4", - "browserify-cipher": "^1.0.1", - "bedrock-provider": "^1.0.0", "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", "jsp-raknet": "github:extremeheat/raknet#client", - "leveldb-zlib": "0.0.26", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", "protodef": "^1.11.0", - "raknet-native": "^1.0.0", + "raknet-native": "^1.0.1", "uuid-1345": "^1.0.2" }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", + "bedrock-provider": "^1.0.0", "babel-eslint": "^10.1.0", - "buffer-equal": "^1.0.0", "mocha": "^8.3.2", - "protodef-yaml": "^1.0.2", + "protodef-yaml": "^1.0.3", "standard": "^16.0.3", + "leveldb-zlib": "0.0.26", "bedrock-protocol": "file:." }, "standard": { diff --git a/src/connection.js b/src/connection.js index f4476bc..a13872a 100644 --- a/src/connection.js +++ b/src/connection.js @@ -2,7 +2,7 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') -const Versions = require('./options') +const { Versions } = require('./options') const debug = require('debug')('minecraft-protocol') const SKIP_BATCH = ['level_chunk', 'client_cache_blob_status', 'client_cache_miss_response'] @@ -29,19 +29,11 @@ class Connection extends EventEmitter { } versionLessThan (version) { - if (typeof version === 'string') { - return Versions[version] < this.options.protocolVersion - } else { - return version < this.options.protocolVersion - } + return this.options.protocolVersion < (typeof version === 'string' ? Versions[version] : version) } versionGreaterThan (version) { - if (typeof version === 'string') { - return Versions[version] > this.options.protocolVersion - } else { - return version > this.options.protocolVersion - } + return this.options.protocolVersion > (typeof version === 'string' ? Versions[version] : version) } startEncryption (iv) { diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index dd3afe3..6838a84 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -36,28 +36,48 @@ SizeOf.restBuffer = ['native', (value) => { return value.length }] +/** + * Encapsulated data with length prefix + */ +Read.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => { + return compiler.wrapCode(` + const payloadSize = ${compiler.callType(lengthType, 'offset')} + const { value, size } = ctx.${type}(buffer, offset + payloadSize.size) + return { value, size: size + payloadSize.size } +`.trim()) +}] +Write.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => { + return compiler.wrapCode(` + const buf = Buffer.allocUnsafe(buffer.length - offset) + const payloadSize = (ctx.${type})(value, buf, 0) + let size = (ctx.${lengthType})(payloadSize, buffer, offset) + size += buf.copy(buffer, size, 0, payloadSize) + return size +`.trim()) +}] +SizeOf.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => { + return compiler.wrapCode(` + const payloadSize = (ctx.${type})(value) + return (ctx.${lengthType})(payloadSize) + payloadSize +`.trim()) +}] + /** * Read NBT until end of buffer or \0 */ Read.nbtLoop = ['context', (buffer, offset) => { const values = [] while (buffer[offset] != 0) { - // console.log('offs',offset, buffer.length,buffer.slice(offset)) const n = ctx.nbt(buffer, offset) - // console.log('read',n) values.push(n.value) offset += n.size } - // console.log('Ext',offset, buffer.length,buffer.slice(offset)) return { value: values, size: buffer.length - offset } }] Write.nbtLoop = ['context', (value, buffer, offset) => { for (const val of value) { - // console.log('val',val,offset) offset = ctx.nbt(val, buffer, offset) } - // offset += 1 - // console.log('writing 0', offset) buffer.writeUint8(0, offset) return offset + 1 }] @@ -76,6 +96,10 @@ Read.nbt = ['native', minecraft.nbt[0]] Write.nbt = ['native', minecraft.nbt[1]] SizeOf.nbt = ['native', minecraft.nbt[2]] +Read.lnbt = ['native', minecraft.lnbt[0]] +Write.lnbt = ['native', minecraft.lnbt[1]] +SizeOf.lnbt = ['native', minecraft.lnbt[2]] + /** * Bits */ @@ -84,7 +108,7 @@ Read.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { let fstr = JSON.stringify(flags) if (Array.isArray(flags)) { fstr = '{' - flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) + flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) fstr += '}' } else if (shift) { fstr = '{' @@ -106,7 +130,7 @@ Write.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => { let fstr = JSON.stringify(flags) if (Array.isArray(flags)) { fstr = '{' - flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) + flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) fstr += '}' } else if (shift) { fstr = '{' @@ -127,7 +151,7 @@ SizeOf.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => let fstr = JSON.stringify(flags) if (Array.isArray(flags)) { fstr = '{' - flags.map((v,k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) + flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ',')) fstr += '}' } else if (shift) { fstr = '{' diff --git a/src/datatypes/minecraft.js b/src/datatypes/minecraft.js index 9ca4920..ae5d324 100644 --- a/src/datatypes/minecraft.js +++ b/src/datatypes/minecraft.js @@ -2,7 +2,8 @@ const nbt = require('prismarine-nbt') const UUID = require('uuid-1345') -const proto = nbt.protos.littleVarint +const protoLE = nbt.protos.little +const protoLEV = nbt.protos.littleVarint // TODO: deal with this: const zigzag = require('prismarine-nbt/compiler-zigzag') @@ -20,16 +21,32 @@ function writeUUID (value, buffer, offset) { return offset + 16 } +// Little Endian + varints + function readNbt (buffer, offset) { - return proto.read(buffer, offset, 'nbt') + return protoLEV.read(buffer, offset, 'nbt') } function writeNbt (value, buffer, offset) { - return proto.write(value, buffer, offset, 'nbt') + return protoLEV.write(value, buffer, offset, 'nbt') } function sizeOfNbt (value) { - return proto.sizeOf(value, 'nbt') + return protoLEV.sizeOf(value, 'nbt') +} + +// Little Endian + +function readNbtLE (buffer, offset) { + return protoLE.read(buffer, offset, 'nbt') +} + +function writeNbtLE (value, buffer, offset) { + return protoLE.write(value, buffer, offset, 'nbt') +} + +function sizeOfNbtLE (value) { + return protoLE.sizeOf(value, 'nbt') } function readEntityMetadata (buffer, offset, _ref) { @@ -131,6 +148,7 @@ function sizeOfEndOfArray (value, typeArgs) { module.exports = { uuid: [readUUID, writeUUID, 16], nbt: [readNbt, writeNbt, sizeOfNbt], + lnbt: [readNbtLE, writeNbtLE, sizeOfNbtLE], entityMetadataLoop: [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata], ipAddress: [readIpAddress, writeIpAddress, 4], endOfArray: [readEndOfArray, writeEndOfArray, sizeOfEndOfArray], diff --git a/src/options.js b/src/options.js index 1c9e978..8750697 100644 --- a/src/options.js +++ b/src/options.js @@ -1,9 +1,10 @@ // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson -const CURRENT_VERSION = '1.16.210' +const CURRENT_VERSION = '1.16.220' const Versions = { + '1.16.220': 431, '1.16.210': 428, '1.16.201': 422 } diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 1d4d294..56dfc44 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,28 +1,26 @@ const { Transform } = require('readable-stream') const crypto = require('crypto') const Zlib = require('zlib') -if (globalThis.isElectron) var { CipherCFB8 } = require('raknet-native') // eslint-disable-line +if (globalThis.isElectron) var { CipherGCM, CipherCFB8 } = require('raknet-native') // eslint-disable-line -const CIPHER_ALG = 'aes-256-cfb8' - -function createCipher (secret, initialValue) { - if (crypto.getCiphers().includes(CIPHER_ALG)) { - return crypto.createCipheriv(CIPHER_ALG, secret, initialValue) +function createCipher (secret, initialValue, cipherAlgorithm) { + if (crypto.getCiphers().includes(cipherAlgorithm)) { + return crypto.createCipheriv(cipherAlgorithm, secret, initialValue) } return new Cipher(secret, initialValue) } -function createDecipher (secret, initialValue) { - if (crypto.getCiphers().includes(CIPHER_ALG)) { - return crypto.createDecipheriv(CIPHER_ALG, secret, initialValue) +function createDecipher (secret, initialValue, cipherAlgorithm) { + if (crypto.getCiphers().includes(cipherAlgorithm)) { + return crypto.createDecipheriv(cipherAlgorithm, secret, initialValue) } return new Decipher(secret, initialValue) } class Cipher extends Transform { - constructor (secret, iv) { + constructor (gcm, secret, iv) { super() - this.aes = new CipherCFB8(secret, iv) + this.aes = gcm ? new CipherGCM(secret, iv) : new CipherCFB8(secret, iv) } _transform (chunk, enc, cb) { @@ -32,9 +30,9 @@ class Cipher extends Transform { } class Decipher extends Transform { - constructor (secret, iv) { + constructor (gcm, secret, iv) { super() - this.aes = new CipherCFB8(secret, iv) + this.aes = gcm ? new CipherGCM(secret, iv) : new CipherCFB8(secret, iv) } _transform (chunk, enc, cb) { @@ -54,7 +52,11 @@ function computeCheckSum (packetPlaintext, sendCounter, secretKeyBytes) { } function createEncryptor (client, iv) { - client.cipher = createCipher(client.secretKeyBytes, iv) + if (client.versionLessThan('1.16.220')) { + client.cipher = createCipher(client.secretKeyBytes, iv, 'aes-256-cfb8') + } else { + client.cipher = createCipher(client.secretKeyBytes, iv.slice(0, 12), 'aes-256-gcm') + } client.sendCounter = client.sendCounter || 0n // A packet is encrypted via AES256(plaintext + SHA256(send_counter + plaintext + secret_key)[0:8]). @@ -77,18 +79,21 @@ function createEncryptor (client, iv) { } function createDecryptor (client, iv) { - client.decipher = createDecipher(client.secretKeyBytes, iv) + if (client.versionLessThan('1.16.220')) { + client.decipher = createDecipher(client.secretKeyBytes, iv, 'aes-256-cfb8') + } else { + client.decipher = createDecipher(client.secretKeyBytes, iv.slice(0, 12), 'aes-256-gcm') + } + client.receiveCounter = client.receiveCounter || 0n function verify (chunk) { - // console.log('Decryptor: checking checksum', client.receiveCounter, chunk) const packet = chunk.slice(0, chunk.length - 8) const checksum = chunk.slice(chunk.length - 8, chunk.length) const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) client.receiveCounter++ if (Buffer.compare(checksum, computedCheckSum) !== 0) { - // console.log('Inflated', inflatedLen, chunk.length, extraneousLen, chunk.toString('hex')) throw Error(`Checksum mismatch ${checksum.toString('hex')} != ${computedCheckSum.toString('hex')}`) } @@ -108,17 +113,3 @@ function createDecryptor (client, iv) { module.exports = { createCipher, createDecipher, createEncryptor, createDecryptor } - -// function testDecrypt () { -// const client = { -// secretKeyBytes: Buffer.from('ZOBpyzki/M8UZv5tiBih048eYOBVPkQE3r5Fl0gmUP4=', 'base64'), -// onDecryptedPacket: (...data) => console.log('Decrypted', data) -// } -// const iv = Buffer.from('ZOBpyzki/M8UZv5tiBih0w==', 'base64') - -// const decrypt = createDecryptor(client, iv) -// console.log('Dec', decrypt(Buffer.from('4B4FCA0C2A4114155D67F8092154AAA5EF', 'hex'))) -// console.log('Dec 2', decrypt(Buffer.from('DF53B9764DB48252FA1AE3AEE4', 'hex'))) -// } - -// testDecrypt() diff --git a/test/internal.js b/test/internal.js index 40aeb5e..09b184b 100644 --- a/test/internal.js +++ b/test/internal.js @@ -1,17 +1,15 @@ // process.env.DEBUG = 'minecraft-protocol raknet' const { Server, Client } = require('../') -const { dumpPackets, hasDumps } = require('../tools/genPacketDumps') +const { dumpPackets } = require('../tools/genPacketDumps') const DataProvider = require('../data/provider') // First we need to dump some packets that a vanilla server would send a vanilla // client. Then we can replay those back in our custom server. function prepare (version) { - if (!hasDumps(version)) { - return dumpPackets(version) - } + return dumpPackets(version) } -async function startTest (version = '1.16.210', ok) { +async function startTest (version = '1.16.201', ok) { await prepare(version) const Item = require('../types/Item')(version) const port = 19130 @@ -36,7 +34,7 @@ async function startTest (version = '1.16.210', ok) { // server logic server.on('connect', client => { client.on('join', () => { - console.log('Client joined', client.getData()) + console.log('Client joined server', client.getData()) client.write('resource_packs_info', { must_accept: false, diff --git a/test/internal.test.js b/test/internal.test.js index e3feeac..3f37b17 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -1,11 +1,15 @@ /* eslint-env jest */ const { timedTest } = require('./internal') +const { Versions } = require('../src/options') describe('internal client/server test', function () { this.timeout(120 * 1000) it('connects', async () => { - await timedTest() + for (const version in Versions) { + console.debug(version) + await timedTest(version) + } }) }) diff --git a/test/vanilla.js b/test/vanilla.js index 4f37d6b..3d7c11a 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -3,10 +3,11 @@ const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') const { waitFor } = require('../src/datatypes/util') const { ChunkColumn, Version } = require('bedrock-provider') +const { CURRENT_VERSION } = require('../src/options') async function test (version) { // Start the server, wait for it to accept clients, throws on timeout - const handle = await vanillaServer.startServerAndWait(version, 1000 * 120) + const handle = await vanillaServer.startServerAndWait(version, 1000 * 220) console.log('Started server') const client = new Client({ @@ -65,5 +66,5 @@ async function test (version) { clearInterval(loop) } -if (!module.parent) test() +if (!module.parent) test(CURRENT_VERSION) module.exports = { clientTest: test } diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index fabb0db..4163094 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -66,6 +66,7 @@ function createProtocol () { function copyLatest () { process.chdir(join(__dirname, '/../data/latest')) const version = genProtoSchema() + try { fs.mkdirSync(`../${version}`) } catch {} fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: getJSON('./proto.json') }, null, 2)) fs.unlinkSync('./proto.json') // remove temp file fs.unlinkSync('./packet_map.yml') // remove temp file diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index 5add677..d91dc54 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -27,6 +27,7 @@ async function dump (version, force) { const client = new Client({ hostname: '127.0.0.1', port, + version, username: 'Boat' + random, offline: true }) diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index a409fca..169f3f7 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -48,7 +48,7 @@ async function download (os, version, path = 'bds-') { get(found, 'bds.zip') console.info('⚡ Unzipping') // Unzip server - if (process.platform === 'linux') cp.execSync('unzip bds.zip') + if (process.platform === 'linux') cp.execSync('unzip bds.zip && chmod +777 ./bedrock_server') else cp.execSync('tar -xf bds.zip') return verStr } @@ -83,7 +83,11 @@ async function startServer (version, onStart, options = {}) { configure(options) const handle = run(!onStart) if (onStart) { - handle.stdout.on('data', data => data.includes('Server started.') ? onStart() : null) + let stdout = '' + handle.stdout.on('data', data => { + stdout += data + if (stdout.includes('Server started')) onStart() + }) handle.stdout.pipe(process.stdout) handle.stderr.pipe(process.stdout) } diff --git a/types/Item.js b/types/Item.js index eb4d804..1153308 100644 --- a/types/Item.js +++ b/types/Item.js @@ -11,26 +11,52 @@ module.exports = (version) => } static fromBedrock (obj) { - return new Item({ - runtimeId: obj.runtime_id, - networkId: obj.item?.network_id, - count: obj.item?.auxiliary_value & 0xff, - metadata: obj.item?.auxiliary_value >> 8, - nbt: obj.item?.nbt?.nbt - }) + if (version === '1.16.220') { + return new Item({ + networkId: obj.network_id, + stackId: obj.stack_id, + blockRuntimeId: obj.block_runtime_id, + count: obj.count, + metadata: obj.metadata, + nbt: obj.extra.nbt + }) + } else { + return new Item({ + networkId: obj.runtime_id, + sackId: obj.item?.network_id, + count: obj.item?.auxiliary_value & 0xff, + metadata: obj.item?.auxiliary_value >> 8, + nbt: obj.item?.nbt?.nbt + }) + } } toBedrock () { - return { - runtime_id: this.runtimeId, - item: { + if (version === '1.16.220') { + return { network_id: this.networkId, - auxiliary_value: (this.metadata << 8) | (this.count & 0xff), - has_nbt: !!this.nbt, - nbt: { version: 1, nbt: this.nbt }, - can_place_on: [], - can_destroy: [], - blocking_tick: 0 + count: this.count, + metadata: this.metadata, + extra: { + has_nbt: !!this.nbt, + nbt: { version: 1, nbt: this.nbt }, + can_place_on: [], + can_destroy: [], + blocking_tick: 0 + } + } + } else { + return { + runtime_id: this.runtimeId, + item: { + network_id: this.networkId, + auxiliary_value: (this.metadata << 8) | (this.count & 0xff), + has_nbt: !!this.nbt, + nbt: { version: 1, nbt: this.nbt }, + can_place_on: [], + can_destroy: [], + blocking_tick: 0 + } } } } From 999bfd3569cda99c1b705a4cd93ea803649c856b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 18 Apr 2021 09:19:59 -0400 Subject: [PATCH 163/458] Enforce server auth, ping on createClient, update docs (#68) * Add createServer, ping on createClient, update README * fix createClient keepalive * resort readme, fix node 14 * Enforce auth on server connections, fix close/connect issues * add type definitions, update readme, docs * Wait some time before closing connection, update docs * wait for server close in tests, fix race bug * export a ping api * Rename api.md to API.md * add ping example --- .npmignore | 8 ++- README.md | 123 +++++++++++++++++++++++++++----- docs/API.md | 115 +++++++++++++++++++++++++++++ docs/FAQ.md | 7 ++ docs/api.md | 16 ----- examples/clientReadmeExample.js | 17 +++++ examples/clientTest.js | 1 + examples/ping.js | 5 ++ examples/serverReadmeExample.js | 14 ++++ examples/serverTest.js | 38 +++++----- index.d.ts | 111 ++++++++++++++++++++++++++++ index.js | 3 +- src/auth/login.js | 2 +- src/auth/loginVerify.js | 9 ++- src/client.js | 56 +++++++++------ src/connection.js | 2 +- src/createClient.js | 81 ++++++++++++++------- src/createServer.js | 11 +++ src/rak.js | 4 +- src/server.js | 20 ++++-- src/server/advertisement.js | 17 ++++- src/serverPlayer.js | 27 +++---- test/internal.js | 15 ++-- test/internal.test.js | 10 +-- test/vanilla.js | 1 + test/vanilla.test.js | 2 +- tools/genPacketDumps.js | 2 +- tools/startVanillaServer.js | 2 +- types/Item.js | 2 + 29 files changed, 583 insertions(+), 138 deletions(-) create mode 100644 docs/API.md create mode 100644 docs/FAQ.md delete mode 100644 docs/api.md create mode 100644 examples/clientReadmeExample.js create mode 100644 examples/ping.js create mode 100644 examples/serverReadmeExample.js create mode 100644 index.d.ts create mode 100644 src/createServer.js diff --git a/.npmignore b/.npmignore index b512c09..a085593 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1,7 @@ -node_modules \ No newline at end of file +node_modules/ +npm-debug.log +__* +src/**/*.json +# Runtime generated data +data/**/sample +tools/bds* \ No newline at end of file diff --git a/README.md b/README.md index 3773432..02c816a 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,122 @@ -# bedrock-protocol +# Minecraft Bedrock protocol library [![NPM version](https://img.shields.io/npm/v/bedrock-protocol.svg)](http://npmjs.com/package/bedrock-protocol) [![Build Status](https://github.com/PrismarineJS/bedrock-protocol/workflows/CI/badge.svg)](https://github.com/PrismarineJS/bedrock-protocol/actions?query=workflow%3A%22CI%22) [![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8) [![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/bedrock-protocol) -Not ready for prime time yet, check https://github.com/PrismarineJS/bedrock-protocol/projects/1 for progress -Parse and serialize Minecraft: Pocket Edition packets +Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication and encryption. Help [contribute](CONTRIBUTING.md). + +This is a work in progress. You can track the progress in https://github.com/PrismarineJS/bedrock-protocol/pull/34. ## Features - * Supports Minecraft Pocket Edition `1.0` - * Pure JavaScript - * Easily send and listen for any packet - * RakNet support through [node-raknet](https://github.com/mhsjlw/node-raknet) + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220 + - Parses and serialize all packets with JavaScript objects + - Send a packet by supplying fields as a JavaScript object + - Automatically respond to keep-alive packets + - Client + - Authentication and login + - Encryption + - Online mode servers + - [Ping a server for status](docs/API.md#beping-host-port---serveradvertisement) + - Server + - Autheticate clients with Xbox Live + - Ping status + - Automatically respond to keep-alive packets + + * Robust test coverage. + * Easily extend with many other PrismarineJS projects, world providers, and more + * Optimized for rapidly staying up to date with Minecraft protocol updates. + + +Want to contribute on something important for PrismarineJS ? go to https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects ## Installation -Simply run - npm install bedrock-protocol +`npm install bedrock-protocol` -Then view our `examples` for inspiration! +## Usage -## Contributors -This project is run by these guys: +### Client example - - [mhsjlw](https://github.com/mhsjlw) - - [rom1504](https://github.com/rom1504) - - [Filiph Sandström](https://github.com/filfat) +```js +const bedrock = require('bedrock-protocol') +const client = bedrock.createClient({ + host: 'localhost', // optional + port: 19132, // optional, default 19132 + username: 'Notch', // the username you want to join as, optional if online mode + offline: true // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. +}) -## License -Licensed under the MIT license. +client.on('text', (packet) => { // Listen for chat messages and echo them back. + if (packet.source_name != client.options.username) { + client.queue('text', { + type: 'chat', needs_translation: false, source_name: client.username, xuid: '', platform_chat_id: '', + message: `${packet.source_name} said: ${packet.message} on ${new Date().toLocaleString()}` + }) + } +}) +``` + +### Server example + +*Can't connect locally on Windows? See the [faq](docs/FAQ.md)* +```js +const bedrock = require('bedrock-protocol') +const server = new bedrock.createServer({ + host: '0.0.0.0', // optional. Hostname to bind as. + port: 19132, // optional + version: '1.16.220' // optional. The server version, latest if not specified. +}) + +server.on('connect', client => { + client.on('join', () => { // The client has joined the server. + const d = new Date() // Once client is in the server, send a colorful kick message + client.disconnect(`Good ${d.getHours() < 12 ? '§emorning§r' : '§3afternoon§r'} :)\n\nMy time is ${d.toLocaleString()} !`) + }) +}) +``` + +### Ping example + +```js +const { ping } = require('bedrock-protocol') +ping({ host: 'play.cubecraft.net', port: 19132 }).then(res => { + console.log(res) +}) +``` + +## Documentation + +See [API documentation](docs/API.md) + +See [faq](docs/FAQ.md) + + + +## Testing + +```npm test``` + +## Debugging + +You can enable some protocol debugging output using `DEBUG` environment variable. + +Through node.js, add `process.env.DEBUG = 'minecraft-protocol'` at the top of your script. + +## Contribute + +Please read [CONTRIBUTING.md](CONTRIBUTING.md) and https://github.com/PrismarineJS/prismarine-contribute + +## History + +See [history](HISTORY.md) + + \ No newline at end of file diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..dac0dab --- /dev/null +++ b/docs/API.md @@ -0,0 +1,115 @@ +# Documentation + +## be.createClient(options) : Client + +Returns a `Client` instance and connects to the server. + +`options` is an object containing the properties : + +| Paramater | Optionality | Description | +| ----------- | ----------- |-| +| host | **Required** | Hostname to connect to, for example `127.0.0.1`. | +| port | *optional* | port to connect to, default to **19132** | +| version | *optional* | Version to connect as.
(Future feature, see [#69][1]) If not specified, should automatically match server version.
(Current feature) Defaults to latest version. | +| offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth. | +| username | Conditional | Required if `offline` set to true : Username to connect to server as. | +| connectTimeout | *optional* | default to **9000ms**. How long to wait in milliseconds while trying to connect to server. | +| onMsaCode | *optional* | Callback called when signing in with a microsoft account with device code auth, `data` is an object documented [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code#device-authorization-response) | +| autoInitPlayer | optional | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | + + +## be.createServer(options) : Server + +Returns a `Server` instance and starts listening for clients. All clients will be +authenticated unless offline is set to true. + +`options` is an object containing the properties : + +| Paramater | Optionality | Description | +| ----------- | ----------- |-| +| host | **Required** | The hostname to bind to. use `0.0.0.0` to bind all IPv4 addresses. | +| port | *optional* | the port to bind to, default **19132** | +| version | *optional* | Version to run server as. Clients below this version will be kicked, clients above will still be permitted. | +| offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth enforcement. | +| maxPlayers | *[Future][1]* | default to **3**. Set this to change the maximum number of players connected. | +| kickTimeout | *[Future][1]* | How long to wait before kicking a unresponsive client. | +| motd | *[Future][1]* | ServerAdvertisement instance. The server advertisment shown to clients, including the message of the day, level name. | +| advertismentFn | *[Future][1]* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | + +## be.ping({ host, port }) : ServerAdvertisement + +Ping a server and get the response. See type definitions for the structure. + +## Methods + +[See the type defintions for this library for more information on methods.](../index.d.ts) + +Both Client and Server classes have `write(name, params)` and `queue(name, params)` methods. The former sends a packet immediately, and the latter queues them to be sent in the next packet batch. Prefer the latter for better performance and less blocking. + +You can use `.close()` to terminate a connection, and `.disconnect(reason)` to gracefully kick a connected client. + +## Server usage + +You can create a server as such: +```js +const bedrock = require('bedrock-protocol') +const server = bedrock.createServer({ + host: '0.0.0.0', // the hostname to bind to, use '0.0.0.0' to bind all hostnames + port: 19132, // optional, port to bind to, default 19132 + offline: false // default false. verify connections with XBL +}) +``` + +Then you can listen for clients and their events: +```js +// The 'connect' event is emitted after a new client has started a connection with the server and is handshaking. +// Its one paramater is the client class instance which handles this session from here on out. +server.on('connect', (client) => { + // 'join' is emitted after the client has authenticated & connection is now encrypted. + client.on('join', () => { + // Then we can continue with the server spawning sequence. See examples/serverTest.js for an example spawn sequence. + }) +}) + +``` + +Order of server client event emisions: +* 'connect' - emitted by `Server` after a client first joins the server. Second paramater is a `ServerPlayer` instance. +* 'login' - emitted by client after the client has been authenticated by the server +* 'join' - the client is ready to recieve game packets after successful server-client handshake/encryption +* 'spawn' - emitted after the client lets the server know that it has successfully spawned + +## Client docs + +You can create a server as such: +```js +const bedrock = require('bedrock-protocol') +const client = bedrock.createClient({ + host: '127.0.0.1', // the hostname to bind to, use '0.0.0.0' to bind all hostnames + port: 19132, // optional, port to bind to, default 19132 + username: 'Notch' // Any profile name, only used internally for account caching. You'll + // be asked to sign-in with Xbox Live the first time. +}) +``` + +```js +// The 'join' event is emitted after the player has authenticated +// and is ready to recieve chunks and start game packets +client.on('join', client => console.log('Player has joined!')) + +// The 'spawn' event is emitted. The chunks have been sent and all is well. +client.on('join', client => console.log('Player has spawned!')) + +// We can listen for text packets. See proto.yml for documentation. +client.on('text', (packet) => { + console.log('Client got text packet', packet) +}) +``` + +Order of client event emisions: +* 'connect' - emitted after a client first joins the server +* 'login' - emitted after the client has been authenticated by the server +* 'join' - the client is ready to recieve game packets after successful server-client handshake +* 'spawn' - emitted after the client has permission from the server to spawn + +[1]: https://github.com/PrismarineJS/bedrock-protocol/issues/69 diff --git a/docs/FAQ.md b/docs/FAQ.md new file mode 100644 index 0000000..c4a5f06 --- /dev/null +++ b/docs/FAQ.md @@ -0,0 +1,7 @@ +## Can’t connect to localhost Win10 server with Minecraft Win10 Edition + +This issue occurs due to loopback restrictions on Windows 10 UWP apps. To lift this restriction, launch Windows PowerShell as an administrator and run the following: + +```ps +CheckNetIsolation LoopbackExempt -a -n="Microsoft.MinecraftUWP_8wekyb3d8bbwe" +``` \ No newline at end of file diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index f5f6564..0000000 --- a/docs/api.md +++ /dev/null @@ -1,16 +0,0 @@ -# Documentation - -## be.createClient(options) - -Returns a `Client` instance and starts listening. All clients will be -automatically logged in and validated against microsoft's auth. - -`options` is an object containing the properties : - * host : default to undefined which means listen to all available ipv4 and ipv6 adresses - * port (optional) : default to 25565 - (see https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback for details) - * kickTimeout (optional) : default to `10*1000` (10s), kick client that doesn't answer to keepalive after that time - * version (optional) : default to latest stable version, version of server - * autoInitPlayer (optional) : default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. - * offline (optional) : default to false, whether to auth with microsoft - * connectTimeout (optional) : default to 9000, ms to wait before aborting connection attempt diff --git a/examples/clientReadmeExample.js b/examples/clientReadmeExample.js new file mode 100644 index 0000000..32cffaf --- /dev/null +++ b/examples/clientReadmeExample.js @@ -0,0 +1,17 @@ +/* eslint-disable */ +const bedrock = require('bedrock-protocol') +const client = bedrock.createClient({ + host: 'localhost', // optional + port: 19132, // optional, default 19132 + username: 'Notch', // the username you want to join as, optional if online mode + offline: false // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. +}) + +client.on('text', (packet) => { // Listen for chat messages and echo them back. + if (packet.source_name != client.options.username) { + client.queue('text', { + type: 'chat', needs_translation: false, source_name: client.username, xuid: '', platform_chat_id: '', + message: `${packet.source_name} said: ${packet.message} on ${new Date().toLocaleString()}` + }) + } +}) \ No newline at end of file diff --git a/examples/clientTest.js b/examples/clientTest.js index bcb644e..717a428 100644 --- a/examples/clientTest.js +++ b/examples/clientTest.js @@ -9,6 +9,7 @@ async function test () { // You can specify version by adding : // version: '1.16.210' }) + client.connect() client.once('resource_packs_info', (packet) => { client.write('resource_pack_client_response', { diff --git a/examples/ping.js b/examples/ping.js new file mode 100644 index 0000000..5545cd5 --- /dev/null +++ b/examples/ping.js @@ -0,0 +1,5 @@ +const { ping } = require('bedrock-protocol') + +ping({ host: 'play.cubecraft.net', port: 19132 }).then(res => { + console.log(res) +}) diff --git a/examples/serverReadmeExample.js b/examples/serverReadmeExample.js new file mode 100644 index 0000000..95f4925 --- /dev/null +++ b/examples/serverReadmeExample.js @@ -0,0 +1,14 @@ +/* eslint-disable */ +const bedrock = require('bedrock-protocol') +const server = new bedrock.createServer({ + host: '0.0.0.0', // optional + port: 19132, // optional + version: '1.16.220' // The server version +}) + +server.on('connect', client => { + client.on('join', () => { // The client has joined the server. + const d = new Date() // Once client is in the server, send a colorful kick message + client.disconnect(`Good ${d.getHours() < 12 ? '§emorning§r' : '§3afternoon§r'} :)\n\nMy time is ${d.toLocaleString()} !`) + }) +}) \ No newline at end of file diff --git a/examples/serverTest.js b/examples/serverTest.js index c060954..a704dfd 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -71,25 +71,25 @@ async function startServer (version = '1.16.210', ok) { client.queue('inventory_slot', { window_id: 120, slot: 0, item: new Item().toBedrock() }) } - client.write('player_list', get('player_list')) - client.write('start_game', get('start_game')) - client.write('item_component', { entries: [] }) - client.write('set_spawn_position', get('set_spawn_position')) - client.write('set_time', { time: 5433771 }) - client.write('set_difficulty', { difficulty: 1 }) - client.write('set_commands_enabled', { enabled: true }) - client.write('adventure_settings', get('adventure_settings')) - client.write('biome_definition_list', get('biome_definition_list')) - client.write('available_entity_identifiers', get('available_entity_identifiers')) - client.write('update_attributes', get('update_attributes')) - client.write('creative_content', get('creative_content')) - client.write('inventory_content', get('inventory_content')) - client.write('player_hotbar', { selected_slot: 3, window_id: 'inventory', select_slot: true }) - client.write('crafting_data', get('crafting_data')) - client.write('available_commands', get('available_commands')) - client.write('chunk_radius_update', { chunk_radius: 1 }) - client.write('game_rules_changed', get('game_rules_changed')) - client.write('respawn', get('respawn')) + client.queue('player_list', get('player_list')) + client.queue('start_game', get('start_game')) + client.queue('item_component', { entries: [] }) + client.queue('set_spawn_position', get('set_spawn_position')) + client.queue('set_time', { time: 5433771 }) + client.queue('set_difficulty', { difficulty: 1 }) + client.queue('set_commands_enabled', { enabled: true }) + client.queue('adventure_settings', get('adventure_settings')) + client.queue('biome_definition_list', get('biome_definition_list')) + client.queue('available_entity_identifiers', get('available_entity_identifiers')) + client.queue('update_attributes', get('update_attributes')) + client.queue('creative_content', get('creative_content')) + client.queue('inventory_content', get('inventory_content')) + client.queue('player_hotbar', { selected_slot: 3, window_id: 'inventory', select_slot: true }) + client.queue('crafting_data', get('crafting_data')) + client.queue('available_commands', get('available_commands')) + client.queue('chunk_radius_update', { chunk_radius: 1 }) + client.queue('game_rules_changed', get('game_rules_changed')) + client.queue('respawn', get('respawn')) for (const chunk of chunks) { client.queue('level_chunk', chunk) diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..705e2ad --- /dev/null +++ b/index.d.ts @@ -0,0 +1,111 @@ +import EventEmitter from "events" + +declare module "bedrock-protocol" { + type Version = '1.16.220' | '1.16.210' | '1.16.201' + + export interface Options { + // The string version to start the client or server as + version: number, + // For the client, the hostname of the server to connect to (default: 127.0.0.1) + // For the server, the hostname to bind to (default: 0.0.0.0) + host: string, + // The port to connect or bind to, default: 19132 + port: number + } + + enum ClientStatus { + Disconected, Authenticating, Initializing, Initialized + } + + export class Connection extends EventEmitter { + readonly status: ClientStatus + + // Check if the passed version is less than or greater than the current connected client version. + versionLessThan(version: string | number) + versionGreaterThan(version: string | number) + + // Writes a Minecraft bedrock packet and sends it without queue batching + write(name: string, params: object) + // Adds a Minecraft bedrock packet to be sent in the next outgoing batch + queue(name: string, params: object) + // Writes a MCPE buffer to the connection and skips Protodef serialization. `immediate` if skip queue. + sendBuffer(buffer: Buffer, immediate?: boolean) + } + + type PlayStatus = + | 'login_success' + // # Displays "Could not connect: Outdated client!" + | 'failed_client' + // # Displays "Could not connect: Outdated server!" + | 'failed_spawn' + // # Sent after world data to spawn the player + | 'player_spawn' + // # Displays "Unable to connect to world. Your school does not have access to this server." + | 'failed_invalid_tenant' + // # Displays "The server is not running Minecraft: Education Edition. Failed to connect." + | 'failed_vanilla_edu' + // # Displays "The server is running an incompatible edition of Minecraft. Failed to connect." + | 'failed_edu_vanilla' + // # Displays "Wow this server is popular! Check back later to see if space opens up. Server Full" + | 'failed_server_full' + + + export class Client extends Connection { + constructor(options: Options) + // The client's EntityID returned by the server + readonly entityId: BigInt + + /** + * Close the connection, leave the server. + */ + close() + } + + /** + * `Player` represents a player connected to the server. + */ + export class Player extends Connection { + /** + * Disconnects a client before it has logged in via a PlayStatus packet. + * @param {string} playStatus + */ + sendDisconnectStatus(playStatus: PlayStatus) + + /** + * Disconnects a client + * @param reason The message to be shown to the user on disconnect + * @param hide Don't show the client the reason for the disconnect + */ + disconnect(reason: string, hide?: boolean) + + /** + * Close the connection. Already called by disconnect. Call this to manually close RakNet connection. + */ + close() + } + + export class Server extends EventEmitter { + clients: Map + constructor(options: Options) + // Disconnects all currently connected clients + close(disconnectReason: string) + } + + class ServerAdvertisement { + motd: string + name: string + protocol: number + version: string + players: { + online: number, + max: number + } + gamemode: string + serverId: string + } + + export function createClient(options: Options): Client + export function createServer(options: Options): Server + + export function ping({ host, port }) : ServerAdvertisement +} \ No newline at end of file diff --git a/index.js b/index.js index d6ba9b1..834f737 100644 --- a/index.js +++ b/index.js @@ -3,5 +3,6 @@ module.exports = { ...require('./src/server'), ...require('./src/serverPlayer'), ...require('./src/relay'), - ...require('./src/createClient') + ...require('./src/createClient'), + ...require('./src/createServer') } diff --git a/src/auth/login.js b/src/auth/login.js index 49913b4..d835326 100644 --- a/src/auth/login.js +++ b/src/auth/login.js @@ -65,7 +65,7 @@ module.exports = (client, server, options) => { // inside of PlayFab. PlayFabId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', // 1.16.210 PremiumSkin: false, - SelfSignedId: '78eb38a6-950e-3ab9-b2cf-dd849e343702', + SelfSignedId: nextUUID(), ServerAddress: `${options.hostname}:${options.port}`, SkinAnimationData: '', SkinColor: '#ffffcd96', diff --git a/src/auth/loginVerify.js b/src/auth/loginVerify.js index 0809269..233e729 100644 --- a/src/auth/loginVerify.js +++ b/src/auth/loginVerify.js @@ -14,7 +14,7 @@ module.exports = (client, server, options) => { // from Xbox with addition user profile data // We verify that at least one of the tokens in the chain has been properly // signed by Mojang by checking the x509 public key in the JWT headers - // let didVerify = false + let didVerify = false let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it let finalKey = null @@ -26,17 +26,20 @@ module.exports = (client, server, options) => { // Check if signed by Mojang key const x5u = getX5U(token) if (x5u === constants.PUBLIC_KEY && !data.extraData?.XUID) { - // didVerify = true + didVerify = true debug('Verified client with mojang key', x5u) } - // TODO: Handle `didVerify` = false pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u finalKey = decoded.identityPublicKey || finalKey // non pem data = { ...data, ...decoded } } // console.log('Result', data) + if (!didVerify && !options.offline) { + client.disconnect('disconnectionScreen.notAuthenticated') + } + return { key: finalKey, data } } diff --git a/src/client.js b/src/client.js index 2fb3ce1..83dcb7c 100644 --- a/src/client.js +++ b/src/client.js @@ -29,25 +29,30 @@ class Client extends Connection { Login(this, null, this.options) LoginVerify(this, null, this.options) - this.on('session', this.connect) - - if (options.offline) { - console.debug('offline mode, not authenticating', this.options) - auth.createOfflineSession(this, this.options) - } else if (options.password) { - auth.authenticatePassword(this, this.options) - } else { - auth.authenticateDeviceCode(this, this.options) - } + const hostname = this.options.hostname + const port = this.options.port + this.connection = new RakClient({ useWorkers: true, hostname, port }) this.startGameData = {} this.clientRuntimeId = null - this.startQueue() this.inLog = (...args) => debug('C ->', ...args) this.outLog = (...args) => debug('C <-', ...args) } + connect () { + this.on('session', this._connect) + + if (this.options.offline) { + console.debug('offline mode, not authenticating', this.options) + auth.createOfflineSession(this, this.options) + } else { + auth.authenticateDeviceCode(this, this.options) + } + + this.startQueue() + } + validateOptions () { if (!this.options.hostname || this.options.port == null) throw Error('Invalid hostname/port') @@ -70,18 +75,23 @@ class Client extends Connection { this.handle(buffer) } - connect = async (sessionData) => { - const hostname = this.options.hostname - const port = this.options.port - debug('[client] connecting to', hostname, port, sessionData) + async ping () { + try { + return await this.connection.ping(this.options.connectTimeout) + } catch (e) { + console.warn(`Unable to connect to [${this.options.hostname}]/${this.options.port}. Is the server running?`) + throw e + } + } - this.connection = new RakClient({ useWorkers: true, hostname, port }) + _connect = async (sessionData) => { + debug('[client] connecting to', this.options.hostname, this.options.port, sessionData, this.connection) this.connection.onConnected = () => this.sendLogin() this.connection.onCloseConnection = () => this.close() this.connection.onEncapsulated = this.onEncapsulated this.connection.connect() - this.connectTimer = setTimeout(() => { + this.connectTimeout = setTimeout(() => { if (this.status === ClientStatus.Disconnected) { this.connection.close() this.emit('error', 'connect timed out') @@ -115,6 +125,7 @@ class Client extends Connection { onDisconnectRequest (packet) { console.warn(`C Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) this.emit('kick', packet) + this.close() } onPlayStatus (statusPacket) { @@ -128,21 +139,24 @@ class Client extends Connection { } close () { - this.emit('close') + if (this.status !== ClientStatus.Disconnected) { + this.emit('close') // Emit close once + console.log('Client closed!') + } clearInterval(this.loop) clearTimeout(this.connectTimeout) this.q = [] this.q2 = [] this.connection?.close() this.removeAllListeners() - console.log('Client closed!') + this.status = ClientStatus.Disconnected } tryRencode (name, params, actual) { const packet = this.serializer.createPacketBuffer({ name, params }) - console.assert(packet.toString('hex') === actual.toString('hex')) - if (packet.toString('hex') !== actual.toString('hex')) { + console.assert(packet.equals(actual)) + if (!packet.equals(actual)) { const ours = packet.toString('hex').match(/.{1,16}/g).join('\n') const theirs = actual.toString('hex').match(/.{1,16}/g).join('\n') diff --git a/src/connection.js b/src/connection.js index a13872a..0b0a28c 100644 --- a/src/connection.js +++ b/src/connection.js @@ -75,7 +75,7 @@ class Connection extends EventEmitter { if (this.q.length) { // TODO: can we just build Batch before the queue loop? const batch = new BatchPacket() - this.outLog('<- BATCH', this.q2) + this.outLog('<- Batch', this.q2) const sending = [] for (let i = 0; i < this.q.length; i++) { const packet = this.q.shift() diff --git a/src/createClient.js b/src/createClient.js index 612fd48..e357627 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -1,45 +1,76 @@ const { Client } = require('./client') +const { RakClient } = require('./rak') const assert = require('assert') +const advertisement = require('./server/advertisement') -module.exports = { createClient } - -/** @param {{ version?: number, hostname: string, port?: number }} options */ +/** @param {{ version?: number, hostname: string, port?: number, connectTimeout?: number }} options */ function createClient (options) { - assert(options && options.hostname) + assert(options) + if (options.host) options.hostname = options.host const client = new Client({ port: 19132, ...options }) - client.once('resource_packs_info', (packet) => { - handleResourcePackInfo(client) - disableClientCache(client) - handleRenderDistance(client) - handleTickSync(client) - }) + if (options.skipPing) { + connect(client) + } else { // Try to ping + client.ping().then(data => { + const advert = advertisement.fromServerName(data) + console.log(`Connecting to server ${advert.motd} (${advert.name}), version ${advert.version}`) + // TODO: update connect version based on ping response + connect(client) + }, client) + } return client } -function handleResourcePackInfo (client) { - client.write('resource_pack_client_response', { - response_status: 'completed', - resourcepackids: [] - }) +function connect (client) { + // Actually connect + client.connect() - client.once('resource_pack_stack', (stack) => { + client.once('resource_packs_info', (packet) => { client.write('resource_pack_client_response', { response_status: 'completed', resourcepackids: [] }) + + client.once('resource_pack_stack', (stack) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] + }) + }) + + client.queue('client_cache_status', { enabled: false }) + client.queue('request_chunk_radius', { chunk_radius: client.renderDistance || 1 }) + client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + }) + + const KEEPALIVE_INTERVAL = 10 // Send tick sync packets every 10 ticks + let keepalive + client.tick = 0n + client.once('spawn', () => { + keepalive = setInterval(() => { + // Client fills out the request_time and the server does response_time in its reply. + client.queue('tick_sync', { request_time: client.tick, response_time: 0n }) + client.tick += BigInt(KEEPALIVE_INTERVAL) + }, 50 * KEEPALIVE_INTERVAL) + + client.on('tick_sync', async packet => { + client.emit('heartbeat', packet.response_time) + client.tick = packet.response_time + }) + }) + + client.once('close', () => { + clearInterval(keepalive) }) } -function handleRenderDistance (client) { - client.queue('request_chunk_radius', { chunk_radius: 1 }) +async function ping ({ host, port }) { + const con = new RakClient({ hostname: host, port }) + const ret = await con.ping() + con.close() + return advertisement.fromServerName(ret) } -function disableClientCache (client) { - client.queue('client_cache_status', { enabled: false }) -} - -function handleTickSync (client) { - client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) -} +module.exports = { createClient, ping } diff --git a/src/createServer.js b/src/createServer.js new file mode 100644 index 0000000..3c6762c --- /dev/null +++ b/src/createServer.js @@ -0,0 +1,11 @@ +const { Server } = require('./server') + +function createServer (options) { + if (options.host) options.hostname = options.host + if (!options.port) options.port = 19132 + const server = new Server(options) + server.listen() + return server +} + +module.exports = { createServer } diff --git a/src/rak.js b/src/rak.js index 912df2d..7d922c7 100644 --- a/src/rak.js +++ b/src/rak.js @@ -36,7 +36,7 @@ class RakNativeClient extends EventEmitter { }) } - async ping () { + async ping (timeout = 1000) { this.raknet.ping() return waitFor((done) => { this.raknet.on('pong', (ret) => { @@ -44,7 +44,7 @@ class RakNativeClient extends EventEmitter { done(ret.extra.toString()) } }) - }, 1000) + }, timeout, () => { throw new Error('Ping timed out') }) } connect () { diff --git a/src/server.js b/src/server.js index c2dcdf7..b027b73 100644 --- a/src/server.js +++ b/src/server.js @@ -2,6 +2,7 @@ const { EventEmitter } = require('events') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { Player } = require('./serverPlayer') const { RakServer } = require('./rak') +const { sleep } = require('./datatypes/util') const Options = require('./options') const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol') @@ -31,7 +32,7 @@ class Server extends EventEmitter { } onOpenConnection = (conn) => { - this.inLog('new connection', conn) + console.debug('new connection', conn?.address) const player = new Player(this, conn) this.clients[conn.address] = player this.clientCount++ @@ -39,7 +40,7 @@ class Server extends EventEmitter { } onCloseConnection = (inetAddr, reason) => { - console.debug('close connection', inetAddr, reason) + console.debug('close connection', inetAddr?.address, reason) delete this.clients[inetAddr]?.connection // Prevent close loop this.clients[inetAddr]?.close() delete this.clients[inetAddr] @@ -57,7 +58,12 @@ class Server extends EventEmitter { async listen (hostname = this.options.hostname, port = this.options.port) { this.raknet = new RakServer({ hostname, port }) - await this.raknet.listen() + try { + await this.raknet.listen() + } catch (e) { + console.warn(`Failed to bind server on [${this.options.hostname}]/${this.options.port}, is the port free?`) + throw e + } console.debug('Listening on', hostname, port) this.raknet.onOpenConnection = this.onOpenConnection this.raknet.onCloseConnection = this.onCloseConnection @@ -65,14 +71,18 @@ class Server extends EventEmitter { return { hostname, port } } - close (disconnectReason) { + async close (disconnectReason) { for (const caddr in this.clients) { const client = this.clients[caddr] client.disconnect(disconnectReason) } - this.raknet.close() + this.clients = {} this.clientCount = 0 + + // Allow some time for client to get disconnect before closing connection. + await sleep(60) + this.raknet.close() } } diff --git a/src/server/advertisement.js b/src/server/advertisement.js index 0b9a401..978008d 100644 --- a/src/server/advertisement.js +++ b/src/server/advertisement.js @@ -1,8 +1,10 @@ +const { Versions, CURRENT_VERSION } = require('../options') + class ServerName { motd = 'Bedrock Protocol Server' name = 'bedrock-protocol' - protocol = 408 - version = '1.16.20' + protocol = Versions[CURRENT_VERSION] + version = CURRENT_VERSION players = { online: 0, max: 5 @@ -11,6 +13,14 @@ class ServerName { gamemode = 'Creative' serverId = '0' + fromString (str) { + const [header, motd, protocol, version, playersOnline, playersMax, serverId, name, gamemode] = str.split(';') + if (playersOnline) this.players.online = playersOnline + if (playersMax) this.players.max = playersMax + Object.assign(this, { header, motd, protocol, version, serverId, name, gamemode }) + return this + } + toString (version) { return [ 'MCPE', @@ -35,5 +45,8 @@ module.exports = { ServerName, getServerName (client) { return new ServerName().toBuffer() + }, + fromServerName (string) { + return new ServerName().fromString(string) } } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index d2a6d93..5024a9a 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -38,7 +38,7 @@ class Player extends Connection { const clientVer = body.protocol_version if (this.server.options.protocolVersion) { if (this.server.options.protocolVersion < clientVer) { - this.sendDisconnectStatus('failed_client') + this.sendDisconnectStatus('failed_spawn') return } } else if (clientVer < Options.MIN_VERSION) { @@ -76,23 +76,22 @@ class Player extends Connection { * @param {string} playStatus */ sendDisconnectStatus (playStatus) { + if (this.status === ClientStatus.Disconnected) return this.write('play_status', { status: playStatus }) - this.close() + this.close('kick') } /** * Disconnects a client */ disconnect (reason = 'Server closed', hide = false) { - if ([ClientStatus.Authenticating, ClientStatus.Initializing].includes(this.status)) { - this.sendDisconnectStatus('failed_server_full') - } else { - this.write('disconnect', { - hide_disconnect_screen: hide, - message: reason - }) - } - this.close() + if (this.status === ClientStatus.Disconnected) return + this.write('disconnect', { + hide_disconnect_screen: hide, + message: reason + }) + console.debug('Kicked ', this.connection?.address, reason) + setTimeout(() => this.close('kick'), 100) // Allow time for message to be recieved. } // After sending Server to Client Handshake, this handles the client's @@ -105,7 +104,11 @@ class Player extends Connection { this.emit('join') } - close () { + close (reason) { + if (this.status !== ClientStatus.Disconnected) { + this.emit('close') // Emit close once + if (!reason) console.trace('Client closed connection', this.connection?.address) + } this.q = [] this.q2 = [] clearInterval(this.loop) diff --git a/test/internal.js b/test/internal.js index 09b184b..b811588 100644 --- a/test/internal.js +++ b/test/internal.js @@ -2,6 +2,7 @@ const { Server, Client } = require('../') const { dumpPackets } = require('../tools/genPacketDumps') const DataProvider = require('../data/provider') +const { ping } = require('../src/createClient') // First we need to dump some packets that a vanilla server would send a vanilla // client. Then we can replay those back in our custom server. @@ -9,11 +10,11 @@ function prepare (version) { return dumpPackets(version) } -async function startTest (version = '1.16.201', ok) { +async function startTest (version = '1.16.220', ok) { await prepare(version) const Item = require('../types/Item')(version) const port = 19130 - const server = new Server({ hostname: '0.0.0.0', port, version }) + const server = new Server({ hostname: '0.0.0.0', port, version, offline: true }) function getPath (packetPath) { return DataProvider(server.options.protocolVersion).getPath(packetPath) @@ -26,6 +27,9 @@ async function startTest (version = '1.16.201', ok) { server.listen() console.log('Started server') + const pongData = await ping({ host: '127.0.0.1', port }) + console.assert(pongData, 'did not get valid pong data from server') + const respawnPacket = get('packets/respawn.json') const chunks = await requestChunks(respawnPacket.x, respawnPacket.z, 1) @@ -136,11 +140,14 @@ async function startTest (version = '1.16.201', ok) { setTimeout(() => { client.close() - server.close() - ok?.() + server.close().then(() => { + ok?.() + }) }, 500) clearInterval(loop) }) + + client.connect() } const { ChunkColumn, Version } = require('bedrock-provider') diff --git a/test/internal.test.js b/test/internal.test.js index 3f37b17..c75ad3f 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -4,12 +4,12 @@ const { timedTest } = require('./internal') const { Versions } = require('../src/options') describe('internal client/server test', function () { - this.timeout(120 * 1000) + this.timeout(220 * 1000) - it('connects', async () => { - for (const version in Versions) { + for (const version in Versions) { + it('connects ' + version, async () => { console.debug(version) await timedTest(version) - } - }) + }) + } }) diff --git a/test/vanilla.js b/test/vanilla.js index 3d7c11a..6970a6c 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -19,6 +19,7 @@ async function test (version) { }) console.log('Started client') + client.connect() let loop diff --git a/test/vanilla.test.js b/test/vanilla.test.js index 252de3b..2670223 100644 --- a/test/vanilla.test.js +++ b/test/vanilla.test.js @@ -4,7 +4,7 @@ const { clientTest } = require('./vanilla') const { Versions } = require('../src/options') describe('vanilla server test', function () { - this.timeout(120 * 1000) + this.timeout(220 * 1000) for (const version in Versions) { it('client spawns ' + version, async () => { diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index d91dc54..94a718b 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -31,7 +31,7 @@ async function dump (version, force) { username: 'Boat' + random, offline: true }) - + client.connect() return waitFor(async res => { const root = join(__dirname, `../data/${client.options.version}/sample/`) if (!fs.existsSync(root + 'packets') || !fs.existsSync(root + 'chunks')) { diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 169f3f7..32d0e0a 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -108,7 +108,7 @@ async function startServerAndWait (version, withTimeout, options) { if (!module.parent) { // if (process.argv.length < 3) throw Error('Missing version argument') - startServer(process.argv[2] || '1.16.201', null, process.argv[3] ? { 'server-port': process.argv[3] } : undefined) + startServer(process.argv[2] || '1.16.201', null, process.argv[3] ? { 'server-port': process.argv[3], 'online-mode': !!process.argv[4] } : undefined) } module.exports = { fetchLatestStable, startServer, startServerAndWait } diff --git a/types/Item.js b/types/Item.js index 1153308..123ceb4 100644 --- a/types/Item.js +++ b/types/Item.js @@ -37,6 +37,8 @@ module.exports = (version) => network_id: this.networkId, count: this.count, metadata: this.metadata, + has_stack_id: this.stackId, + stack_id: this.stackId, extra: { has_nbt: !!this.nbt, nbt: { version: 1, nbt: this.nbt }, From 72637915814e2837c2d5e430c5d256d91ab20801 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 18 Apr 2021 16:43:39 -0400 Subject: [PATCH 164/458] Async batching --- package.json | 1 - src/connection.js | 68 ++++++++++++------------------- src/datatypes/BatchPacket.js | 77 ------------------------------------ src/transforms/framer.js | 76 +++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 120 deletions(-) delete mode 100644 src/datatypes/BatchPacket.js create mode 100644 src/transforms/framer.js diff --git a/package.json b/package.json index cea9e9d..ae9b91d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "license": "MIT", "dependencies": { "@azure/msal-node": "^1.0.0-beta.6", - "@jsprismarine/jsbinaryutils": "^2.1.8", "@xboxreplay/xboxlive-auth": "^3.3.3", "asn1": "^0.2.4", "debug": "^4.3.1", diff --git a/src/connection.js b/src/connection.js index 0b0a28c..247dc0d 100644 --- a/src/connection.js +++ b/src/connection.js @@ -1,12 +1,9 @@ -const BinaryStream = require('@jsprismarine/jsbinaryutils').default -const BatchPacket = require('./datatypes/BatchPacket') +const Framer = require('./transforms/framer') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') const { Versions } = require('./options') const debug = require('debug')('minecraft-protocol') -const SKIP_BATCH = ['level_chunk', 'client_cache_blob_status', 'client_cache_miss_response'] - const ClientStatus = { Disconnected: 0, Authenticating: 1, // Handshaking @@ -16,8 +13,8 @@ const ClientStatus = { class Connection extends EventEmitter { #status = ClientStatus.Disconnected - q = [] - q2 = [] + sendQ = [] + sendIds = [] get status () { return this.#status @@ -41,12 +38,11 @@ class Connection extends EventEmitter { this.inLog('Started encryption', this.sharedSecret, iv) this.decrypt = cipher.createDecryptor(this, iv) this.encrypt = cipher.createEncryptor(this, iv) - this.q2 = [] } write (name, params) { this.outLog('sending', name, params) - const batch = new BatchPacket() + const batch = new Framer() const packet = this.serializer.createPacketBuffer({ name, params }) batch.addEncodedPacket(packet) @@ -60,29 +56,24 @@ class Connection extends EventEmitter { queue (name, params) { this.outLog('Q <- ', name, params) const packet = this.serializer.createPacketBuffer({ name, params }) - if (SKIP_BATCH.includes(name)) { + if (name === 'level_chunk') { // Skip queue, send ASAP this.sendBuffer(packet) return } - this.q.push(packet) - this.q2.push(name) + this.sendQ.push(packet) + this.sendIds.push(name) } startQueue () { - this.q = [] + this.sendQ = [] this.loop = setInterval(() => { - if (this.q.length) { - // TODO: can we just build Batch before the queue loop? - const batch = new BatchPacket() - this.outLog('<- Batch', this.q2) - const sending = [] - for (let i = 0; i < this.q.length; i++) { - const packet = this.q.shift() - sending.push(this.q2.shift()) - batch.addEncodedPacket(packet) - } - // this.outLog('~~ Sending', sending) + if (this.sendQ.length) { + const batch = new Framer() + this.outLog('<- Batch', this.sendIds) + batch.addEncodedPackets(this.sendQ) + this.sendQ = [] + this.sendIds = [] if (this.encryptionEnabled) { this.sendEncryptedBatch(batch) } else { @@ -97,7 +88,7 @@ class Connection extends EventEmitter { */ sendBuffer (buffer, immediate = false) { if (immediate) { - const batch = new BatchPacket() + const batch = new Framer() batch.addEncodedPacket(buffer) if (this.encryptionEnabled) { this.sendEncryptedBatch(batch) @@ -105,24 +96,21 @@ class Connection extends EventEmitter { this.sendDecryptedBatch(batch) } } else { - this.q.push(buffer) - this.q2.push('rawBuffer') + this.sendQ.push(buffer) + this.sendIds.push('rawBuffer') } } sendDecryptedBatch (batch) { - const buf = batch.encode() // send to raknet - this.sendMCPE(buf, true) + batch.encode(buf => this.sendMCPE(buf, true)) } sendEncryptedBatch (batch) { - const buf = batch.stream.getBuffer() - // debug('Sending encrypted batch', batch) + const buf = batch.getBuffer() this.encrypt(buf) } - // TODO: Rename this to sendEncapsulated sendMCPE (buffer, immediate) { if (this.connection.connected === false || this.status === ClientStatus.Disconnected) return this.connection.sendReliable(buffer, immediate) @@ -133,13 +121,11 @@ class Connection extends EventEmitter { this.outLog('Enc buf', buf) const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header - // this.outLog('Sending wrapped encrypted batch', packet) this.sendMCPE(packet) } onDecryptedPacket = (buf) => { - const stream = new BinaryStream(buf) - const packets = BatchPacket.getPackets(stream) + const packets = Framer.getPackets(buf) for (const packet of packets) { this.readPacket(packet) @@ -151,14 +137,12 @@ class Connection extends EventEmitter { if (this.encryptionEnabled) { this.decrypt(buffer.slice(1)) } else { - const stream = new BinaryStream(buffer) - const batch = new BatchPacket(stream) - batch.decode() - const packets = batch.getPackets() - this.inLog('Reading ', packets.length, 'packets') - for (const packet of packets) { - this.readPacket(packet) - } + Framer.decode(buffer, packets => { + this.inLog('Reading ', packets.length, 'packets') + for (const packet of packets) { + this.readPacket(packet) + } + }) } } } diff --git a/src/datatypes/BatchPacket.js b/src/datatypes/BatchPacket.js deleted file mode 100644 index 8c1094c..0000000 --- a/src/datatypes/BatchPacket.js +++ /dev/null @@ -1,77 +0,0 @@ -const BinaryStream = require('@jsprismarine/jsbinaryutils').default -const Zlib = require('zlib') - -const NETWORK_ID = 0xfe - -// This is not a real MCPE packet, it's a wrapper that contains compressed/encrypted batched packets -class BatchPacket { - constructor (stream) { - // Shared - this.payload = Buffer.alloc(0) - this.stream = stream || new BinaryStream() - - // Decoding - this.packets = [] - - // Encoding - this.compressionLevel = 7 - this.count = 0 - } - - decode () { - // Read header - const pid = this.stream.readByte() - if (!pid === NETWORK_ID) { - throw new Error(`Batch ID mismatch: is ${BatchPacket.NETWORK_ID}, got ${pid}`) // this is not a BatchPacket - } - - // Decode the payload - try { - this.payload = Zlib.inflateRawSync(this.stream.readRemaining(), { - chunkSize: 1024 * 1024 * 2 - }) - } catch (e) { - console.error(e) - console.debug(`[bp] Error decompressing packet ${pid}`) - } - } - - encode () { - const buf = this.stream.getBuffer() - const def = Zlib.deflateRawSync(buf, { level: this.compressionLevel }) - const ret = Buffer.concat([Buffer.from([0xfe]), def]) - return ret - } - - addEncodedPacket (packet) { - this.stream.writeUnsignedVarInt(packet.byteLength) - this.stream.append(packet) - this.count++ - } - - getPackets () { - const stream = new BinaryStream() - stream.buffer = this.payload - const packets = [] - while (!stream.feof()) { - const length = stream.readUnsignedVarInt() - const buffer = stream.read(length) - packets.push(buffer) - } - - return packets - } - - static getPackets (stream) { - const packets = [] - while (!stream.feof()) { - const length = stream.readUnsignedVarInt() - const buffer = stream.read(length) - packets.push(buffer) - } - - return packets - } -} - -module.exports = BatchPacket diff --git a/src/transforms/framer.js b/src/transforms/framer.js new file mode 100644 index 0000000..7df557a --- /dev/null +++ b/src/transforms/framer.js @@ -0,0 +1,76 @@ +const [readVarInt, writeVarInt, sizeOfVarInt] = require('protodef').types.varint +const zlib = require('zlib') + +// Concatenates packets into one batch packet, and adds length prefixs. +class Framer { + constructor () { + // Decoding + this.packets = [] + this.compressionLevel = 7 + } + + static decode (buf, cb) { + // Read header + if (buf[0] !== 0xfe) throw Error('bad batch packet header ' + buf[0]) + + // Decode the payload + zlib.inflateRaw(buf.slice(1), { chunkSize: 1024 * 1024 * 2 }, (err, inflated) => { + if (err) { + throw err + // console.error(err) + } else cb(Framer.getPackets(inflated)) + }) + } + + encode (cb) { + const buf = Buffer.concat(this.packets) + zlib.deflateRaw(buf, { level: this.compressionLevel }, (err, def) => { + if (err) throw err + const ret = Buffer.concat([Buffer.from([0xfe]), def]) + cb(ret) + }) + } + + addEncodedPacket (chunk) { + const varIntSize = sizeOfVarInt(chunk.byteLength) + const buffer = Buffer.allocUnsafe(varIntSize + chunk.byteLength) + writeVarInt(chunk.length, buffer, 0) + chunk.copy(buffer, varIntSize) + this.packets.push(buffer) + } + + addEncodedPackets (packets) { + let allocSize = 0 + for (const packet of packets) { + allocSize += sizeOfVarInt(packet.byteLength) + allocSize += packet.byteLength + } + const buffer = Buffer.allocUnsafe(allocSize) + let offset = 0 + for (const chunk of packets) { + offset = writeVarInt(chunk.length, buffer, offset) + offset += chunk.copy(buffer, offset, 0) + } + + this.packets.push(buffer) + } + + getBuffer () { + return Buffer.concat(this.packets) + } + + static getPackets (buffer) { + const packets = [] + let offset = 0 + while (offset < buffer.byteLength) { + const { value, size } = readVarInt(buffer, offset) + const dec = Buffer.allocUnsafe(value) + offset += size + offset += buffer.copy(dec, 0, offset, offset + value) + packets.push(dec) + } + return packets + } +} + +module.exports = Framer From 1538c3fc03d5157f9112136419a8211e1987bf95 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 19 Apr 2021 00:19:36 -0400 Subject: [PATCH 165/458] Add server MOTD options --- README.md | 9 ++++----- docs/API.md | 28 +++++++++++++++++---------- examples/serverReadmeExample.js | 10 +++++++--- examples/serverTest.js | 4 ++-- index.d.ts | 11 ++++++++++- src/rak.js | 10 +++++++--- src/server.js | 21 ++++++++++++++++++-- src/server/advertisement.js | 34 ++++++++++++++++----------------- 8 files changed, 84 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 02c816a..dd18d0a 100644 --- a/README.md +++ b/README.md @@ -12,18 +12,15 @@ This is a work in progress. You can track the progress in https://github.com/Pri ## Features - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220 - - Parses and serialize all packets with JavaScript objects - - Send a packet by supplying fields as a JavaScript object + - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - Client - - Authentication and login + - Authentication - Encryption - - Online mode servers - [Ping a server for status](docs/API.md#beping-host-port---serveradvertisement) - Server - Autheticate clients with Xbox Live - Ping status - - Automatically respond to keep-alive packets * Robust test coverage. * Easily extend with many other PrismarineJS projects, world providers, and more @@ -89,6 +86,8 @@ ping({ host: 'play.cubecraft.net', port: 19132 }).then(res => { ## Documentation +For documentation on the protocol, and packets/fields see the [proto.yml](data/latest/proto.yml) and [types.yml](data/latest/proto.yml) files. + See [API documentation](docs/API.md) See [faq](docs/FAQ.md) diff --git a/docs/API.md b/docs/API.md index dac0dab..cf9939f 100644 --- a/docs/API.md +++ b/docs/API.md @@ -6,7 +6,7 @@ Returns a `Client` instance and connects to the server. `options` is an object containing the properties : -| Paramater | Optionality | Description | +| Parameter | Optionality | Description | | ----------- | ----------- |-| | host | **Required** | Hostname to connect to, for example `127.0.0.1`. | | port | *optional* | port to connect to, default to **19132** | @@ -15,6 +15,7 @@ Returns a `Client` instance and connects to the server. | username | Conditional | Required if `offline` set to true : Username to connect to server as. | | connectTimeout | *optional* | default to **9000ms**. How long to wait in milliseconds while trying to connect to server. | | onMsaCode | *optional* | Callback called when signing in with a microsoft account with device code auth, `data` is an object documented [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code#device-authorization-response) | +| profilesFolder | *optional* | Where to store cached authentication tokens. Defaults to .minecraft, or the node_modules folder if not found. | | autoInitPlayer | optional | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | @@ -25,16 +26,16 @@ authenticated unless offline is set to true. `options` is an object containing the properties : -| Paramater | Optionality | Description | +| Parameter | Optionality | Description | | ----------- | ----------- |-| | host | **Required** | The hostname to bind to. use `0.0.0.0` to bind all IPv4 addresses. | | port | *optional* | the port to bind to, default **19132** | | version | *optional* | Version to run server as. Clients below this version will be kicked, clients above will still be permitted. | | offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth enforcement. | -| maxPlayers | *[Future][1]* | default to **3**. Set this to change the maximum number of players connected. | +| maxPlayers | *optional* | default to **3**. Set this to change the maximum number of players connected. | | kickTimeout | *[Future][1]* | How long to wait before kicking a unresponsive client. | -| motd | *[Future][1]* | ServerAdvertisement instance. The server advertisment shown to clients, including the message of the day, level name. | -| advertismentFn | *[Future][1]* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | +| motd | *optional* | The "message of the day" for the server, the message shown to players in the server list. See usage below. | +| advertismentFn | *optional* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | ## be.ping({ host, port }) : ServerAdvertisement @@ -56,7 +57,11 @@ const bedrock = require('bedrock-protocol') const server = bedrock.createServer({ host: '0.0.0.0', // the hostname to bind to, use '0.0.0.0' to bind all hostnames port: 19132, // optional, port to bind to, default 19132 - offline: false // default false. verify connections with XBL + offline: false, // default false. verify connections with XBL + motd: { + name: 'Funtime Server', // Top level message shown in server list + levelName: 'Wonderland' // Sub-level header + } }) ``` @@ -73,7 +78,7 @@ server.on('connect', (client) => { ``` -Order of server client event emisions: +Order of server client event emissions: * 'connect' - emitted by `Server` after a client first joins the server. Second paramater is a `ServerPlayer` instance. * 'login' - emitted by client after the client has been authenticated by the server * 'join' - the client is ready to recieve game packets after successful server-client handshake/encryption @@ -87,8 +92,7 @@ const bedrock = require('bedrock-protocol') const client = bedrock.createClient({ host: '127.0.0.1', // the hostname to bind to, use '0.0.0.0' to bind all hostnames port: 19132, // optional, port to bind to, default 19132 - username: 'Notch' // Any profile name, only used internally for account caching. You'll - // be asked to sign-in with Xbox Live the first time. + username: 'Notch' // Any profile name, only used internally for account caching when in online mode. In offline mode, the username to connect with. }) ``` @@ -106,10 +110,14 @@ client.on('text', (packet) => { }) ``` -Order of client event emisions: +Order of client event emissions: * 'connect' - emitted after a client first joins the server * 'login' - emitted after the client has been authenticated by the server * 'join' - the client is ready to recieve game packets after successful server-client handshake * 'spawn' - emitted after the client has permission from the server to spawn +### Protocol docs + +For documentation on the protocol, and packets/fields see the [proto.yml](data/latest/proto.yml) and [types.yml](data/latest/proto.yml) files. More information on syntax can be found in CONTRIBUTING.md. When sending a packet, you must fill out all of the required fields. + [1]: https://github.com/PrismarineJS/bedrock-protocol/issues/69 diff --git a/examples/serverReadmeExample.js b/examples/serverReadmeExample.js index 95f4925..870aed8 100644 --- a/examples/serverReadmeExample.js +++ b/examples/serverReadmeExample.js @@ -1,9 +1,13 @@ /* eslint-disable */ const bedrock = require('bedrock-protocol') const server = new bedrock.createServer({ - host: '0.0.0.0', // optional - port: 19132, // optional - version: '1.16.220' // The server version + host: '0.0.0.0', // optional + port: 19132, // optional + version: '1.16.220', // The server version + motd: { // The message of the day + motd: 'Funtime Server', + levelName: 'Wonderland' + } }) server.on('connect', client => { diff --git a/examples/serverTest.js b/examples/serverTest.js index a704dfd..a155c2e 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -16,7 +16,7 @@ const DataProvider = require('../data/provider') const { waitFor } = require('../src/datatypes/util') const { loadWorld } = require('./serverChunks') -async function startServer (version = '1.16.210', ok) { +async function startServer (version = '1.16.220', ok) { if (!hasDumps(version)) { throw Error('You need to dump some packets first. Run tools/genPacketDumps.js') } @@ -33,7 +33,7 @@ async function startServer (version = '1.16.210', ok) { console.log('Started server') // Find the center position from the dumped packets - const respawnPacket = get('packets/respawn.json') + const respawnPacket = get('respawn') const world = await loadWorld(version) const chunks = await world.requestChunks(respawnPacket.x, respawnPacket.z, 2) diff --git a/index.d.ts b/index.d.ts index 705e2ad..3541be6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -10,7 +10,16 @@ declare module "bedrock-protocol" { // For the server, the hostname to bind to (default: 0.0.0.0) host: string, // The port to connect or bind to, default: 19132 - port: number + port: number, + // The maximum number of players allowed on the server at any time. + maxPlayers: number, + + motd: { + // The header for the MOTD shown in the server list. + motd: string, + // The sub-header for the MOTD shown in the server list. + levelName: string + } } enum ClientStatus { diff --git a/src/rak.js b/src/rak.js index 7d922c7..141dc71 100644 --- a/src/rak.js +++ b/src/rak.js @@ -5,7 +5,6 @@ const Reliability = require('jsp-raknet/protocol/reliability') const RakClient = require('jsp-raknet/client') const ConnWorker = require('./rakWorker') const { waitFor } = require('./datatypes/util') -const ServerName = require('./server/advertisement') try { var { Client, Server, PacketPriority, PacketReliability } = require('raknet-native') // eslint-disable-line } catch (e) { @@ -72,10 +71,15 @@ class RakNativeServer extends EventEmitter { this.onCloseConnection = () => { } this.onEncapsulated = () => { } this.raknet = new Server(options.hostname, options.port, { - maxConnections: options.maxConnections || 3, + maxConnections: options.maxPlayers || 3, protocolVersion: 10, - message: ServerName.getServerName(server) + message: server.getAdvertisement().toBuffer() }) + + this.updateAdvertisement = () => { + this.raknet.setOfflineMessage(server.getAdvertisement().toBuffer()) + } + // TODO: periodically update the server name until we're closed this.raknet.on('openConnection', (client) => { diff --git a/src/server.js b/src/server.js index b027b73..4c7551a 100644 --- a/src/server.js +++ b/src/server.js @@ -3,6 +3,7 @@ const { createDeserializer, createSerializer } = require('./transforms/serialize const { Player } = require('./serverPlayer') const { RakServer } = require('./rak') const { sleep } = require('./datatypes/util') +const { ServerAdvertisement } = require('./server/advertisement') const Options = require('./options') const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol') @@ -13,6 +14,8 @@ class Server extends EventEmitter { this.validateOptions() this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) + this.advertisement = new ServerAdvertisement(this.options.motd) + this.advertisement.playersMax = options.maxPlayers ?? 3 /** @type {Object} */ this.clients = {} this.clientCount = 0 @@ -56,18 +59,31 @@ class Server extends EventEmitter { client.handle(buffer) } + getAdvertisement () { + if (this.options.advertisementFn) { + return this.options.advertisementFn() + } + this.advertisement.playersOnline = this.clientCount + return this.advertisement + } + async listen (hostname = this.options.hostname, port = this.options.port) { - this.raknet = new RakServer({ hostname, port }) + this.raknet = new RakServer({ hostname, port }, this) try { await this.raknet.listen() } catch (e) { console.warn(`Failed to bind server on [${this.options.hostname}]/${this.options.port}, is the port free?`) throw e } - console.debug('Listening on', hostname, port) + console.debug('Listening on', hostname, port, this.options.version) this.raknet.onOpenConnection = this.onOpenConnection this.raknet.onCloseConnection = this.onCloseConnection this.raknet.onEncapsulated = this.onEncapsulated + + this.serverTimer = setInterval(() => { + this.raknet.updateAdvertisement() + }, 1000) + return { hostname, port } } @@ -77,6 +93,7 @@ class Server extends EventEmitter { client.disconnect(disconnectReason) } + clearInterval(this.serverTimer) this.clients = {} this.clientCount = 0 diff --git a/src/server/advertisement.js b/src/server/advertisement.js index 978008d..3bca141 100644 --- a/src/server/advertisement.js +++ b/src/server/advertisement.js @@ -1,36 +1,36 @@ const { Versions, CURRENT_VERSION } = require('../options') -class ServerName { +class ServerAdvertisement { motd = 'Bedrock Protocol Server' - name = 'bedrock-protocol' + levelName = 'bedrock-protocol' protocol = Versions[CURRENT_VERSION] version = CURRENT_VERSION - players = { - online: 0, - max: 5 - } + playersOnline = 0 + playersMax = 5 gamemode = 'Creative' serverId = '0' + constructor (obj, version) { + Object.assign(this, obj) + } + fromString (str) { - const [header, motd, protocol, version, playersOnline, playersMax, serverId, name, gamemode] = str.split(';') - if (playersOnline) this.players.online = playersOnline - if (playersMax) this.players.max = playersMax - Object.assign(this, { header, motd, protocol, version, serverId, name, gamemode }) + const [header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode] = str.split(';') + Object.assign(this, { header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode }) return this } - toString (version) { + toString () { return [ 'MCPE', this.motd, this.protocol, this.version, - this.players.online, - this.players.max, + this.playersOnline, + this.playersMax, this.serverId, - this.name, + this.levelName, this.gamemode ].join(';') + ';' } @@ -42,11 +42,11 @@ class ServerName { } module.exports = { - ServerName, + ServerAdvertisement, getServerName (client) { - return new ServerName().toBuffer() + return new ServerAdvertisement().toBuffer() }, fromServerName (string) { - return new ServerName().fromString(string) + return new ServerAdvertisement().fromString(string) } } From 5ea8056e0414c05a6a41bbd8a20083282dedcc08 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 20 Apr 2021 09:50:12 -0400 Subject: [PATCH 166/458] Fix relay, cleanup --- examples/createRelay.js | 22 ++------------------ src/rak.js | 4 ---- src/relay.js | 44 ++++++++++++++-------------------------- src/server.js | 9 ++++---- src/transforms/framer.js | 8 +++----- 5 files changed, 25 insertions(+), 62 deletions(-) diff --git a/examples/createRelay.js b/examples/createRelay.js index d3b76ad..78eb4d3 100644 --- a/examples/createRelay.js +++ b/examples/createRelay.js @@ -2,36 +2,18 @@ const { Relay } = require('../src/relay') function createRelay () { console.log('Creating relay') - /** - * Example to create a non-transparent proxy (or 'Relay') connection to destination server - * In Relay we de-code and re-encode packets - */ + /* Example to create a non-transparent proxy (or 'Relay') connection to destination server */ const relay = new Relay({ /* Hostname and port for clients to listen to */ hostname: '0.0.0.0', port: 19130, - /** - * Who does the authentication - * If set to `client`, all connecting clients will be sent a message with a link to authenticate - * If set to `server`, the server will authenticate and only one client will be able to join - * (Default) If set to `none`, no authentication will be done - */ - auth: 'server', - - /** - * Sets if packets will automatically be forwarded. If set to false, you must listen for on('packet') - * events and - */ - auto: true, - /* Where to send upstream packets to */ destination: { hostname: '127.0.0.1', port: 19132 - // encryption: true } }) - + relay.conLog = console.debug relay.listen() } diff --git a/src/rak.js b/src/rak.js index 141dc71..930bc8a 100644 --- a/src/rak.js +++ b/src/rak.js @@ -80,8 +80,6 @@ class RakNativeServer extends EventEmitter { this.raknet.setOfflineMessage(server.getAdvertisement().toBuffer()) } - // TODO: periodically update the server name until we're closed - this.raknet.on('openConnection', (client) => { client.sendReliable = function (buffer, immediate) { const priority = immediate ? PacketPriority.IMMEDIATE_PRIORITY : PacketPriority.MEDIUM_PRIORITY @@ -91,8 +89,6 @@ class RakNativeServer extends EventEmitter { }) this.raknet.on('closeConnection', (client) => { - console.warn('! Client closed connection') - // TODO: need to handle this properly.. this.onCloseConnection(client) }) diff --git a/src/relay.js b/src/relay.js index 813ec05..70e0023 100644 --- a/src/relay.js +++ b/src/relay.js @@ -1,9 +1,7 @@ -// process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('./client') const { Server } = require('./server') const { Player } = require('./serverPlayer') -const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol relay') -// const { serialize } = require('./datatypes/util') +const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol') /** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ @@ -22,10 +20,10 @@ class RelayPlayer extends Player { }) this.downQ = [] this.upQ = [] - this.upInLog = (...msg) => console.debug('** Backend -> Proxy', ...msg) - this.upOutLog = (...msg) => console.debug('** Proxy -> Backend', ...msg) - this.downInLog = (...msg) => console.debug('** Client -> Proxy', ...msg) - this.downOutLog = (...msg) => console.debug('** Proxy -> Client', ...msg) + this.upInLog = (...msg) => console.debug('* Backend -> Proxy', ...msg) + this.upOutLog = (...msg) => console.debug('* Proxy -> Backend', ...msg) + this.downInLog = (...msg) => console.debug('* Client -> Proxy', ...msg) + this.downOutLog = (...msg) => console.debug('* Proxy -> Client', ...msg) if (!server.options.logging) { this.upInLog = () => { } @@ -34,13 +32,6 @@ class RelayPlayer extends Player { this.downOutLog = () => { } } - // this.upOutLog = (...msg) => { - // if (msg.includes('player_auth_input')) { - // // stream.write(msg) - // console.info('INPUT', msg) - // } - // } - this.outLog = this.downOutLog this.inLog = this.downInLog } @@ -48,21 +39,18 @@ class RelayPlayer extends Player { // Called when we get a packet from backend server (Backend -> PROXY -> Client) readUpstream (packet) { if (!this.startRelaying) { - console.warn('The downstream client is not ready yet !!') this.downQ.push(packet) return } - // this.upInLog('Recv packet', packet) + this.upInLog('->', packet) const des = this.server.deserializer.parsePacketBuffer(packet) const name = des.data.name const params = des.data.params - // this.upInLog('~ Bounce B->C', name, serialize(params).slice(0, 100)) - // this.upInLog('~ ', des.buffer) if (name === 'play_status' && params.status === 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect if (debugging) { // some packet encode/decode testing stuff const rpacket = this.server.serializer.createPacketBuffer({ name, params }) - if (rpacket.toString('hex') !== packet.toString('hex')) { + if (!rpacket.equals(packet)) { console.warn('New', rpacket.toString('hex')) console.warn('Old', packet.toString('hex')) console.log('Failed to re-encode', name, params) @@ -71,8 +59,6 @@ class RelayPlayer extends Player { } this.queue(name, params) - // this.sendBuffer(packet) - this.emit('clientbound', des.data) } @@ -107,7 +93,7 @@ class RelayPlayer extends Player { return } this.flushUpQueue() // Send queued packets - // this.downInLog('Recv packet', packet) + this.downInLog('recv', packet) // TODO: If we fail to parse a packet, proxy it raw and log an error const des = this.server.deserializer.parsePacketBuffer(packet) @@ -127,7 +113,6 @@ class RelayPlayer extends Player { break default: // Emit the packet as-is back to the upstream server - // this.upstream.queue(des.data.name, des.data.params) this.downInLog('Relaying', des.data) this.upstream.sendBuffer(packet) } @@ -148,6 +133,7 @@ class Relay extends Server { this.RelayPlayer = options.relayPlayer || RelayPlayer this.forceSingle = true this.upstreams = new Map() + this.conLog = debug } openUpstreamConnection (ds, clientAddr) { @@ -157,13 +143,14 @@ class Relay extends Server { encrypt: this.options.encrypt, autoInitPlayer: false }) + client.connect() + console.log('CONNECTING TO', this.options.destination.hostname, this.options.destination.port) client.outLog = ds.upOutLog client.inLog = ds.upInLog - // console.log('Set upstream logs', client.outLog, client.inLog) client.once('join', () => { // Intercept once handshaking done ds.upstream = client ds.flushUpQueue() - console.log('Connected to upstream server') + this.conLog('Connected to upstream server') client.readPacket = (packet) => ds.readUpstream(packet) this.emit('join', /* client connected to proxy */ ds, /* backend server */ client) @@ -176,17 +163,16 @@ class Relay extends Server { if (!up) throw Error(`unable to close non-open connection ${clientAddr.hash}`) up.close() this.upstreams.delete(clientAddr.hash) - debug('relay closed connection', clientAddr) + this.conLog('closed upstream connection', clientAddr) } onOpenConnection = (conn) => { - debug('new connection', conn) if (this.forceSingle && this.clientCount > 0) { - debug('dropping connection as single client relay', conn) + this.conLog('dropping connection as single client relay', conn) conn.close() } else { const player = new this.RelayPlayer(this, conn) - console.debug('New connection from', conn.address) + this.conLog('New connection from', conn.address) this.clients[conn.address] = player this.emit('connect', player) this.openUpstreamConnection(player, conn.address) diff --git a/src/server.js b/src/server.js index 4c7551a..a953c39 100644 --- a/src/server.js +++ b/src/server.js @@ -21,11 +21,12 @@ class Server extends EventEmitter { this.clientCount = 0 this.inLog = (...args) => debug('S ->', ...args) this.outLog = (...args) => debug('S <-', ...args) + this.conLog = debug } validateOptions () { if (!Options.Versions[this.options.version]) { - console.warn('Supported versions: ', Options.Versions) + console.warn('Supported versions', Options.Versions) throw Error(`Unsupported version ${this.options.version}`) } this.options.protocolVersion = Options.Versions[this.options.version] @@ -35,7 +36,7 @@ class Server extends EventEmitter { } onOpenConnection = (conn) => { - console.debug('new connection', conn?.address) + this.conLog('new connection', conn?.address) const player = new Player(this, conn) this.clients[conn.address] = player this.clientCount++ @@ -43,7 +44,7 @@ class Server extends EventEmitter { } onCloseConnection = (inetAddr, reason) => { - console.debug('close connection', inetAddr?.address, reason) + this.conLog('close connection', inetAddr?.address, reason) delete this.clients[inetAddr]?.connection // Prevent close loop this.clients[inetAddr]?.close() delete this.clients[inetAddr] @@ -75,7 +76,7 @@ class Server extends EventEmitter { console.warn(`Failed to bind server on [${this.options.hostname}]/${this.options.port}, is the port free?`) throw e } - console.debug('Listening on', hostname, port, this.options.version) + this.conLog('Listening on', hostname, port, this.options.version) this.raknet.onOpenConnection = this.onOpenConnection this.raknet.onCloseConnection = this.onCloseConnection this.raknet.onEncapsulated = this.onEncapsulated diff --git a/src/transforms/framer.js b/src/transforms/framer.js index 7df557a..38d04c4 100644 --- a/src/transforms/framer.js +++ b/src/transforms/framer.js @@ -4,7 +4,7 @@ const zlib = require('zlib') // Concatenates packets into one batch packet, and adds length prefixs. class Framer { constructor () { - // Decoding + // Encoding this.packets = [] this.compressionLevel = 7 } @@ -15,10 +15,8 @@ class Framer { // Decode the payload zlib.inflateRaw(buf.slice(1), { chunkSize: 1024 * 1024 * 2 }, (err, inflated) => { - if (err) { - throw err - // console.error(err) - } else cb(Framer.getPackets(inflated)) + if (err) throw err + cb(Framer.getPackets(inflated)) }) } From b60fd53ad51bed4405782bab247b6441fa7b5055 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 21 Apr 2021 06:22:51 -0400 Subject: [PATCH 167/458] Add relay proxy to tests, docs, fix offline (#71) * Add relay proxy to tests, docs * Add proxy example, type defs * update docs * proxy: forward login packet, fix offline --- CONTRIBUTING.md | 9 ++++--- README.md | 1 + docs/API.md | 40 ++++++++++++++++++++++++++++ examples/relay.js | 37 ++++++++++++++++++++++++++ examples/serverTest.js | 2 +- index.d.ts | 17 ++++++++++++ src/auth/login.js | 2 +- src/client.js | 1 + src/relay.js | 32 +++++++++++++++-------- src/serverPlayer.js | 25 +++++++++--------- test/internal.js | 2 +- test/internal.test.js | 8 ++++++ test/proxy.js | 59 ++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 206 insertions(+), 29 deletions(-) create mode 100644 examples/relay.js create mode 100644 test/proxy.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4129d2..746f349 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,9 @@ Steps to update: * Save and make sure to update the !version field at the top of the file * Run `npm run build` and `npm test` to test +## Code structure + +The code structure is similar to node-minecraft-protocol. For raknet, raknet-native is used for Raknet communication. ## Packet serialization @@ -29,7 +32,7 @@ Packets should go in proto.yml and extra types should go in types.yml. ```yml # This defines a new data structure, a ProtoDef container. -PlayerPosition: +Position: # Variable `x` in this struct has a type of `li32`, a little-endian 32-bit integer x: li32 # `z` is a 32-bit LE *unsigned* integer @@ -45,7 +48,7 @@ packet_player_position: # Read `on_ground` as a boolean on_ground: bool - # Read `position` as custom data type `PlayerPosition` defined above. + # Read `position` as custom data type `Position` defined above. position: Position # Reads a 8-bit unsigned integer, then maps it to a string @@ -90,7 +93,7 @@ packet_player_position: The above roughly translates to the following JavaScript code to read a packet: ```js -function read_player_position(stream) { +function read_position(stream) { const ret = {} ret.x = stream.readSignedInt32LE() ret.z = stream.readUnsignedInt32LE() diff --git a/README.md b/README.md index dd18d0a..5b17a18 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ This is a work in progress. You can track the progress in https://github.com/Pri - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets + - [Proxy and mitm connections](docs/API.md) - Client - Authentication - Encryption diff --git a/docs/API.md b/docs/API.md index cf9939f..0b64c8e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -120,4 +120,44 @@ Order of client event emissions: For documentation on the protocol, and packets/fields see the [proto.yml](data/latest/proto.yml) and [types.yml](data/latest/proto.yml) files. More information on syntax can be found in CONTRIBUTING.md. When sending a packet, you must fill out all of the required fields. + +### Proxy docs + +You can create a proxy ("Relay") to create a machine-in-the-middle (MITM) connection to a server. You can observe and intercept packets as they go through. The Relay is a server+client combo with some special packet handling and forwarding that takes care of the authentication and encryption on the server side. You'll be asked to login if `offline` is not specified once you connect. + +```js +const { Relay } = require('bedrock-protocol') +const relay = new Relay({ + version: '1.16.220', // The version + /* Hostname and port to listen for clients on */ + hostname: '0.0.0.0', + port: 19132, + /* Where to send upstream packets to */ + destination: { + hostname: '127.0.0.1', + port: 19131 + } +}) +relay.listen() // Tell the server to start listening. + +relay.on('connect', player => { + console.log('New connection', player.connection.address) + + // Server is sending a message to the client. + player.on('clientbound', ({ name, params }) => { + if (name === 'disconnect') { // Intercept kick + params.message = 'Intercepted' // Change kick message to "Intercepted" + } + }) + // Client is sending a message to the server + player.on('serverbound', ({ name, params }) => { + if (name === 'text') { // Intercept chat message to server and append time. + params.message += `, on ${new Date().toLocaleString()}` + } + }) +}) +``` + +'Relay' emits 'clientbound' and 'serverbound' events, along with the data for the outgoing packet that can be modified. You can send a packet to the client with `player.queue()` or to the backend server with `player.upstream.queue()`. + [1]: https://github.com/PrismarineJS/bedrock-protocol/issues/69 diff --git a/examples/relay.js b/examples/relay.js new file mode 100644 index 0000000..f8e5791 --- /dev/null +++ b/examples/relay.js @@ -0,0 +1,37 @@ +const { Relay } = require('bedrock-protocol') + +// Start your server first on port 19131. + +// Start the proxy server +const relay = new Relay({ + version: '1.16.220', // The version + /* Hostname and port to listen for clients on */ + hostname: '0.0.0.0', + port: 19132, + /* Where to send upstream packets to */ + destination: { + hostname: '127.0.0.1', + port: 19131 + } +}) +relay.conLog = console.debug +relay.listen() // Tell the server to start listening. + +relay.on('connect', player => { + console.log('New connection', player.connection.address) + + // Server is sending a message to the client. + player.on('clientbound', ({ name, params }) => { + if (name === 'disconnect') { // Intercept kick + params.message = 'Intercepted' // Change kick message to "Intercepted" + } + }) + // Client is sending a message to the server + player.on('serverbound', ({ name, params }) => { + if (name === 'text') { // Intercept chat message to server and append time. + params.message += `, on ${new Date().toLocaleString()}` + } + }) +}) + +// Now clients can connect to your proxy diff --git a/examples/serverTest.js b/examples/serverTest.js index a155c2e..6cae966 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -41,7 +41,7 @@ async function startServer (version = '1.16.220', ok) { server.on('connect', client => { // Join is emitted after the client has been authenticated and encryption has started client.on('join', () => { - console.log('Client joined', client.getData()) + console.log('Client joined', client.getUserData()) // ResourcePacksInfo is sent by the server to inform the client on what resource packs the server has. It // sends a list of the resource packs it has and basic information on them like the version and description. diff --git a/index.d.ts b/index.d.ts index 3541be6..bb64b6c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -95,11 +95,28 @@ declare module "bedrock-protocol" { export class Server extends EventEmitter { clients: Map + // Connection logging function + conLog: Function constructor(options: Options) // Disconnects all currently connected clients close(disconnectReason: string) } + type RelayOptions = Options & { + hostname: string, + port: number, + // Toggle packet logging. + logging: boolean, + // Where to proxy requests to. + destination: { + hostname: string, + port: number + } + } + export class Relay extends Server { + constructor(options: RelayOptions) + } + class ServerAdvertisement { motd: string name: string diff --git a/src/auth/login.js b/src/auth/login.js index d835326..c2d56bb 100644 --- a/src/auth/login.js +++ b/src/auth/login.js @@ -79,7 +79,7 @@ module.exports = (client, server, options) => { ThirdPartyNameOnly: false, UIProfile: 0 } - const customPayload = options.userData || {} + const customPayload = options.skinData || {} payload = { ...payload, ...customPayload } client.clientUserChain = JWT.sign(payload, privateKey, diff --git a/src/client.js b/src/client.js index 83dcb7c..8bdce58 100644 --- a/src/client.js +++ b/src/client.js @@ -188,6 +188,7 @@ class Client extends Connection { this.emit('client.server_handshake', des.data.params) break case 'disconnect': // Client kicked + this.emit(des.data.name, des.data.params) // Emit before we kill all listeners. this.onDisconnectRequest(des.data.params) break case 'start_game': diff --git a/src/relay.js b/src/relay.js index 70e0023..492ca9e 100644 --- a/src/relay.js +++ b/src/relay.js @@ -3,15 +3,11 @@ const { Server } = require('./server') const { Player } = require('./serverPlayer') const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol') -/** @typedef {{ hostname: string, port: number, auth: 'client' | 'server' | null, destination?: { hostname: string, port: number } }} Options */ - const debugging = true // Do re-encoding tests class RelayPlayer extends Player { constructor (server, conn) { super(server, conn) - this.server = server - this.conn = conn this.startRelaying = false this.once('join', () => { // The client has joined our proxy @@ -58,8 +54,8 @@ class RelayPlayer extends Player { } } - this.queue(name, params) this.emit('clientbound', des.data) + this.queue(name, params) } // Send queued packets to the connected client @@ -99,7 +95,7 @@ class RelayPlayer extends Player { if (debugging) { // some packet encode/decode testing stuff const rpacket = this.server.serializer.createPacketBuffer(des.data) - if (rpacket.toString('hex') !== packet.toString('hex')) { + if (!rpacket.equals(packet)) { console.warn('New', rpacket.toString('hex')) console.warn('Old', packet.toString('hex')) console.log('Failed to re-encode', des.data) @@ -107,6 +103,8 @@ class RelayPlayer extends Player { } } + this.emit('serverbound', des.data) + switch (des.data.name) { case 'client_cache_status': this.upstream.queue('client_cache_status', { enabled: false }) @@ -114,9 +112,8 @@ class RelayPlayer extends Player { default: // Emit the packet as-is back to the upstream server this.downInLog('Relaying', des.data) - this.upstream.sendBuffer(packet) + this.upstream.queue(des.data.name, des.data.params) } - this.emit('serverbound', des.data) } else { super.readPacket(packet) } @@ -138,13 +135,17 @@ class Relay extends Server { openUpstreamConnection (ds, clientAddr) { const client = new Client({ + offline: this.options.offline, + username: this.options.offline ? ds.profile.name : null, + version: this.options.version, hostname: this.options.destination.hostname, port: this.options.destination.port, - encrypt: this.options.encrypt, autoInitPlayer: false }) + // Set the login payload unless `noLoginForward` option + if (!client.noLoginForward) client.skinData = ds.skinData client.connect() - console.log('CONNECTING TO', this.options.destination.hostname, this.options.destination.port) + this.conLog('Connecting to', this.options.destination.hostname, this.options.destination.port) client.outLog = ds.upOutLog client.inLog = ds.upInLog client.once('join', () => { // Intercept once handshaking done @@ -175,9 +176,18 @@ class Relay extends Server { this.conLog('New connection from', conn.address) this.clients[conn.address] = player this.emit('connect', player) - this.openUpstreamConnection(player, conn.address) + player.on('login', () => { + this.openUpstreamConnection(player, conn.address) + }) } } + + close (...a) { + for (const [, v] of this.upstreams) { + v.close(...a) + } + super.close(...a) + } } // Too many things called 'Proxy' ;) diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 5024a9a..bbbdcb6 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -26,7 +26,7 @@ class Player extends Connection { this.outLog = (...args) => debug('S <-', ...args) } - getData () { + getUserData () { return this.userData } @@ -51,24 +51,25 @@ class Player extends Connection { const skinChain = body.params.client_data try { - var { key, userData, chain } = this.decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line + var { key, userData, skinData } = this.decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line } catch (e) { console.error(e) - // TODO: disconnect user - throw new Error('Failed to verify user') + this.disconnect('Server authentication error') + return } debug('Verified user pub key', key, userData) - this.emit('login', { user: userData.extraData }) // emit events for user this.emit('server.client_handshake', { key }) // internal so we start encryption this.userData = userData.extraData + this.skinData = skinData this.profile = { name: userData.extraData?.displayName, uuid: userData.extraData?.identity, xuid: userData.extraData?.xuid } this.version = clientVer + this.emit('login', { user: userData.extraData }) // emit events for user } /** @@ -90,7 +91,7 @@ class Player extends Connection { hide_disconnect_screen: hide, message: reason }) - console.debug('Kicked ', this.connection?.address, reason) + this.server.conLog('Kicked ', this.connection?.address, reason) setTimeout(() => this.close('kick'), 100) // Allow time for message to be recieved. } @@ -118,20 +119,17 @@ class Player extends Connection { } readPacket (packet) { - // console.log('packet', packet) try { var des = this.server.deserializer.parsePacketBuffer(packet) // eslint-disable-line } catch (e) { this.disconnect('Server error') console.warn('Packet parsing failed! Writing dump to ./packetdump.bin') - fs.writeFileSync('packetdump.bin', packet) - fs.writeFileSync('packetdump.txt', packet.toString('hex')) - throw e + fs.writeFile('packetdump.bin', packet) + return } switch (des.data.name) { case 'login': - // console.log(des) this.onLogin(des) return case 'client_to_server_handshake': @@ -145,7 +143,10 @@ class Player extends Connection { this.emit('spawn') break default: - // console.log('ignoring, unhandled') + if (this.status === ClientStatus.Disconnected || this.status === ClientStatus.Authenticating) { + this.inLog('ignoring', des.data.name) + return + } } this.emit(des.data.name, des.data.params) } diff --git a/test/internal.js b/test/internal.js index b811588..449df62 100644 --- a/test/internal.js +++ b/test/internal.js @@ -38,7 +38,7 @@ async function startTest (version = '1.16.220', ok) { // server logic server.on('connect', client => { client.on('join', () => { - console.log('Client joined server', client.getData()) + console.log('Client joined server', client.getUserData()) client.write('resource_packs_info', { must_accept: false, diff --git a/test/internal.test.js b/test/internal.test.js index c75ad3f..ef756c6 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -1,6 +1,7 @@ /* eslint-env jest */ const { timedTest } = require('./internal') +const { proxyTest } = require('./proxy') const { Versions } = require('../src/options') describe('internal client/server test', function () { @@ -12,4 +13,11 @@ describe('internal client/server test', function () { await timedTest(version) }) } + + for (const version in Versions) { + it('proxies ' + version, async () => { + console.debug(version) + await proxyTest(version) + }) + } }) diff --git a/test/proxy.js b/test/proxy.js new file mode 100644 index 0000000..280efbf --- /dev/null +++ b/test/proxy.js @@ -0,0 +1,59 @@ +const { createClient, createServer, Relay } = require('bedrock-protocol') +const { sleep, waitFor } = require('../src/datatypes/util') + +function proxyTest (version, timeout = 1000 * 20) { + return waitFor(res => { + const server = createServer({ + host: '0.0.0.0', // optional + port: 19131, // optional + offline: true, + version // The server version + }) + + server.on('connect', client => { + client.on('join', () => { // The client has joined the server. + setTimeout(() => { + client.disconnect('Hello world !') + }, 1000) // allow some time for client to connect + }) + }) + + console.debug('Server started', server.options.version) + + const relay = new Relay({ + version, + offline: true, + /* Hostname and port for clients to listen to */ + hostname: '0.0.0.0', + port: 19132, + /* Where to send upstream packets to */ + destination: { + hostname: '127.0.0.1', + port: 19131 + } + }) + relay.conLog = console.debug + relay.listen() + + console.debug('Proxy started', server.options.version) + + const client = createClient({ hostname: '127.0.0.1', version, username: 'Boat', offline: true }) + + console.debug('Client started') + + client.on('disconnect', packet => { + console.assert(packet.message === 'Hello world !') + + server.close() + relay.close() + console.log('✔ OK') + sleep(500).then(res) + }) + }, timeout, () => { throw Error('timed out') }) +} + +if (!module.parent) { + proxyTest('1.16.220') +} + +module.exports = { proxyTest } From 7c6439b301bae4ef33530f4da44a2e470652feaf Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 21 Apr 2021 07:23:06 -0400 Subject: [PATCH 168/458] Add version check (#73) * Add version check * fix server import --- index.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 834f737..a4e2f49 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,20 @@ -module.exports = { - ...require('./src/client'), - ...require('./src/server'), - ...require('./src/serverPlayer'), - ...require('./src/relay'), - ...require('./src/createClient'), - ...require('./src/createServer') +if (typeof process !== 'undefined' && parseInt(process.versions.node.split('.')[0]) < 14) { + console.error('Your node version is currently', process.versions.node) + console.error('Please update it to a version >= 14.x.x from https://nodejs.org/') + process.exit(1) +} + +const { Client } = require('./src/client') +const { Server } = require('./src/server') +const { Relay } = require('./src/relay') +const { createClient, ping } = require('./src/createClient') +const { createServer } = require('./src/createServer') + +module.exports = { + Client, + Server, + Relay, + createClient, + ping, + createServer } From 39659cf48b5c64f4a2383bde1b4eb7ada45a6e2b Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Fri, 23 Apr 2021 03:23:43 -0400 Subject: [PATCH 169/458] rename hostname to host (#74) --- README.md | 2 +- docs/API.md | 14 +++++++------- examples/clientTest.js | 2 +- examples/createClientExample.js | 2 +- examples/createRelay.js | 6 +++--- examples/relay.js | 6 +++--- examples/serverTest.js | 2 +- examples/viewer/client/ClientProvider.js | 2 +- examples/viewer/client/ProxyProvider.js | 4 ++-- index.d.ts | 8 ++++---- src/auth/login.js | 2 +- src/client.js | 12 ++++++------ src/createClient.js | 5 ++--- src/createServer.js | 1 - src/rak.js | 16 ++++++++-------- src/rakWorker.js | 10 +++++----- src/relay.js | 4 ++-- src/server.js | 10 +++++----- test/internal.js | 4 ++-- test/proxy.js | 8 ++++---- test/vanilla.js | 2 +- tools/dumpPackets.js | 2 +- tools/genPacketDumps.js | 2 +- 23 files changed, 62 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 5b17a18..a8307aa 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ client.on('text', (packet) => { // Listen for chat messages and echo them back. ```js const bedrock = require('bedrock-protocol') const server = new bedrock.createServer({ - host: '0.0.0.0', // optional. Hostname to bind as. + host: '0.0.0.0', // optional. host to bind as. port: 19132, // optional version: '1.16.220' // optional. The server version, latest if not specified. }) diff --git a/docs/API.md b/docs/API.md index 0b64c8e..071cb6b 100644 --- a/docs/API.md +++ b/docs/API.md @@ -8,7 +8,7 @@ Returns a `Client` instance and connects to the server. | Parameter | Optionality | Description | | ----------- | ----------- |-| -| host | **Required** | Hostname to connect to, for example `127.0.0.1`. | +| host | **Required** | host to connect to, for example `127.0.0.1`. | | port | *optional* | port to connect to, default to **19132** | | version | *optional* | Version to connect as.
(Future feature, see [#69][1]) If not specified, should automatically match server version.
(Current feature) Defaults to latest version. | | offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth. | @@ -28,7 +28,7 @@ authenticated unless offline is set to true. | Parameter | Optionality | Description | | ----------- | ----------- |-| -| host | **Required** | The hostname to bind to. use `0.0.0.0` to bind all IPv4 addresses. | +| host | **Required** | The host to bind to. use `0.0.0.0` to bind all IPv4 addresses. | | port | *optional* | the port to bind to, default **19132** | | version | *optional* | Version to run server as. Clients below this version will be kicked, clients above will still be permitted. | | offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth enforcement. | @@ -55,7 +55,7 @@ You can create a server as such: ```js const bedrock = require('bedrock-protocol') const server = bedrock.createServer({ - host: '0.0.0.0', // the hostname to bind to, use '0.0.0.0' to bind all hostnames + host: '0.0.0.0', // the host to bind to, use '0.0.0.0' to bind all hosts port: 19132, // optional, port to bind to, default 19132 offline: false, // default false. verify connections with XBL motd: { @@ -90,7 +90,7 @@ You can create a server as such: ```js const bedrock = require('bedrock-protocol') const client = bedrock.createClient({ - host: '127.0.0.1', // the hostname to bind to, use '0.0.0.0' to bind all hostnames + host: '127.0.0.1', // the host to bind to, use '0.0.0.0' to bind all hosts port: 19132, // optional, port to bind to, default 19132 username: 'Notch' // Any profile name, only used internally for account caching when in online mode. In offline mode, the username to connect with. }) @@ -129,12 +129,12 @@ You can create a proxy ("Relay") to create a machine-in-the-middle (MITM) connec const { Relay } = require('bedrock-protocol') const relay = new Relay({ version: '1.16.220', // The version - /* Hostname and port to listen for clients on */ - hostname: '0.0.0.0', + /* host and port to listen for clients on */ + host: '0.0.0.0', port: 19132, /* Where to send upstream packets to */ destination: { - hostname: '127.0.0.1', + host: '127.0.0.1', port: 19131 } }) diff --git a/examples/clientTest.js b/examples/clientTest.js index 717a428..a6996eb 100644 --- a/examples/clientTest.js +++ b/examples/clientTest.js @@ -4,7 +4,7 @@ const { ChunkColumn, Version } = require('bedrock-provider') async function test () { const client = new Client({ - hostname: '127.0.0.1', + host: '127.0.0.1', port: 19132 // You can specify version by adding : // version: '1.16.210' diff --git a/examples/createClientExample.js b/examples/createClientExample.js index 6de4b9b..f05a0b5 100644 --- a/examples/createClientExample.js +++ b/examples/createClientExample.js @@ -1,6 +1,6 @@ const { createClient } = require('bedrock-protocol') -const client = createClient({ hostname: '127.0.0.1' }) +const client = createClient({ host: '127.0.0.1' }) let ix = 0 client.on('packet', (args) => { diff --git a/examples/createRelay.js b/examples/createRelay.js index 78eb4d3..7209904 100644 --- a/examples/createRelay.js +++ b/examples/createRelay.js @@ -4,12 +4,12 @@ function createRelay () { console.log('Creating relay') /* Example to create a non-transparent proxy (or 'Relay') connection to destination server */ const relay = new Relay({ - /* Hostname and port for clients to listen to */ - hostname: '0.0.0.0', + /* host and port for clients to listen to */ + host: '0.0.0.0', port: 19130, /* Where to send upstream packets to */ destination: { - hostname: '127.0.0.1', + host: '127.0.0.1', port: 19132 } }) diff --git a/examples/relay.js b/examples/relay.js index f8e5791..7fce986 100644 --- a/examples/relay.js +++ b/examples/relay.js @@ -5,12 +5,12 @@ const { Relay } = require('bedrock-protocol') // Start the proxy server const relay = new Relay({ version: '1.16.220', // The version - /* Hostname and port to listen for clients on */ - hostname: '0.0.0.0', + /* host and port to listen for clients on */ + host: '0.0.0.0', port: 19132, /* Where to send upstream packets to */ destination: { - hostname: '127.0.0.1', + host: '127.0.0.1', port: 19131 } }) diff --git a/examples/serverTest.js b/examples/serverTest.js index 6cae966..e299b62 100644 --- a/examples/serverTest.js +++ b/examples/serverTest.js @@ -23,7 +23,7 @@ async function startServer (version = '1.16.220', ok) { const Item = require('../types/Item')(version) const port = 19132 - const server = new Server({ hostname: '0.0.0.0', port, version }) + const server = new Server({ host: '0.0.0.0', port, version }) let loop const getPath = (packetPath) => DataProvider(server.options.protocolVersion).getPath(packetPath) diff --git a/examples/viewer/client/ClientProvider.js b/examples/viewer/client/ClientProvider.js index e8f3ada..73d7b8f 100644 --- a/examples/viewer/client/ClientProvider.js +++ b/examples/viewer/client/ClientProvider.js @@ -14,7 +14,7 @@ class ClientProvider extends BotProvider { downKeys = new Set() connect () { - const client = new Client({ hostname: '127.0.0.1', version: '1.16.210', username: 'notch', offline: true, port: 19132, connectTimeout: 100000 }) + const client = new Client({ host: '127.0.0.1', version: '1.16.210', username: 'notch', offline: true, port: 19132, connectTimeout: 100000 }) client.once('resource_packs_info', (packet) => { client.write('resource_pack_client_response', { diff --git a/examples/viewer/client/ProxyProvider.js b/examples/viewer/client/ProxyProvider.js index de97ee6..29f74c7 100644 --- a/examples/viewer/client/ProxyProvider.js +++ b/examples/viewer/client/ProxyProvider.js @@ -7,11 +7,11 @@ class ProxyProvider extends BotProvider { connect () { const proxy = new Relay({ - hostname: '0.0.0.0', + host: '0.0.0.0', port: 19130, // logging: true, destination: { - hostname: '127.0.0.1', + host: '127.0.0.1', port: 19132 } }) diff --git a/index.d.ts b/index.d.ts index bb64b6c..26b764a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -6,8 +6,8 @@ declare module "bedrock-protocol" { export interface Options { // The string version to start the client or server as version: number, - // For the client, the hostname of the server to connect to (default: 127.0.0.1) - // For the server, the hostname to bind to (default: 0.0.0.0) + // For the client, the host of the server to connect to (default: 127.0.0.1) + // For the server, the host to bind to (default: 0.0.0.0) host: string, // The port to connect or bind to, default: 19132 port: number, @@ -103,13 +103,13 @@ declare module "bedrock-protocol" { } type RelayOptions = Options & { - hostname: string, + host: string, port: number, // Toggle packet logging. logging: boolean, // Where to proxy requests to. destination: { - hostname: string, + host: string, port: number } } diff --git a/src/auth/login.js b/src/auth/login.js index c2d56bb..afa74fb 100644 --- a/src/auth/login.js +++ b/src/auth/login.js @@ -66,7 +66,7 @@ module.exports = (client, server, options) => { PlayFabId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', // 1.16.210 PremiumSkin: false, SelfSignedId: nextUUID(), - ServerAddress: `${options.hostname}:${options.port}`, + ServerAddress: `${options.host}:${options.port}`, SkinAnimationData: '', SkinColor: '#ffffcd96', SkinData: 'AAAAAA==', diff --git a/src/client.js b/src/client.js index 8bdce58..049dda0 100644 --- a/src/client.js +++ b/src/client.js @@ -17,7 +17,7 @@ class Client extends Connection { // The RakNet connection connection - /** @param {{ version: number, hostname: string, port: number }} options */ + /** @param {{ version: number, host: string, port: number }} options */ constructor (options) { super() this.options = { ...Options.defaultOptions, ...options } @@ -29,9 +29,9 @@ class Client extends Connection { Login(this, null, this.options) LoginVerify(this, null, this.options) - const hostname = this.options.hostname + const host = this.options.host const port = this.options.port - this.connection = new RakClient({ useWorkers: true, hostname, port }) + this.connection = new RakClient({ useWorkers: true, host, port }) this.startGameData = {} this.clientRuntimeId = null @@ -54,7 +54,7 @@ class Client extends Connection { } validateOptions () { - if (!this.options.hostname || this.options.port == null) throw Error('Invalid hostname/port') + if (!this.options.host || this.options.port == null) throw Error('Invalid host/port') if (!Options.Versions[this.options.version]) { console.warn('Supported versions: ', Options.Versions) @@ -79,13 +79,13 @@ class Client extends Connection { try { return await this.connection.ping(this.options.connectTimeout) } catch (e) { - console.warn(`Unable to connect to [${this.options.hostname}]/${this.options.port}. Is the server running?`) + console.warn(`Unable to connect to [${this.options.host}]/${this.options.port}. Is the server running?`) throw e } } _connect = async (sessionData) => { - debug('[client] connecting to', this.options.hostname, this.options.port, sessionData, this.connection) + debug('[client] connecting to', this.options.host, this.options.port, sessionData, this.connection) this.connection.onConnected = () => this.sendLogin() this.connection.onCloseConnection = () => this.close() this.connection.onEncapsulated = this.onEncapsulated diff --git a/src/createClient.js b/src/createClient.js index e357627..85856f9 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -3,10 +3,9 @@ const { RakClient } = require('./rak') const assert = require('assert') const advertisement = require('./server/advertisement') -/** @param {{ version?: number, hostname: string, port?: number, connectTimeout?: number }} options */ +/** @param {{ version?: number, host: string, port?: number, connectTimeout?: number }} options */ function createClient (options) { assert(options) - if (options.host) options.hostname = options.host const client = new Client({ port: 19132, ...options }) if (options.skipPing) { @@ -67,7 +66,7 @@ function connect (client) { } async function ping ({ host, port }) { - const con = new RakClient({ hostname: host, port }) + const con = new RakClient({ host, port }) const ret = await con.ping() con.close() return advertisement.fromServerName(ret) diff --git a/src/createServer.js b/src/createServer.js index 3c6762c..88b362d 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,7 +1,6 @@ const { Server } = require('./server') function createServer (options) { - if (options.host) options.hostname = options.host if (!options.port) options.port = 19132 const server = new Server(options) server.listen() diff --git a/src/rak.js b/src/rak.js index 930bc8a..05cacc0 100644 --- a/src/rak.js +++ b/src/rak.js @@ -19,7 +19,7 @@ class RakNativeClient extends EventEmitter { this.onCloseConnection = () => { } this.onEncapsulated = () => { } - this.raknet = new Client(options.hostname, options.port, { protocolVersion: 10 }) + this.raknet = new Client(options.host, options.port, { protocolVersion: 10 }) this.raknet.on('encapsulated', ({ buffer, address }) => { this.onEncapsulated(buffer, address) }) @@ -70,7 +70,7 @@ class RakNativeServer extends EventEmitter { this.onOpenConnection = () => { } this.onCloseConnection = () => { } this.onEncapsulated = () => { } - this.raknet = new Server(options.hostname, options.port, { + this.raknet = new Server(options.host, options.port, { maxConnections: options.maxPlayers || 3, protocolVersion: 10, message: server.getAdvertisement().toBuffer() @@ -120,8 +120,8 @@ class RakJsClient extends EventEmitter { } } - workerConnect (hostname = this.options.hostname, port = this.options.port) { - this.worker = ConnWorker.connect(hostname, port) + workerConnect (host = this.options.host, port = this.options.port) { + this.worker = ConnWorker.connect(host, port) this.worker.on('message', (evt) => { switch (evt.type) { @@ -138,12 +138,12 @@ class RakJsClient extends EventEmitter { }) } - async plainConnect (hostname = this.options.hostname, port = this.options.port) { - this.raknet = new RakClient(hostname, port) + async plainConnect (host = this.options.host, port = this.options.port) { + this.raknet = new RakClient(host, port) await this.raknet.connect() this.raknet.on('connecting', () => { - console.log(`[client] connecting to ${hostname}/${port}`) + console.log(`[client] connecting to ${host}/${port}`) }) this.raknet.on('connected', this.onConnected) @@ -180,7 +180,7 @@ class RakJsServer extends EventEmitter { async plainListen () { this.raknet = new Listener() - await this.raknet.listen(this.options.hostname, this.options.port) + await this.raknet.listen(this.options.host, this.options.port) this.raknet.on('openConnection', (conn) => { conn.sendReliable = function (buffer, immediate) { const sendPacket = new EncapsulatedPacket() diff --git a/src/rakWorker.js b/src/rakWorker.js index d9a4bc5..97643a9 100644 --- a/src/rakWorker.js +++ b/src/rakWorker.js @@ -3,10 +3,10 @@ const { Worker, isMainThread, parentPort } = require('worker_threads') const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') const Reliability = require('jsp-raknet/protocol/reliability') -function connect (hostname, port) { +function connect (host, port) { if (isMainThread) { const worker = new Worker(__filename) - worker.postMessage({ type: 'connect', hostname, port }) + worker.postMessage({ type: 'connect', host, port }) return worker } } @@ -16,15 +16,15 @@ let raknet function main () { parentPort.on('message', (evt) => { if (evt.type === 'connect') { - const { hostname, port } = evt - raknet = new RakClient(hostname, port) + const { host, port } = evt + raknet = new RakClient(host, port) raknet.connect().then(() => { console.log('Raknet Connected!') }) raknet.on('connecting', () => { - console.log(`[client] connecting to ${hostname}/${port}`) + console.log(`[client] connecting to ${host}/${port}`) parentPort.postMessage('message', { type: 'connecting' }) console.log('Raknet', raknet) }) diff --git a/src/relay.js b/src/relay.js index 492ca9e..9e7992a 100644 --- a/src/relay.js +++ b/src/relay.js @@ -138,14 +138,14 @@ class Relay extends Server { offline: this.options.offline, username: this.options.offline ? ds.profile.name : null, version: this.options.version, - hostname: this.options.destination.hostname, + host: this.options.destination.host, port: this.options.destination.port, autoInitPlayer: false }) // Set the login payload unless `noLoginForward` option if (!client.noLoginForward) client.skinData = ds.skinData client.connect() - this.conLog('Connecting to', this.options.destination.hostname, this.options.destination.port) + this.conLog('Connecting to', this.options.destination.host, this.options.destination.port) client.outLog = ds.upOutLog client.inLog = ds.upInLog client.once('join', () => { // Intercept once handshaking done diff --git a/src/server.js b/src/server.js index a953c39..b10abd8 100644 --- a/src/server.js +++ b/src/server.js @@ -68,15 +68,15 @@ class Server extends EventEmitter { return this.advertisement } - async listen (hostname = this.options.hostname, port = this.options.port) { - this.raknet = new RakServer({ hostname, port }, this) + async listen (host = this.options.host, port = this.options.port) { + this.raknet = new RakServer({ host, port }, this) try { await this.raknet.listen() } catch (e) { - console.warn(`Failed to bind server on [${this.options.hostname}]/${this.options.port}, is the port free?`) + console.warn(`Failed to bind server on [${this.options.host}]/${this.options.port}, is the port free?`) throw e } - this.conLog('Listening on', hostname, port, this.options.version) + this.conLog('Listening on', host, port, this.options.version) this.raknet.onOpenConnection = this.onOpenConnection this.raknet.onCloseConnection = this.onCloseConnection this.raknet.onEncapsulated = this.onEncapsulated @@ -85,7 +85,7 @@ class Server extends EventEmitter { this.raknet.updateAdvertisement() }, 1000) - return { hostname, port } + return { host, port } } async close (disconnectReason) { diff --git a/test/internal.js b/test/internal.js index 449df62..9cdc76c 100644 --- a/test/internal.js +++ b/test/internal.js @@ -14,7 +14,7 @@ async function startTest (version = '1.16.220', ok) { await prepare(version) const Item = require('../types/Item')(version) const port = 19130 - const server = new Server({ hostname: '0.0.0.0', port, version, offline: true }) + const server = new Server({ host: '0.0.0.0', port, version, offline: true }) function getPath (packetPath) { return DataProvider(server.options.protocolVersion).getPath(packetPath) @@ -108,7 +108,7 @@ async function startTest (version = '1.16.220', ok) { // client logic const client = new Client({ - hostname: '127.0.0.1', + host: '127.0.0.1', port, username: 'Notch', version, diff --git a/test/proxy.js b/test/proxy.js index 280efbf..ad5d3ab 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -23,12 +23,12 @@ function proxyTest (version, timeout = 1000 * 20) { const relay = new Relay({ version, offline: true, - /* Hostname and port for clients to listen to */ - hostname: '0.0.0.0', + /* host and port for clients to listen to */ + host: '0.0.0.0', port: 19132, /* Where to send upstream packets to */ destination: { - hostname: '127.0.0.1', + host: '127.0.0.1', port: 19131 } }) @@ -37,7 +37,7 @@ function proxyTest (version, timeout = 1000 * 20) { console.debug('Proxy started', server.options.version) - const client = createClient({ hostname: '127.0.0.1', version, username: 'Boat', offline: true }) + const client = createClient({ host: '127.0.0.1', version, username: 'Boat', offline: true }) console.debug('Client started') diff --git a/test/vanilla.js b/test/vanilla.js index 6970a6c..13c6069 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -11,7 +11,7 @@ async function test (version) { console.log('Started server') const client = new Client({ - hostname: '127.0.0.1', + host: '127.0.0.1', port: 19130, username: 'Notch', version, diff --git a/tools/dumpPackets.js b/tools/dumpPackets.js index 8ef569a..47cc30b 100644 --- a/tools/dumpPackets.js +++ b/tools/dumpPackets.js @@ -20,7 +20,7 @@ async function dump (version) { console.log('Started server') const client = new Client({ - hostname: '127.0.0.1', + host: '127.0.0.1', port, username: 'dumpBot', offline: true diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index 94a718b..a5b63b7 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -25,7 +25,7 @@ async function dump (version, force) { console.log('Started server') const client = new Client({ - hostname: '127.0.0.1', + host: '127.0.0.1', port, version, username: 'Boat' + random, From cf006ab12d31af3a49a109b96123904d8841ead0 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 25 Apr 2021 09:28:15 -0400 Subject: [PATCH 170/458] Fix readme install command --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8307aa..aebb43c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Want to contribute on something important for PrismarineJS ? go to https://githu ## Installation -`npm install bedrock-protocol` +`npm install PrismarineJS/bedrock-protocol` ## Usage @@ -119,4 +119,4 @@ See [history](HISTORY.md) \ No newline at end of file +* [map-colors](https://github.com/AresRPG/aresrpg-map-colors) can be used to convert any image into a buffer of minecraft compatible colors --> From cbfd9eac1db617bf4f418235ae49d4a980f00f5d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 2 May 2021 01:04:32 +0200 Subject: [PATCH 171/458] Upgrade to GitHub-native Dependabot (#75) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- .github/dependabot.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..bd5d879 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 +updates: +- package-ecosystem: npm + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + ignore: + - dependency-name: raknet-native + versions: + - 0.2.0 + - 1.0.0 + - dependency-name: bedrock-provider + versions: + - 1.0.0 + - dependency-name: mocha + versions: + - 8.3.1 From faf7373dfd77ead1837e2a38026860815dbccc45 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 4 May 2021 01:46:56 -0400 Subject: [PATCH 172/458] Fix microsoft auth refresh --- src/client/tokens.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/tokens.js b/src/client/tokens.js index 6603df9..5dda941 100644 --- a/src/client/tokens.js +++ b/src/client/tokens.js @@ -103,9 +103,10 @@ class MsaTokenManager { } async verifyTokens () { + if (this.forceRefresh) try { await this.refreshTokens() } catch {} const at = this.getAccessToken() const rt = this.getRefreshToken() - if (!at || !rt || this.forceRefresh) { + if (!at || !rt) { return false } debug('[msa] have at, rt', at, rt) From c9c162bc16ca617063f11c11bdc0bcc2e9d6f357 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 4 May 2021 02:52:09 -0400 Subject: [PATCH 173/458] Increase test timeouts --- test/internal.test.js | 2 +- test/proxy.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/internal.test.js b/test/internal.test.js index ef756c6..b2a901b 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -5,7 +5,7 @@ const { proxyTest } = require('./proxy') const { Versions } = require('../src/options') describe('internal client/server test', function () { - this.timeout(220 * 1000) + this.timeout(240 * 1000) for (const version in Versions) { it('connects ' + version, async () => { diff --git a/test/proxy.js b/test/proxy.js index ad5d3ab..5c98785 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -1,7 +1,7 @@ const { createClient, createServer, Relay } = require('bedrock-protocol') const { sleep, waitFor } = require('../src/datatypes/util') -function proxyTest (version, timeout = 1000 * 20) { +function proxyTest (version, timeout = 1000 * 40) { return waitFor(res => { const server = createServer({ host: '0.0.0.0', // optional From ab8b6ddc0c3bd9f9ced2996e62c3ee5c24b0e7b3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 4 May 2021 13:56:12 -0400 Subject: [PATCH 174/458] Protocol updates, maps and rotation (#77) * protocol updates * Add clientbound map packet impl * Add missing byte rotation implementation * github: auto collapse generated diffs * protocol doc fix * protocol collision fix * Fix map pixels --- .gitattributes | 1 + data/1.16.220/protocol.json | 381 +++++++++++++++++++++------- data/latest/proto.yml | 76 +++++- data/latest/types.yaml | 72 ++++-- src/datatypes/compiler-minecraft.js | 16 ++ 5 files changed, 435 insertions(+), 111 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..cd19a23 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +data/*/*.json linguist-generated \ No newline at end of file diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index d12afd5..e859abd 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -956,100 +956,92 @@ ] ], "TransactionActions": [ - "container", - [ - { - "name": "actions", - "type": [ - "array", + "array", + { + "countType": "varint", + "type": [ + "container", + [ { - "countType": "varint", + "name": "source_type", "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "container", - "1": "global", - "2": "world_interaction", - "3": "creative", - "100": "craft_slot", - "99999": "craft" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "container": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "craft": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "world_interaction": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "craft_slot": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" + "mapper", + { + "type": "varint", + "mappings": { + "0": "container", + "1": "global", + "2": "world_interaction", + "3": "creative", + "100": "craft_slot", + "99999": "craft" } - ] + } ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "container": [ + "container", + [ + { + "name": "inventory_id", + "type": "WindowIDVarint" + } + ] + ], + "craft": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "world_interaction": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "craft_slot": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" } ] - } - ] + ] + } ], "TransactionLegacy": [ "container", @@ -2656,6 +2648,79 @@ } ] ], + "TrackedObject": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "entity", + "1": "block" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "block_position", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "block": "BlockCoordinates" + }, + "default": "void" + } + ] + } + ] + ], + "MapDecoration": [ + "container", + [ + { + "name": "type", + "type": "u8" + }, + { + "name": "rotation", + "type": "u8" + }, + { + "name": "x", + "type": "u8" + }, + { + "name": "y", + "type": "u8" + }, + { + "name": "label", + "type": "string" + }, + { + "name": "color_abgr", + "type": "varint" + } + ] + ], "WindowID": [ "mapper", { @@ -5673,8 +5738,132 @@ "container", [ { - "name": "mapinfo", - "type": "MapInfo" + "name": "map_id", + "type": "zigzag64" + }, + { + "name": "update_flags", + "type": "UpdateMapFlags" + }, + { + "name": "dimension", + "type": "u8" + }, + { + "name": "locked", + "type": "bool" + }, + { + "name": "included_in", + "type": [ + "switch", + { + "compareTo": "update_flags.initialisation", + "fields": { + "true": [ + "array", + { + "countType": "varint", + "type": "zigzag64" + } + ] + }, + "default": "void" + } + ] + }, + { + "name": "scale", + "type": [ + "switch", + { + "compareTo": "update_flags.initialisation || update_flags.decoration || update_flags.texture", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "tracked", + "type": [ + "switch", + { + "compareTo": "update_flags.decoration", + "fields": { + "true": [ + "container", + [ + { + "name": "objects", + "type": [ + "array", + { + "countType": "varint", + "type": "TrackedObject" + } + ] + }, + { + "name": "decorations", + "type": [ + "array", + { + "countType": "varint", + "type": "MapDecoration" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "texture", + "type": [ + "switch", + { + "compareTo": "update_flags.texture", + "fields": { + "true": [ + "container", + [ + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "x_offset", + "type": "zigzag32" + }, + { + "name": "y_offset", + "type": "zigzag32" + }, + { + "name": "pixels", + "type": [ + "array", + { + "countType": "varint", + "type": "varint" + } + ] + } + ] + ] + }, + "default": "void" + } + ] } ] ], @@ -8216,6 +8405,18 @@ } } ], + "UpdateMapFlags": [ + "bitflags", + { + "type": "varint", + "flags": [ + "void", + "texture", + "decoration", + "initialisation" + ] + } + ], "CommandFlags": [ "bitfield", [ diff --git a/data/latest/proto.yml b/data/latest/proto.yml index da3a9e1..1b6efdd 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -465,12 +465,22 @@ packet_take_item_entity: runtime_entity_id: varint64 target: varint +# MoveActorAbsolute is sent by the server to move an entity to an absolute position. It is typically used +# for movements where high accuracy isn't needed, such as for long range teleporting. packet_move_entity: !id: 0x12 !bound: both + # EntityRuntimeID is the runtime ID of the entity. The runtime ID is unique for each world session, and + # entities are generally identified in packets using this runtime ID. runtime_entity_id: varint64 + # Flags is a combination of flags that specify details of the movement. It is a combination of the flags + # above. flags: u8 + # Position is the position to spawn the entity on. If the entity is on a distance that the player cannot + # see it, the entity will still show up if the player moves closer. position: vec3f + # Rotation is a Vec3 holding the X, Y and Z rotation of the entity after the movement. This is a Vec3 for + # the reason that projectiles like arrows don't have yaw/pitch, but do have roll. rotation: Rotation # MovePlayer is sent by players to send their movement to the server, and by the server to update the @@ -1249,10 +1259,74 @@ packet_spawn_experience_orb: position: vec3f count: zigzag32 +UpdateMapFlags: [ "bitflags", { + "type": "varint", + "flags": [ + "void", + "texture", + "decoration", + "initialisation" + ] +}] + +# ClientBoundMapItemData is sent by the server to the client to update the data of a map shown to the client. +# It is sent with a combination of flags that specify what data is updated. +# The ClientBoundMapItemData packet may be used to update specific parts of the map only. It is not required +# to send the entire map each time when updating one part. packet_clientbound_map_item_data: !id: 0x43 !bound: client - mapinfo: MapInfo + # MapID is the unique identifier that represents the map that is updated over network. It remains + # consistent across sessions. + map_id: zigzag64 + # UpdateFlags is a combination of flags found above that indicate what parts of the map should be updated + # client-side. + update_flags: UpdateMapFlags + # Dimension is the dimension of the map that should be updated, for example the overworld (0), the nether + # (1) or the end (2). + dimension: u8 + # LockedMap specifies if the map that was updated was a locked map, which may be done using a cartography + # table. + locked: bool + # The following fields apply only for the MapUpdateFlagInitialisation. + # MapsIncludedIn holds an array of map IDs that the map updated is included in. This has to do with the + # scale of the map: Each map holds its own map ID and all map IDs of maps that include this map and have + # a bigger scale. This means that a scale 0 map will have 5 map IDs in this slice, whereas a scale 4 map + # will have only 1 (its own). + # The actual use of this field remains unknown. + included_in: update_flags.initialisation ? + if true: zigzag64[]varint + # Scale is the scale of the map as it is shown in-game. It is written when any of the MapUpdateFlags are + # set to the UpdateFlags field. + scale: update_flags.initialisation || update_flags.decoration || update_flags.texture ? + if true: u8 + # The following fields apply only for the MapUpdateFlagDecoration. + # TrackedObjects is a list of tracked objects on the map, which may either be entities or blocks. The + # client makes sure these tracked objects are actually tracked. (position updated etc.) + tracked: update_flags.decoration ? + if true: + objects: TrackedObject[]varint + decorations: MapDecoration[]varint + # Updates to the map contents itself (texture) + texture: update_flags.texture ? + if true: + # Width is the width of the texture area that was updated. The width may be a subset of the total width + # of the map. + width: zigzag32 + # Height is the height of the texture area that was updated. The height may be a subset of the total + # height of the map + height: zigzag32 + # XOffset is the X offset in pixels at which the updated texture area starts. From this X, the updated + # texture will extend exactly Width pixels to the right. + x_offset: zigzag32 + # YOffset is the Y offset in pixels at which the updated texture area starts. From this Y, the updated + # texture will extend exactly Height pixels up. + y_offset: zigzag32 + # Pixels is a list of pixel colours for the new texture of the map. It is indexed as Pixels[y][x], with + # the length of the outer slice having to be exactly Height long and the inner slices exactly Width long. + # To access this array, use $width * y + x + pixels: varint[]varint + packet_map_info_request: !id: 0x44 diff --git a/data/latest/types.yaml b/data/latest/types.yaml index d633c70..7a5595c 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -484,26 +484,25 @@ TransactionUseItem: # these actions hold one slot in which one item was changed to another. In general, the combination of # all of these actions results in a balanced inventory transaction. This should be checked to ensure that # no items are cheated into the inventory. -TransactionActions: - actions: []varint - source_type: varint => - 0: container - 1: global - 2: world_interaction - 3: creative - 100: craft_slot - 99999: craft - _: source_type? - if container or craft: - inventory_id: varint - if world_interaction: - flags: varint - if craft or craft_slot: - action: varint - default: void - slot: varint - old_item: Item - new_item: Item +TransactionActions: []varint + source_type: varint => + 0: container + 1: global + 2: world_interaction + 3: creative + 100: craft_slot + 99999: craft + _: source_type? + if container or craft: + inventory_id: WindowIDVarint + if world_interaction: + flags: varint + if craft or craft_slot: + action: varint + default: void + slot: varint + old_item: Item + new_item: Item # The Minecraft bedrock inventory system was refactored, but not all inventory actions use the new packet. # This data structure holds actions that have not been updated to the new system. @@ -1011,6 +1010,39 @@ CommandOrigin: if dev_console or test: player_entity_id: zigzag64 +# MapTrackedObject is an object on a map that is 'tracked' by the client, such as an entity or a block. This +# object may move, which is handled client-side. +TrackedObject: + # Type is the type of the tracked object. It is either MapObjectTypeEntity or MapObjectTypeBlock. + type: li32 => + 0: entity + 1: block + # EntityUniqueID is the unique ID of the entity, if the tracked object was an entity. It needs not to be + # filled out if Type is not MapObjectTypeEntity. + entity_unique_id: type ? + if entity: zigzag64 + # BlockPosition is the position of the block, if the tracked object was a block. It needs not to be + # filled out if Type is not MapObjectTypeBlock. + block_position: type ? + if block: BlockCoordinates + +# MapDecoration is a fixed decoration on a map: Its position or other properties do not change automatically +# client-side. +MapDecoration: + type: u8 + # Rotation is the rotation of the map decoration. It is byte due to the 16 fixed directions that the + # map decoration may face. + rotation: u8 + # X is the offset on the X axis in pixels of the decoration. + x: u8 + # Y is the offset on the Y axis in pixels of the decoration. + y: u8 + # Label is the name of the map decoration. This name may be of any value. + label: string + # Colour is the colour of the map decoration. Some map decoration types have a specific colour set + # automatically, whereas others may be changed. + color_abgr: varint + # Some arbitrary definitions from CBMC, Window IDs are normally # unique + sequential WindowID: i8 => diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index 6838a84..3fbc2b9 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -89,6 +89,22 @@ SizeOf.nbtLoop = ['context', (value, buffer, offset) => { return size }] +/** + * Read rotation float encoded as a byte + */ +Read.byterot = ['context', (buffer, offset) => { + const val = buffer.readUint8(buffer) + return { value: (val * (360 / 256)), size: 1 } +}] +Write.byterot = ['context', (value, buffer, offset) => { + const val = (value / (360 / 256)) + buffer.writeUint8(val, offset) + return offset + 1 +}] +SizeOf.byterot = ['context', (value, buffer, offset) => { + return 1 +}] + /** * NBT */ From a8188c07ef83332eea434053450ba3884d345a31 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 4 May 2021 14:16:23 -0400 Subject: [PATCH 175/458] Release 3.1.0 --- HISTORY.md | 7 +++++++ README.md | 2 +- package.json | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index f8583b2..4eac540 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,10 @@ +## 3.1.0 +* Add support for 1.16 +* New docs and examples +* Ping support +* Add microsoft authentication +* Codebase refactor + ## 2.4.0 * Update to version 1.12.0 * Add option to provide protocol.json diff --git a/README.md b/README.md index aebb43c..56f5f5d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Want to contribute on something important for PrismarineJS ? go to https://githu ## Installation -`npm install PrismarineJS/bedrock-protocol` +`npm install bedrock-protocol` ## Usage diff --git a/package.json b/package.json index ae9b91d..23213b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.0.0", + "version": "3.1.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { @@ -27,7 +27,7 @@ "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", - "jsp-raknet": "github:extremeheat/raknet#client", + "jsp-raknet": "latest", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", From 8de044aafacf5d497f19c66d80766146e255fe2a Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 4 May 2021 14:24:05 -0400 Subject: [PATCH 176/458] update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23213b6..688fab4 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", - "jsp-raknet": "latest", + "jsp-raknet": "^1.5.0", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", From bb88115e5e1c6d6485eb736e4bca4dc842bf82c5 Mon Sep 17 00:00:00 2001 From: Nihat <73744616+KaffinPX@users.noreply.github.com> Date: Thu, 6 May 2021 20:23:45 +0300 Subject: [PATCH 177/458] Update readme (#81) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56f5f5d..8eb7dce 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Minecraft Bedrock protocol library +# bedrock-protocol [![NPM version](https://img.shields.io/npm/v/bedrock-protocol.svg)](http://npmjs.com/package/bedrock-protocol) [![Build Status](https://github.com/PrismarineJS/bedrock-protocol/workflows/CI/badge.svg)](https://github.com/PrismarineJS/bedrock-protocol/actions?query=workflow%3A%22CI%22) [![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8) From 3a4335a2ae211726f36e35e0f0622751d1065418 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 11 May 2021 13:39:46 -0400 Subject: [PATCH 178/458] Fix third party servers, optional client encryption (#83) * Fix CBMC connections, fix js-raknet * Remove electron support * make raknet-native an optional dep * protocol: fix skin serialization * enable debugging output in tests * Fix tests * Allow server to skip encryption * update protocol docs --- data/1.16.220/protocol.json | 19 ++++++++---- data/latest/proto.yml | 2 +- data/latest/types.yaml | 7 +++-- package.json | 8 +++-- src/client.js | 5 ++++ src/datatypes/compiler-minecraft.js | 2 +- src/rak.js | 45 +++++++++++++++++++---------- src/rakWorker.js | 19 +++++------- src/serverPlayer.js | 1 + src/transforms/encryption.js | 27 ----------------- src/transforms/framer.js | 8 +++-- src/transforms/serializer.js | 13 ++++++++- test/internal.js | 1 - tools/genPacketDumps.js | 4 +-- 14 files changed, 88 insertions(+), 73 deletions(-) diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index e859abd..ea3b674 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -1667,7 +1667,7 @@ }, { "name": "data", - "type": "string" + "type": "ByteArray" } ] ], @@ -1734,7 +1734,7 @@ }, { "name": "premium", - "type": "string" + "type": "bool" }, { "name": "persona", @@ -1915,10 +1915,19 @@ { "name": "verified", "type": [ - "array", + "switch", { - "count": "records_count", - "type": "bool" + "compareTo": "type", + "fields": { + "add": [ + "array", + { + "count": "records_count", + "type": "bool" + } + ] + }, + "default": "void" } ] } diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 1b6efdd..aebfc05 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -2480,7 +2480,7 @@ packet_animate_entity: # Controller is the animation controller that is used to manage animations. These controllers decide when # to play which animation. controller: string - # BlendOutTime does not currently seem to be used. + # How long to move from the previous animation to the next. blend_out_time: lf32 # EntityRuntimeIDs is list of runtime IDs of entities that the animation should be applied to. runtime_entity_ids: varint64[]varint diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 7a5595c..888be3c 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -657,7 +657,7 @@ Recipes: []varint SkinImage: width: li32 height: li32 - data: string + data: ByteArray Skin: skin_id: string @@ -672,7 +672,7 @@ Skin: cape_data: SkinImage geometry_data: string animation_data: string - premium: string + premium: bool persona: bool cape_on_classic: bool cape_id: string @@ -708,7 +708,8 @@ PlayerRecords: is_host: bool if remove: uuid: uuid - verified: bool[]$records_count + verified: type ? + if add: bool[]$records_count ScoreEntries: type: u8 => diff --git a/package.json b/package.json index 688fab4..589ad5e 100644 --- a/package.json +++ b/package.json @@ -27,14 +27,16 @@ "debug": "^4.3.1", "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", - "jsp-raknet": "^1.5.0", + "jsp-raknet": "^2.0.0", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", - "protodef": "^1.11.0", - "raknet-native": "^1.0.1", + "protodef": "extremeheat/node-protodef#patch-1", "uuid-1345": "^1.0.2" }, + "optionalDependencies": { + "raknet-native": "^1.0.3" + }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", "bedrock-provider": "^1.0.0", diff --git a/src/client.js b/src/client.js index 049dda0..68f247c 100644 --- a/src/client.js +++ b/src/client.js @@ -195,6 +195,11 @@ class Client extends Connection { this.startGameData = pakData.params break case 'play_status': + if (this.status === ClientStatus.Authenticating) { + this.inLog('Server wants to skip encryption') + this.emit('join') + this.status = ClientStatus.Initializing + } this.onPlayStatus(pakData.params) break default: diff --git a/src/datatypes/compiler-minecraft.js b/src/datatypes/compiler-minecraft.js index 3fbc2b9..3dd9483 100644 --- a/src/datatypes/compiler-minecraft.js +++ b/src/datatypes/compiler-minecraft.js @@ -93,7 +93,7 @@ SizeOf.nbtLoop = ['context', (value, buffer, offset) => { * Read rotation float encoded as a byte */ Read.byterot = ['context', (buffer, offset) => { - const val = buffer.readUint8(buffer) + const val = buffer.readUint8(offset) return { value: (val * (360 / 256)), size: 1 } }] Write.byterot = ['context', (value, buffer, offset) => { diff --git a/src/rak.js b/src/rak.js index 05cacc0..d8e99ee 100644 --- a/src/rak.js +++ b/src/rak.js @@ -1,13 +1,11 @@ const { EventEmitter } = require('events') -const Listener = require('jsp-raknet/listener') -const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') -const Reliability = require('jsp-raknet/protocol/reliability') -const RakClient = require('jsp-raknet/client') const ConnWorker = require('./rakWorker') const { waitFor } = require('./datatypes/util') +// TODO: better way to switch, via an option try { var { Client, Server, PacketPriority, PacketReliability } = require('raknet-native') // eslint-disable-line } catch (e) { + var { Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet') // eslint-disable-line console.debug('[raknet] native not found, using js', e) } @@ -21,7 +19,9 @@ class RakNativeClient extends EventEmitter { this.raknet = new Client(options.host, options.port, { protocolVersion: 10 }) this.raknet.on('encapsulated', ({ buffer, address }) => { - this.onEncapsulated(buffer, address) + if (this.connected) { // Discard packets that are queued to be sent to us after close + this.onEncapsulated(buffer, address) + } }) this.raknet.on('connect', () => { @@ -109,13 +109,16 @@ class RakNativeServer extends EventEmitter { class RakJsClient extends EventEmitter { constructor (options = {}) { super() + this.options = options this.onConnected = () => { } this.onEncapsulated = () => { } if (options.useWorkers) { this.connect = this.workerConnect + this.close = reason => this.worker?.postMessage({ type: 'close', reason }) this.sendReliable = this.workerSendReliable } else { this.connect = this.plainConnect + this.close = this.plainClose this.sendReliable = this.plainSendReliable } } @@ -131,7 +134,7 @@ class RakJsClient extends EventEmitter { } case 'encapsulated': { const [ecapsulated, address] = evt.args - this.onEncapsulated(ecapsulated.buffer, address.hash) + this.onEncapsulated(ecapsulated, address.hash) break } } @@ -139,7 +142,7 @@ class RakJsClient extends EventEmitter { } async plainConnect (host = this.options.host, port = this.options.port) { - this.raknet = new RakClient(host, port) + this.raknet = new Client(host, port) await this.raknet.connect() this.raknet.on('connecting', () => { @@ -161,16 +164,27 @@ class RakJsClient extends EventEmitter { this.connection.addEncapsulatedToQueue(sendPacket) if (immediate) this.connection.sendQueue() } + + plainClose (reason) { + this.raknet.close(reason) + } + + ping () { + // TODO + } } class RakJsServer extends EventEmitter { - constructor (options = {}) { + constructor (options = {}, server) { super() this.options = options + this.server = server this.onOpenConnection = () => { } this.onCloseConnection = () => { } - this.onEncapsulated = () => { } - + this.onEncapsulated = (packet, address) => server.onEncapsulated(packet.buffer, address) + this.updateAdvertisement = () => { + // TODO + } if (options.useWorkers) { throw Error('nyi') } else { @@ -179,15 +193,14 @@ class RakJsServer extends EventEmitter { } async plainListen () { - this.raknet = new Listener() + this.raknet = new Server(this.options.host, this.options.port, this.server.getAdvertisement()) await this.raknet.listen(this.options.host, this.options.port) this.raknet.on('openConnection', (conn) => { - conn.sendReliable = function (buffer, immediate) { + conn.sendReliable = (buffer, immediate) => { const sendPacket = new EncapsulatedPacket() sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = buffer - this.connection.addEncapsulatedToQueue(sendPacket) - if (immediate) this.raknet.sendQueue() + conn.addEncapsulatedToQueue(sendPacket, immediate ? 1 : 0) } this.onOpenConnection(conn) }) @@ -197,6 +210,6 @@ class RakJsServer extends EventEmitter { } module.exports = { - RakClient: Client ? RakNativeClient : RakJsClient, - RakServer: Server ? RakNativeServer : RakJsServer + RakClient: PacketPriority ? RakNativeClient : RakJsClient, + RakServer: PacketPriority ? RakNativeServer : RakJsServer } diff --git a/src/rakWorker.js b/src/rakWorker.js index 97643a9..f6e4046 100644 --- a/src/rakWorker.js +++ b/src/rakWorker.js @@ -1,7 +1,6 @@ -const RakClient = require('jsp-raknet/client') const { Worker, isMainThread, parentPort } = require('worker_threads') -const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') -const Reliability = require('jsp-raknet/protocol/reliability') +const { Client, EncapsulatedPacket, Reliability } = require('jsp-raknet') +const debug = require('debug')('minecraft-protocol') function connect (host, port) { if (isMainThread) { @@ -17,26 +16,24 @@ function main () { parentPort.on('message', (evt) => { if (evt.type === 'connect') { const { host, port } = evt - raknet = new RakClient(host, port) + raknet = new Client(host, port) raknet.connect().then(() => { - console.log('Raknet Connected!') + debug('Raknet Connected!') }) raknet.on('connecting', () => { - console.log(`[client] connecting to ${host}/${port}`) + debug(`[client] connecting to ${host}/${port}`) parentPort.postMessage('message', { type: 'connecting' }) - console.log('Raknet', raknet) }) raknet.once('connected', (connection) => { - console.log('[worker] connected!') + debug('[worker] connected!') globalThis.raknetConnection = connection parentPort.postMessage({ type: 'connected' }) }) raknet.on('encapsulated', (...args) => { - // console.log('-> ENCAP BUF', args) setTimeout(() => { parentPort.postMessage({ type: 'encapsulated', args }) }, 100) @@ -46,8 +43,6 @@ function main () { console.log('Raw packet', buffer, inetAddr) }) } else if (evt.type === 'queueEncapsulated') { - // console.log('SEND', globalThis.raknetConnection, evt.packet) - const sendPacket = new EncapsulatedPacket() sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = evt.packet @@ -56,6 +51,8 @@ function main () { if (evt.immediate) { globalThis.raknetConnection?.sendQueue() } + } else if (evt.type === 'close') { + raknet.close() } }) } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index bbbdcb6..9005cef 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -54,6 +54,7 @@ class Player extends Connection { var { key, userData, skinData } = this.decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line } catch (e) { console.error(e) + console.debug(authChain.chain, skinChain) this.disconnect('Server authentication error') return } diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 56dfc44..c878c8d 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -1,43 +1,16 @@ -const { Transform } = require('readable-stream') const crypto = require('crypto') const Zlib = require('zlib') -if (globalThis.isElectron) var { CipherGCM, CipherCFB8 } = require('raknet-native') // eslint-disable-line function createCipher (secret, initialValue, cipherAlgorithm) { if (crypto.getCiphers().includes(cipherAlgorithm)) { return crypto.createCipheriv(cipherAlgorithm, secret, initialValue) } - return new Cipher(secret, initialValue) } function createDecipher (secret, initialValue, cipherAlgorithm) { if (crypto.getCiphers().includes(cipherAlgorithm)) { return crypto.createDecipheriv(cipherAlgorithm, secret, initialValue) } - return new Decipher(secret, initialValue) -} - -class Cipher extends Transform { - constructor (gcm, secret, iv) { - super() - this.aes = gcm ? new CipherGCM(secret, iv) : new CipherCFB8(secret, iv) - } - - _transform (chunk, enc, cb) { - const ciphered = this.aes.cipher(chunk) - cb(null, ciphered) - } -} - -class Decipher extends Transform { - constructor (gcm, secret, iv) { - super() - this.aes = gcm ? new CipherGCM(secret, iv) : new CipherCFB8(secret, iv) - } - - _transform (chunk, enc, cb) { - cb(null, this.aes.decipher(chunk)) - } } function computeCheckSum (packetPlaintext, sendCounter, secretKeyBytes) { diff --git a/src/transforms/framer.js b/src/transforms/framer.js index 38d04c4..77f41e9 100644 --- a/src/transforms/framer.js +++ b/src/transforms/framer.js @@ -12,10 +12,14 @@ class Framer { static decode (buf, cb) { // Read header if (buf[0] !== 0xfe) throw Error('bad batch packet header ' + buf[0]) + const buffer = buf.slice(1) // Decode the payload - zlib.inflateRaw(buf.slice(1), { chunkSize: 1024 * 1024 * 2 }, (err, inflated) => { - if (err) throw err + zlib.inflateRaw(buffer, { chunkSize: 1024 * 1024 * 2 }, (err, inflated) => { + if (err) { // Try to decode without compression + Framer.getPackets(buffer) + return + } cb(Framer.getPackets(inflated)) }) } diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index d31b0dc..f78e4c8 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -2,6 +2,17 @@ const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler const { FullPacketParser, Serializer } = require('protodef') const { join } = require('path') +class Parser extends FullPacketParser { + parsePacketBuffer (buffer) { + try { + return super.parsePacketBuffer(buffer) + } catch (e) { + console.error('While decoding', buffer.toString('hex')) + throw e + } + } +} + // Compiles the ProtoDef schema at runtime function createProtocol (version) { const protocol = require(join(__dirname, `../../data/${version}/protocol.json`)).types @@ -40,7 +51,7 @@ function createSerializer (version) { function createDeserializer (version) { const proto = getProtocol(version) - return new FullPacketParser(proto, 'mcpe_packet') + return new Parser(proto, 'mcpe_packet') } module.exports = { diff --git a/test/internal.js b/test/internal.js index 9cdc76c..ff8cedf 100644 --- a/test/internal.js +++ b/test/internal.js @@ -1,4 +1,3 @@ -// process.env.DEBUG = 'minecraft-protocol raknet' const { Server, Client } = require('../') const { dumpPackets } = require('../tools/genPacketDumps') const DataProvider = require('../data/provider') diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index a5b63b7..39a1fce 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -17,13 +17,13 @@ function hasDumps (version) { let loop -async function dump (version, force) { +async function dump (version, force = true) { const random = ((Math.random() * 100) | 0) const port = 19130 + random const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port }) - console.log('Started server') + console.log('Started dump server') const client = new Client({ host: '127.0.0.1', port, From b8f6ab4ed387157701730dbb9d88c9e3fec378a7 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 11 May 2021 21:09:35 -0400 Subject: [PATCH 179/458] Remove crypto deps Use node crypto lib --- package.json | 4 +-- src/auth/encryption.js | 72 ++++++++++++----------------------------- src/auth/login.js | 20 +++++------- src/auth/loginVerify.js | 24 ++++---------- 4 files changed, 37 insertions(+), 83 deletions(-) diff --git a/package.json b/package.json index 589ad5e..1022e71 100644 --- a/package.json +++ b/package.json @@ -23,11 +23,9 @@ "dependencies": { "@azure/msal-node": "^1.0.0-beta.6", "@xboxreplay/xboxlive-auth": "^3.3.3", - "asn1": "^0.2.4", "debug": "^4.3.1", - "ec-pem": "^0.18.0", "jsonwebtoken": "^8.5.1", - "jsp-raknet": "^2.0.0", + "jsp-raknet": "^2.1.0", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", diff --git a/src/auth/encryption.js b/src/auth/encryption.js index 95d87b1..2656a99 100644 --- a/src/auth/encryption.js +++ b/src/auth/encryption.js @@ -1,27 +1,26 @@ -const { Ber } = require('asn1') const { ClientStatus } = require('../connection') const JWT = require('jsonwebtoken') const crypto = require('crypto') -const ecPem = require('ec-pem') const debug = require('debug')('minecraft-protocol') const SALT = '🧂' const curve = 'secp384r1' +const pem = { format: 'pem', type: 'sec1' } +const der = { format: 'der', type: 'spki' } function Encrypt (client, server, options) { - client.ecdhKeyPair = crypto.createECDH(curve) - client.ecdhKeyPair.generateKeys() - client.clientX509 = writeX509PublicKey(client.ecdhKeyPair.getPublicKey()) + client.ecdhKeyPair = crypto.generateKeyPairSync('ec', { namedCurve: curve }) + client.publicKeyDER = client.ecdhKeyPair.publicKey.export(der) + client.privateKeyPEM = client.ecdhKeyPair.privateKey.export(pem) + console.log(client.publicKeyPEM) + client.clientX509 = client.publicKeyDER.toString('base64') function startClientboundEncryption (publicKey) { debug('[encrypt] Client pub key base64: ', publicKey) - const pubKeyBuf = readX509PublicKey(publicKey.key) - const alice = client.ecdhKeyPair - const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 - const alicePEMPrivate = alicePEM.encodePrivateKey() + const pubKeyDer = crypto.createPublicKey({ key: Buffer.from(publicKey.key, 'base64'), ...der }) // Shared secret from the client's public key + our private key - client.sharedSecret = alice.computeSecret(pubKeyBuf) + client.sharedSecret = crypto.diffieHellman({ privateKey: client.ecdhKeyPair.privateKey, publicKey: pubKeyDer }) // Secret hash we use for packet encryption: // From the public key of the remote and the private key @@ -36,15 +35,12 @@ function Encrypt (client, server, options) { client.secretKeyBytes = secretHash.digest() // console.log('[encrypt] Shared hash', client.secretKeyBytes) - const x509 = writeX509PublicKey(alice.getPublicKey()) const token = JWT.sign({ salt: toBase64(SALT), - signedToken: alice.getPublicKey('base64') - }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: x509 } }) + signedToken: client.clientX509 + }, client.ecdhKeyPair.privateKey, { algorithm: 'ES384', header: { x5u: client.clientX509 } }) - client.write('server_to_client_handshake', { - token: token - }) + client.write('server_to_client_handshake', { token }) // The encryption scheme is AES/CFB8/NoPadding with the // secret key being the result of the sha256 above and @@ -57,28 +53,27 @@ function Encrypt (client, server, options) { debug('[encrypt] Starting serverbound encryption', token) const jwt = token?.token if (!jwt) { - // TODO: allow connecting to servers without encryption throw Error('Server did not return a valid JWT, cannot start encryption!') } + // TODO: Should we do some JWT signature validation here? Seems pointless - const alice = client.ecdhKeyPair + const [header, payload] = jwt.split('.').map(k => Buffer.from(k, 'base64')) const head = JSON.parse(String(header)) const body = JSON.parse(String(payload)) - const serverPublicKey = readX509PublicKey(head.x5u) - client.sharedSecret = alice.computeSecret(serverPublicKey) - // console.log('[encrypt] Shared secret', client.sharedSecret) + + const pubKeyDer = crypto.createPublicKey({ key: Buffer.from(head.x5u, 'base64'), ...der }) + // Shared secret from the client's public key + our private key + client.sharedSecret = crypto.diffieHellman({ privateKey: client.ecdhKeyPair.privateKey, publicKey: pubKeyDer }) const salt = Buffer.from(body.salt, 'base64') - const secretHash = crypto.createHash('sha256') secretHash.update(salt) secretHash.update(client.sharedSecret) client.secretKeyBytes = secretHash.digest() - // console.log('[encrypt] Shared hash', client.secretKeyBytes) - const initial = client.secretKeyBytes.slice(0, 16) - client.startEncryption(initial) + const iv = client.secretKeyBytes.slice(0, 16) + client.startEncryption(iv) // It works! First encrypted packet :) client.write('client_to_server_handshake', {}) @@ -94,29 +89,4 @@ function toBase64 (string) { return Buffer.from(string).toString('base64') } -function readX509PublicKey (key) { - const reader = new Ber.Reader(Buffer.from(key, 'base64')) - reader.readSequence() - reader.readSequence() - reader.readOID() // Hey, I'm an elliptic curve - reader.readOID() // This contains the curve type, could be useful - return Buffer.from(reader.readString(Ber.BitString, true)).slice(1) -} - -function writeX509PublicKey (key) { - const writer = new Ber.Writer() - writer.startSequence() - writer.startSequence() - writer.writeOID('1.2.840.10045.2.1') - writer.writeOID('1.3.132.0.34') - writer.endSequence() - writer.writeBuffer(Buffer.concat([Buffer.from([0x00]), key]), Ber.BitString) - writer.endSequence() - return writer.buffer.toString('base64') -} - -module.exports = { - readX509PublicKey, - writeX509PublicKey, - Encrypt -} +module.exports = { Encrypt } diff --git a/src/auth/login.js b/src/auth/login.js index afa74fb..c55665c 100644 --- a/src/auth/login.js +++ b/src/auth/login.js @@ -1,18 +1,15 @@ const fs = require('fs') const JWT = require('jsonwebtoken') const DataProvider = require('../../data/provider') -const ecPem = require('ec-pem') -const curve = 'secp384r1' const { nextUUID } = require('../datatypes/util') +const { PUBLIC_KEY } = require('./constants') +const algorithm = 'ES384' module.exports = (client, server, options) => { const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') client.createClientChain = (mojangKey, offline) => { - mojangKey = mojangKey || require('./constants').PUBLIC_KEY - const alice = client.ecdhKeyPair - const alicePEM = ecPem(alice, curve) // https://github.com/nodejs/node/issues/15116#issuecomment-384790125 - const alicePEMPrivate = alicePEM.encodePrivateKey() + const privateKey = client.ecdhKeyPair.privateKey let token if (offline) { @@ -25,16 +22,16 @@ module.exports = (client, server, options) => { certificateAuthority: true, identityPublicKey: client.clientX509 } - token = JWT.sign(payload, alicePEMPrivate, { algorithm: 'ES384', notBefore: 0, issuer: 'self', expiresIn: 60 * 60, header: { x5u: client.clientX509 } }) + token = JWT.sign(payload, privateKey, { algorithm, notBefore: 0, issuer: 'self', expiresIn: 60 * 60, header: { x5u: client.clientX509 } }) } else { token = JWT.sign({ - identityPublicKey: mojangKey, + identityPublicKey: mojangKey || PUBLIC_KEY, certificateAuthority: true - }, alicePEMPrivate, { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + }, privateKey, { algorithm, header: { x5u: client.clientX509 } }) } client.clientIdentityChain = token - client.createClientUserChain(alicePEMPrivate) + client.createClientUserChain(privateKey) } client.createClientUserChain = (privateKey) => { @@ -82,7 +79,6 @@ module.exports = (client, server, options) => { const customPayload = options.skinData || {} payload = { ...payload, ...customPayload } - client.clientUserChain = JWT.sign(payload, privateKey, - { algorithm: 'ES384', header: { x5u: client.clientX509 } }) + client.clientUserChain = JWT.sign(payload, privateKey, { algorithm, header: { x5u: client.clientX509 } }) } } diff --git a/src/auth/loginVerify.js b/src/auth/loginVerify.js index 233e729..722dd17 100644 --- a/src/auth/loginVerify.js +++ b/src/auth/loginVerify.js @@ -1,11 +1,14 @@ const JWT = require('jsonwebtoken') const constants = require('./constants') const debug = require('debug')('minecraft-protocol') +const crypto = require('crypto') module.exports = (client, server, options) => { // Refer to the docs: // https://web.archive.org/web/20180917171505if_/https://confluence.yawk.at/display/PEPROTOCOL/Game+Packets#GamePackets-Login + const getDER = b64 => crypto.createPublicKey({ key: Buffer.from(b64, 'base64'), format: 'der', type: 'spki' }) + function verifyAuth (chain) { let data = {} @@ -16,9 +19,9 @@ module.exports = (client, server, options) => { // signed by Mojang by checking the x509 public key in the JWT headers let didVerify = false - let pubKey = mcPubKeyToPem(getX5U(chain[0])) // the first one is client signed, allow it + let pubKey = getDER(getX5U(chain[0])) // the first one is client signed, allow it let finalKey = null - // console.log(pubKey) + for (const token of chain) { const decoded = JWT.verify(token, pubKey, { algorithms: ['ES384'] }) // console.log('Decoded', decoded) @@ -30,7 +33,7 @@ module.exports = (client, server, options) => { debug('Verified client with mojang key', x5u) } - pubKey = decoded.identityPublicKey ? mcPubKeyToPem(decoded.identityPublicKey) : x5u + pubKey = decoded.identityPublicKey ? getDER(decoded.identityPublicKey) : x5u finalKey = decoded.identityPublicKey || finalKey // non pem data = { ...data, ...decoded } } @@ -44,7 +47,7 @@ module.exports = (client, server, options) => { } function verifySkin (publicKey, token) { - const pubKey = mcPubKeyToPem(publicKey) + const pubKey = getDER(publicKey) const decoded = JWT.verify(token, pubKey, { algorithms: ['ES384'] }) return decoded } @@ -71,16 +74,3 @@ function getX5U (token) { const hjson = JSON.parse(hdec) return hjson.x5u } - -function mcPubKeyToPem (mcPubKeyBuffer) { - if (mcPubKeyBuffer[0] === '-') return mcPubKeyBuffer - let pem = '-----BEGIN PUBLIC KEY-----\n' - let base64PubKey = mcPubKeyBuffer.toString('base64') - const maxLineLength = 65 - while (base64PubKey.length > 0) { - pem += base64PubKey.substring(0, maxLineLength) + '\n' - base64PubKey = base64PubKey.substring(maxLineLength) - } - pem += '-----END PUBLIC KEY-----\n' - return pem -} From 7d532e8c7ec30b07b454d4fdd8b6796702447af1 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 11 May 2021 21:40:53 -0400 Subject: [PATCH 180/458] protocol updates --- data/1.16.220/protocol.json | 74 ++++++++++++++++++++------------ data/latest/proto.yml | 84 ++++++++++++++++++++++++------------- data/latest/types.yaml | 13 +++--- 3 files changed, 106 insertions(+), 65 deletions(-) diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index ea3b674..115676d 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -212,7 +212,7 @@ } ] ], - "BlockPalette": [ + "BlockProperties": [ "array", { "countType": "varint", @@ -4287,8 +4287,8 @@ "type": "zigzag32" }, { - "name": "block_palette", - "type": "BlockPalette" + "name": "block_properties", + "type": "BlockProperties" }, { "name": "itemstates", @@ -5967,6 +5967,31 @@ { "compareTo": "type", "fields": { + "show_bar": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "progress", + "type": "lf32" + }, + { + "name": "screen_darkening", + "type": "li16" + }, + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], "register_player": [ "container", [ @@ -5985,16 +6010,21 @@ } ] ], - "show": [ + "set_bar_progress": [ + "container", + [ + { + "name": "progress", + "type": "lf32" + } + ] + ], + "set_bar_title": [ "container", [ { "name": "title", "type": "string" - }, - { - "name": "bar_progress", - "type": "lf32" } ] ], @@ -6002,8 +6032,16 @@ "container", [ { - "name": "darkness_factor", + "name": "screen_darkening", "type": "li16" + }, + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" } ] ], @@ -6019,24 +6057,6 @@ "type": "varint" } ] - ], - "set_bar_progress": [ - "container", - [ - { - "name": "bar_progress", - "type": "lf32" - } - ] - ], - "set_bar_title": [ - "container", - [ - { - "name": "title", - "type": "string" - } - ] ] }, "default": "void" diff --git a/data/latest/proto.yml b/data/latest/proto.yml index aebfc05..57bbd76 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -21,30 +21,30 @@ nbt: native # load the packet map file !import: packet_map.yml -#todo: docs !StartDocs: Packets # # Login Sequence # The login process is as follows: # -# C→S: [Login](#packet_login) -# S→C: [Server To Client Handshake](#packet_server_to_client_handshake) -# C→S: [Client To Server Handshake](#packet_client_to_server_handshake) -# S→C: [Play Status (Login success)](#packet_play_status) -# To spawn, the following packets should be sent, in order, after the ones above: +# * C→S: [Login](#packet_login) +# * S→C: [Server To Client Handshake](#packet_server_to_client_handshake) +# * C→S: [Client To Server Handshake](#packet_client_to_server_handshake) +# * S→C: [Play Status (Login success)](#packet_play_status) +# * To spawn, the following packets should be sent, in order, after the ones above: +# * S→C: [Resource Packs Info](#packet_resource_packs_info) +# * C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) +# * S→C: [Resource Pack Stack](#packet_resource_pack_stack) +# * C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) +# * S→C: [Start Game](#packet_start_game) +# * S→C: [Creative Content](#packet_creative_content) +# * S→C: [Biome Definition List](#packet_biome_definition_list) +# * S→C: [Chunks](#packet_level_chunk) +# * S→C: [Play Status (Player spawn)](#packet_play_status) # -# S→C: [Resource Packs Info](#packet_resource_packs_info) -# C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) -# S→C: [Resource Pack Stack](#packet_resource_pack_stack) -# C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) -# S→C: [Start Game](#packet_start_game) -# S→C: [Creative Content](#packet_creative_content) -# S→C: [Biome Definition List](#packet_biome_definition_list) -# S→C: [Chunks](#packet_level_chunk) -# S→C: [Play Status (Player spawn)](#packet_play_status) # If there are no resource packs being sent, a Resource Pack Stack can be sent directly # after Resource Packs Info to avoid the client responses. - +# +# === packet_login: !id: 0x01 @@ -366,15 +366,17 @@ packet_start_game: # results both client- and server-side. enchantment_seed: zigzag32 - ## This is not sent anymore in protocol versions > 419 (Bedrock Edition v1.16.100) - ## A list of all blocks registered on the server. - block_palette: BlockPalette + # BlockProperties is a list of all the custom blocks registered on the server. + block_properties: BlockProperties # A list of all items with their legacy IDs which are available in the game. # Failing to send any of the items that are in the game will crash mobile clients. itemstates: Itemstates # A unique ID specifying the multi-player session of the player. # A random UUID should be filled out for this field. multiplayer_correlation_id: string + # ServerAuthoritativeInventory specifies if the server authoritative inventory system is enabled. This + # is a new system introduced in 1.16. Backwards compatibility with the inventory transactions has to + # some extent been preserved, but will eventually be removed. server_authoritative_inventory: bool @@ -1387,20 +1389,41 @@ packet_boss_event: # S2C: Not implemented :( Intended to alter bar appearance, but these currently produce no effect on client-side whatsoever. 7: texture _: type? - if register_player or unregister_player: - player_id: zigzag64 - if show: + if show_bar: + # BossBarTitle is the title shown above the boss bar. It currently does not function, and instead uses + # the name tag of the boss entity at all times. It is only set if the EventType is BossEventShow or + # BossEventTitle. + title: string + # HealthPercentage is the percentage of health that is shown in the boss bar. It currently does not + # function, and instead uses the health percentage of the boss entity at all times. It is only set if the + # EventType is BossEventShow or BossEventHealthPercentage. + progress: lf32 + # ScreenDarkening currently seems not to do anything. + screen_darkening: li16 + # Colour is the colour of the boss bar that is shown when a player is subscribed. It currently does not + # function. It is only set if the EventType is BossEventShow, BossEventAppearanceProperties or + # BossEventTexture. + # Format is ARGB + color: varint + # Overlay is the overlay of the boss bar that is shown on top of the boss bar when a player is + # subscribed. It currently does not function. It is only set if the EventType is BossEventShow, + # BossEventAppearanceProperties or BossEventTexture. + overlay: varint + if register_player or unregister_player: + # PlayerUniqueID is the unique ID of the player that is registered to or unregistered from the boss + # fight. It is set if EventType is either BossEventRegisterPlayer or BossEventUnregisterPlayer. + player_id: zigzag64 + if set_bar_progress: + progress: lf32 + if set_bar_title: title: string - bar_progress: lf32 if update_properties: - darkness_factor: li16 + screen_darkening: li16 + color: varint + overlay: varint if texture: color: varint overlay: varint - if set_bar_progress: - bar_progress: lf32 - if set_bar_title: - title: string packet_show_credits: !id: 0x4b @@ -1418,8 +1441,9 @@ packet_available_commands: # The length of the enums for all the command paramaters in this packet values_len: varint # Not read from stream: instead calculated from the `values_len` field - # If the values_len < 0xff => byte - # If the values_len < 0xffff => short + # + # If the values_len < 0xff => byte, + # If the values_len < 0xffff => short, # If the values_len < 0xffffff => int _enum_type: '["enum_size_based_on_values_len"]' # Here all the enum values for all of the possible commands are stored to one array palette diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 888be3c..8174c0f 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -1,4 +1,4 @@ -# !StartDocs: Types +!StartDocs: Types BehaviourPackInfos: []li16 uuid: string @@ -66,7 +66,7 @@ Blob: # Payload in it. payload: ByteArray -BlockPalette: []varint +BlockProperties: []varint name: string state: nbt @@ -75,7 +75,7 @@ Itemstates: []varint runtime_id: li16 component_based: bool -# Start of item crap ... + ItemExtraDataWithBlockingTick: has_nbt: lu16 => @@ -102,7 +102,7 @@ ItemExtraDataWithoutBlockingTick: can_place_on: ShortArray[]li32 can_destroy: ShortArray[]li32 -# Same as below but without a "networkStackID" boolean ... +# Same as below but without a "networkStackID" boolean ItemLegacy: network_id: zigzag32 _: network_id? @@ -140,8 +140,6 @@ Item: if 355: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]' -# end of item crap - vec3i: x: zigzag32 y: zigzag32 @@ -632,8 +630,7 @@ Recipes: []varint recipe_id: string width: zigzag32 height: zigzag32 - # todo: can this become - # RecipeIngredient[$height][$width] or RecipeIngredient[]$height[]$width ? + # 2D input array, size of width*height input: []$width _: RecipeIngredient[]$height output: ItemLegacy[]varint From 879a4c21ba07f2e181f48d768428e35c150ffb2c Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 12 May 2021 04:20:35 -0400 Subject: [PATCH 181/458] Rename src/auth -> src/handshake --- src/client.js | 8 ++++---- src/{auth => handshake}/constants.js | 0 src/{auth/encryption.js => handshake/keyExchange.js} | 12 +++++++----- src/{auth => handshake}/login.js | 0 src/{auth => handshake}/loginVerify.js | 0 src/serverPlayer.js | 8 ++++---- 6 files changed, 15 insertions(+), 13 deletions(-) rename src/{auth => handshake}/constants.js (100%) rename src/{auth/encryption.js => handshake/keyExchange.js} (92%) rename src/{auth => handshake}/login.js (100%) rename src/{auth => handshake}/loginVerify.js (100%) diff --git a/src/client.js b/src/client.js index 68f247c..68c8886 100644 --- a/src/client.js +++ b/src/client.js @@ -7,9 +7,9 @@ const debug = require('debug')('minecraft-protocol') const Options = require('./options') const auth = require('./client/auth') -const { Encrypt } = require('./auth/encryption') -const Login = require('./auth/login') -const LoginVerify = require('./auth/loginVerify') +const { KeyExchange } = require('./handshake/keyExchange') +const Login = require('./handshake/login') +const LoginVerify = require('./handshake/loginVerify') const debugging = false @@ -25,7 +25,7 @@ class Client extends Connection { this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) - Encrypt(this, null, this.options) + KeyExchange(this, null, this.options) Login(this, null, this.options) LoginVerify(this, null, this.options) diff --git a/src/auth/constants.js b/src/handshake/constants.js similarity index 100% rename from src/auth/constants.js rename to src/handshake/constants.js diff --git a/src/auth/encryption.js b/src/handshake/keyExchange.js similarity index 92% rename from src/auth/encryption.js rename to src/handshake/keyExchange.js index 2656a99..e4dfe54 100644 --- a/src/auth/encryption.js +++ b/src/handshake/keyExchange.js @@ -8,7 +8,8 @@ const curve = 'secp384r1' const pem = { format: 'pem', type: 'sec1' } const der = { format: 'der', type: 'spki' } -function Encrypt (client, server, options) { +function KeyExchange (client, server, options) { + // Generate a key pair at program start up client.ecdhKeyPair = crypto.generateKeyPairSync('ec', { namedCurve: curve }) client.publicKeyDER = client.ecdhKeyPair.publicKey.export(der) client.privateKeyPEM = client.ecdhKeyPair.privateKey.export(pem) @@ -31,10 +32,9 @@ function Encrypt (client, server, options) { const secretHash = crypto.createHash('sha256') secretHash.update(SALT) secretHash.update(client.sharedSecret) - // console.log('[encrypt] Shared secret', client.sharedSecret) client.secretKeyBytes = secretHash.digest() - // console.log('[encrypt] Shared hash', client.secretKeyBytes) + const token = JWT.sign({ salt: toBase64(SALT), signedToken: client.clientX509 @@ -56,13 +56,14 @@ function Encrypt (client, server, options) { throw Error('Server did not return a valid JWT, cannot start encryption!') } - // TODO: Should we do some JWT signature validation here? Seems pointless + // No verification here, not needed const [header, payload] = jwt.split('.').map(k => Buffer.from(k, 'base64')) const head = JSON.parse(String(header)) const body = JSON.parse(String(payload)) const pubKeyDer = crypto.createPublicKey({ key: Buffer.from(head.x5u, 'base64'), ...der }) + // Shared secret from the client's public key + our private key client.sharedSecret = crypto.diffieHellman({ privateKey: client.ecdhKeyPair.privateKey, publicKey: pubKeyDer }) @@ -76,6 +77,7 @@ function Encrypt (client, server, options) { client.startEncryption(iv) // It works! First encrypted packet :) + client.write('client_to_server_handshake', {}) this.emit('join') client.status = ClientStatus.Initializing @@ -89,4 +91,4 @@ function toBase64 (string) { return Buffer.from(string).toString('base64') } -module.exports = { Encrypt } +module.exports = { KeyExchange } diff --git a/src/auth/login.js b/src/handshake/login.js similarity index 100% rename from src/auth/login.js rename to src/handshake/login.js diff --git a/src/auth/loginVerify.js b/src/handshake/loginVerify.js similarity index 100% rename from src/auth/loginVerify.js rename to src/handshake/loginVerify.js diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 9005cef..7335d6d 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -3,9 +3,9 @@ const fs = require('fs') const Options = require('./options') const debug = require('debug')('minecraft-protocol') -const { Encrypt } = require('./auth/encryption') -const Login = require('./auth/login') -const LoginVerify = require('./auth/loginVerify') +const { KeyExchange } = require('./handshake/keyExchange') +const Login = require('./handshake/login') +const LoginVerify = require('./handshake/loginVerify') class Player extends Connection { constructor (server, connection) { @@ -16,7 +16,7 @@ class Player extends Connection { this.connection = connection this.options = server.options - Encrypt(this, server, server.options) + KeyExchange(this, server, server.options) Login(this, server, server.options) LoginVerify(this, server, server.options) From 76febb29f1fb51c0984dbd39e496341d55515232 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 19 May 2021 09:53:55 -0400 Subject: [PATCH 182/458] Support xbox title + live.com auth (#86) * preliminary support for xbox title + live.com auth * cleanup * export title list * add to api docs * Verify that minecraft token has titleId if did titleAuth * Minor changes --- README.md | 4 +- docs/API.md | 1 + docs/FAQ.md | 5 +- examples/clientReadmeExample.js | 4 +- index.d.ts | 2 + index.js | 4 +- package.json | 4 +- src/client/auth.js | 2 +- src/client/authConstants.js | 8 +- src/client/authFlow.js | 47 ++++- src/client/titles.js | 4 + src/client/tokens.js | 320 ++++++++++++++++++++++++++++++-- 12 files changed, 371 insertions(+), 34 deletions(-) create mode 100644 src/client/titles.js diff --git a/README.md b/README.md index 8eb7dce..1c87815 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,9 @@ const bedrock = require('bedrock-protocol') const server = new bedrock.createServer({ host: '0.0.0.0', // optional. host to bind as. port: 19132, // optional - version: '1.16.220' // optional. The server version, latest if not specified. + version: '1.16.220', // optional. The server version, latest if not specified. + // Optional for some servers which verify the title ID: + // authTitle: bedrock.title.MinecraftNintendoSwitch }) server.on('connect', client => { diff --git a/docs/API.md b/docs/API.md index 071cb6b..23de8f1 100644 --- a/docs/API.md +++ b/docs/API.md @@ -13,6 +13,7 @@ Returns a `Client` instance and connects to the server. | version | *optional* | Version to connect as.
(Future feature, see [#69][1]) If not specified, should automatically match server version.
(Current feature) Defaults to latest version. | | offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth. | | username | Conditional | Required if `offline` set to true : Username to connect to server as. | +| authTitle | *optional* | The title ID to connect as, see the README for usage. | | connectTimeout | *optional* | default to **9000ms**. How long to wait in milliseconds while trying to connect to server. | | onMsaCode | *optional* | Callback called when signing in with a microsoft account with device code auth, `data` is an object documented [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code#device-authorization-response) | | profilesFolder | *optional* | Where to store cached authentication tokens. Defaults to .minecraft, or the node_modules folder if not found. | diff --git a/docs/FAQ.md b/docs/FAQ.md index c4a5f06..556eedf 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -4,4 +4,7 @@ This issue occurs due to loopback restrictions on Windows 10 UWP apps. To lift t ```ps CheckNetIsolation LoopbackExempt -a -n="Microsoft.MinecraftUWP_8wekyb3d8bbwe" -``` \ No newline at end of file +``` +## Kicked during login + +Some servers can kick you if you don't set `authTitle` as explained in the README. \ No newline at end of file diff --git a/examples/clientReadmeExample.js b/examples/clientReadmeExample.js index 32cffaf..09a29b5 100644 --- a/examples/clientReadmeExample.js +++ b/examples/clientReadmeExample.js @@ -4,7 +4,9 @@ const client = bedrock.createClient({ host: 'localhost', // optional port: 19132, // optional, default 19132 username: 'Notch', // the username you want to join as, optional if online mode - offline: false // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. + offline: false, // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. + // Optional for some servers which verify the title ID: + // authTitle: bedrock.title.MinecraftNintendoSwitch }) client.on('text', (packet) => { // Listen for chat messages and echo them back. diff --git a/index.d.ts b/index.d.ts index 26b764a..b08e207 100644 --- a/index.d.ts +++ b/index.d.ts @@ -3,6 +3,8 @@ import EventEmitter from "events" declare module "bedrock-protocol" { type Version = '1.16.220' | '1.16.210' | '1.16.201' + enum title { MinecraftNintendoSwitch, MinecraftJava } + export interface Options { // The string version to start the client or server as version: number, diff --git a/index.js b/index.js index a4e2f49..e3241a5 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ const { Server } = require('./src/server') const { Relay } = require('./src/relay') const { createClient, ping } = require('./src/createClient') const { createServer } = require('./src/createServer') +const Title = require('./src/client/titles') module.exports = { Client, @@ -16,5 +17,6 @@ module.exports = { Relay, createClient, ping, - createServer + createServer, + title: Title } diff --git a/package.json b/package.json index 1022e71..ba7d7d6 100644 --- a/package.json +++ b/package.json @@ -21,15 +21,17 @@ ], "license": "MIT", "dependencies": { - "@azure/msal-node": "^1.0.0-beta.6", + "@azure/msal-node": "^1.1.0", "@xboxreplay/xboxlive-auth": "^3.3.3", "debug": "^4.3.1", + "jose-node-cjs-runtime": "^3.12.1", "jsonwebtoken": "^8.5.1", "jsp-raknet": "^2.1.0", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", "protodef": "extremeheat/node-protodef#patch-1", + "smart-buffer": "^4.1.0", "uuid-1345": "^1.0.2" }, "optionalDependencies": { diff --git a/src/client/auth.js b/src/client/auth.js index 2d8d30e..d7ffc8d 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -66,7 +66,7 @@ async function authenticatePassword (client, options) { */ async function authenticateDeviceCode (client, options) { try { - const flow = new MsAuthFlow(options.username, options.profilesFolder, options.onMsaCode) + const flow = new MsAuthFlow(options.username, options.profilesFolder, options, options.onMsaCode) const chain = await flow.getMinecraftToken(client.clientX509) // console.log('Chain', chain) diff --git a/src/client/authConstants.js b/src/client/authConstants.js index 65c2575..1f5066f 100644 --- a/src/client/authConstants.js +++ b/src/client/authConstants.js @@ -1,4 +1,10 @@ module.exports = { XSTSRelyingParty: 'https://multiplayer.minecraft.net/', - MinecraftAuth: 'https://multiplayer.minecraft.net/authentication' + MinecraftAuth: 'https://multiplayer.minecraft.net/authentication', + XboxDeviceAuth: 'https://device.auth.xboxlive.com/device/authenticate', + XboxTitleAuth: 'https://title.auth.xboxlive.com/title/authenticate', + XstsAuthorize: 'https://xsts.auth.xboxlive.com/xsts/authorize', + + LiveDeviceCodeRequest: 'https://login.live.com/oauth20_connect.srf', + LiveTokenRequest: 'https://login.live.com/oauth20_token.srf' } diff --git a/src/client/authFlow.js b/src/client/authFlow.js index 7e496ba..1f67aa2 100644 --- a/src/client/authFlow.js +++ b/src/client/authFlow.js @@ -4,7 +4,7 @@ const fs = require('fs') const debug = require('debug')('minecraft-protocol') const mcDefaultFolderPath = require('minecraft-folder-path') const authConstants = require('./authConstants') -const { MsaTokenManager, XboxTokenManager, MinecraftTokenManager } = require('./tokens') +const { LiveTokenManager, MsaTokenManager, XboxTokenManager, MinecraftTokenManager } = require('./tokens') // Initialize msal // Docs: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/request.md#public-apis-1 @@ -30,7 +30,8 @@ async function retry (methodFn, beforeRetry, times) { } class MsAuthFlow { - constructor (username, cacheDir, codeCallback) { + constructor (username, cacheDir, options = {}, codeCallback) { + this.options = options this.initTokenCaches(username, cacheDir) this.codeCallback = codeCallback } @@ -50,14 +51,22 @@ class MsAuthFlow { } const cachePaths = { + live: path.join(cachePath, `./${hash}_live-cache.json`), msa: path.join(cachePath, `./${hash}_msa-cache.json`), xbl: path.join(cachePath, `./${hash}_xbl-cache.json`), bed: path.join(cachePath, `./${hash}_bed-cache.json`) } - const scopes = ['XboxLive.signin', 'offline_access'] - this.msa = new MsaTokenManager(msalConfig, scopes, cachePaths.msa) - this.xbl = new XboxTokenManager(authConstants.XSTSRelyingParty, cachePaths.xbl) + if (this.options.authTitle) { // Login with login.live.com + const scopes = ['service::user.auth.xboxlive.com::MBI_SSL'] + this.msa = new LiveTokenManager(this.options.authTitle, scopes, cachePaths.live) + } else { // Login with microsoftonline.com + const scopes = ['XboxLive.signin', 'offline_access'] + this.msa = new MsaTokenManager(msalConfig, scopes, cachePaths.msa) + } + + const keyPair = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }) + this.xbl = new XboxTokenManager(authConstants.XSTSRelyingParty, keyPair, cachePaths.xbl) this.mca = new MinecraftTokenManager(cachePaths.bed) } @@ -87,7 +96,11 @@ class MsAuthFlow { if (this.codeCallback) this.codeCallback(response) }) - console.info(`[msa] Signed in as ${ret.account.username}`) + if (ret.account) { + console.info(`[msa] Signed in as ${ret.account.username}`) + } else { // We don't get extra account data here per scope + console.info('[msa] Signed in with Microsoft') + } debug('[msa] got auth result', ret) return ret.accessToken @@ -96,15 +109,23 @@ class MsAuthFlow { async getXboxToken () { if (await this.xbl.verifyTokens()) { - debug('[xbl] Using existing tokens') + debug('[xbl] Using existing XSTS token') return this.xbl.getCachedXstsToken().data } else { debug('[xbl] Need to obtain tokens') return await retry(async () => { const msaToken = await this.getMsaToken() - const ut = await this.xbl.getUserToken(msaToken) - const xsts = await this.xbl.getXSTSToken(ut) - return xsts + const ut = await this.xbl.getUserToken(msaToken, !this.options.authTitle) + + if (this.options.authTitle) { + const deviceToken = await this.xbl.getDeviceToken({ DeviceType: 'Nintendo', Version: '0.0.0' }) + const titleToken = await this.xbl.getTitleToken(msaToken, deviceToken) + const xsts = await this.xbl.getXSTSToken(ut, deviceToken, titleToken) + return xsts + } else { + const xsts = await this.xbl.getXSTSToken(ut) + return xsts + } }, () => { this.msa.forceRefresh = true }, 2) } } @@ -122,6 +143,12 @@ class MsAuthFlow { const xsts = await this.getXboxToken() debug('[xbl] xsts data', xsts) const token = await this.mca.getAccessToken(publicKey, xsts) + // If we want to auth with a title ID, make sure there's a TitleID in the response + const body = JSON.parse(Buffer.from(token.chain[1].split('.')[1], 'base64').toString()) + console.log(this.options.authTitle) + if (!body.extraData.titleId && this.options.authTitle) { + throw Error('missing titleId in response') + } return token.chain }, () => { this.xbl.forceRefresh = true }, 2) } diff --git a/src/client/titles.js b/src/client/titles.js new file mode 100644 index 0000000..66ca06c --- /dev/null +++ b/src/client/titles.js @@ -0,0 +1,4 @@ +module.exports = { + MinecraftNintendoSwitch: '00000000441cc96b', + MinecraftJava: '00000000402b5328' +} diff --git a/src/client/tokens.js b/src/client/tokens.js index 5dda941..f4436d6 100644 --- a/src/client/tokens.js +++ b/src/client/tokens.js @@ -5,6 +5,166 @@ const fs = require('fs') const path = require('path') const fetch = require('node-fetch') const authConstants = require('./authConstants') +const crypto = require('crypto') +const { nextUUID } = require('../datatypes/util') +const { SmartBuffer } = require('smart-buffer') +const jose = require('jose-node-cjs-runtime/jwk/from_key_like') + +class LiveTokenManager { + constructor (clientId, scopes, cacheLocation) { + this.clientId = clientId + this.scopes = scopes + this.cacheLocation = cacheLocation + this.reloadCache() + } + + reloadCache () { + try { + this.cache = require(this.cacheLocation) + } catch (e) { + this.cache = {} + fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) + } + } + + async verifyTokens () { + if (this.forceRefresh) try { await this.refreshTokens() } catch { } + const at = this.getAccessToken() + const rt = this.getRefreshToken() + if (!at || !rt) { + return false + } + debug('[live] have at, rt', at, rt) + if (at.valid && rt) { + return true + } else { + try { + await this.refreshTokens() + return true + } catch (e) { + console.warn('Error refreshing token', e) // TODO: looks like an error happens here + return false + } + } + } + + async refreshTokens () { + const rtoken = this.getRefreshToken() + if (!rtoken) { + throw new Error('Cannot refresh without refresh token') + } + + const codeRequest = { + method: 'post', + body: new URLSearchParams({ scope: this.scopes, client_id: this.clientId, grant_type: 'refresh_token', refresh_token: rtoken.token }).toString(), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + credentials: 'include' // This cookie handler does not work on node-fetch ... + } + + const token = await fetch(authConstants.LiveTokenRequest, codeRequest).then(checkStatus) + this.updateCachce(token) + return token + } + + getAccessToken () { + const token = this.cache.token + if (!token) return + const until = new Date(token.obtainedOn + token.expires_in) - Date.now() + const valid = until > 1000 + return { valid, until: until, token: token.access_token } + } + + getRefreshToken () { + const token = this.cache.token + if (!token) return + const until = new Date(token.obtainedOn + token.expires_in) - Date.now() + const valid = until > 1000 + return { valid, until: until, token: token.refresh_token } + } + + updateCachce (data) { + data.obtainedOn = Date.now() + this.cache.token = data + fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) + } + + async authDeviceCode (deviceCodeCallback) { + const acquireTime = Date.now() + const codeRequest = { + method: 'post', + body: new URLSearchParams({ scope: this.scopes, client_id: this.clientId, response_type: 'device_code' }).toString(), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + credentials: 'include' // This cookie handler does not work on node-fetch ... + } + + debug('Requesting live device token', codeRequest) + + const cookies = [] + + const res = await fetch(authConstants.LiveDeviceCodeRequest, codeRequest) + .then(res => { + if (res.status !== 200) { + res.text().then(console.warn) + throw Error('Failed to request live.com device code') + } + for (const cookie of Object.values(res.headers.raw()['set-cookie'])) { + const [keyval] = cookie.split(';') + cookies.push(keyval) + } + return res + }) + .then(checkStatus).then(resp => { + resp.message = `To sign in, use a web browser to open the page ${resp.verification_uri} and enter the code ${resp.user_code} to authenticate.` + deviceCodeCallback(resp) + return resp + }) + const expireTime = acquireTime + (res.expires_in * 1000) - 100 /* for safety */ + + this.polling = true + while (this.polling && expireTime > Date.now()) { + await new Promise(resolve => setTimeout(resolve, res.interval * 1000)) + try { + const verifi = { + method: 'post', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Cookie: cookies.join('; ') + }, + body: new URLSearchParams({ + client_id: this.clientId, + device_code: res.device_code, + grant_type: 'urn:ietf:params:oauth:grant-type:device_code' + }).toString() + } + + const token = await fetch(authConstants.LiveTokenRequest + '?client_id=' + this.clientId, verifi) + .then(res => res.json()).then(res => { + if (res.error) { + if (res.error === 'authorization_pending') { + debug('[live] Still waiting:', res.error_description) + } else { + throw Error(`Failed to acquire authorization code from device token (${res.error}) - ${res.error_description}`) + } + } else { + return res + } + }) + if (!token) continue + this.updateCachce(token) + this.polling = false + return { accessToken: token.access_token } + } catch (e) { + console.debug(e) + } + } + this.polling = false + throw Error('Authenitcation failed, timed out') + } +} // Manages Microsoft account tokens class MsaTokenManager { @@ -103,7 +263,7 @@ class MsaTokenManager { } async verifyTokens () { - if (this.forceRefresh) try { await this.refreshTokens() } catch {} + if (this.forceRefresh) try { await this.refreshTokens() } catch { } const at = this.getAccessToken() const rt = this.getRefreshToken() if (!at || !rt) { @@ -149,14 +309,20 @@ class MsaTokenManager { // Manages Xbox Live tokens for xboxlive.com class XboxTokenManager { - constructor (relyingParty, cacheLocation) { + constructor (relyingParty, ecKey, cacheLocation) { this.relyingParty = relyingParty + this.key = ecKey + jose.fromKeyLike(ecKey.publicKey).then(jwk => { + this.jwk = { ...jwk, alg: 'ES256', use: 'sig' } + }) this.cacheLocation = cacheLocation || path.join(__dirname, './xbl-cache.json') try { this.cache = require(this.cacheLocation) } catch (e) { this.cache = {} } + + this.headers = { 'Cache-Control': 'no-store, must-revalidate, no-cache', 'x-xbl-contract-version': 1 } } getCachedUserToken () { @@ -209,24 +375,145 @@ class XboxTokenManager { return false } - async getUserToken (msaAccessToken) { + async getUserToken (msaAccessToken, azure) { debug('[xbl] obtaining xbox token with ms token', msaAccessToken) - if (!msaAccessToken.startsWith('d=')) { msaAccessToken = 'd=' + msaAccessToken } + msaAccessToken = (azure ? 'd=' : 't=') + msaAccessToken const xblUserToken = await XboxLiveAuth.exchangeRpsTicketForUserToken(msaAccessToken) this.setCachedUserToken(xblUserToken) debug('[xbl] user token:', xblUserToken) return xblUserToken } - async getXSTSToken (xblUserToken) { - debug('[xbl] obtaining xsts token with xbox user token', xblUserToken.Token) - const xsts = await XboxLiveAuth.exchangeUserTokenForXSTSIdentity( - xblUserToken.Token, { XSTSRelyingParty: this.relyingParty, raw: false } - ) + // Make signature for the data being sent to server with our private key; server is sent our public key in plaintext + sign (url, authorizationToken, payload) { + // Their backend servers use Windows epoch timestamps, account for that. The server is very picky, + // bad percision or wrong epoch may fail the request. + const windowsTimestamp = (BigInt((Date.now() / 1000) | 0) + 11644473600n) * 10000000n + // Only the /uri?and-query-string + const pathAndQuery = new URL(url).pathname + + // Allocate the buffer for signature, TS, path, tokens and payload and NUL termination + const allocSize = /* sig */ 5 + /* ts */ 9 + /* POST */ 5 + pathAndQuery.length + 1 + authorizationToken.length + 1 + payload.length + 1 + const buf = SmartBuffer.fromSize(allocSize) + buf.writeInt32BE(1) // Policy Version + buf.writeUInt8(0) + buf.writeBigUInt64BE(windowsTimestamp) + buf.writeUInt8(0) // null term + buf.writeStringNT('POST') + buf.writeStringNT(pathAndQuery) + buf.writeStringNT(authorizationToken) + buf.writeStringNT(payload) + + // Get the signature from the payload + const signature = crypto.sign('SHA256', buf.toBuffer(), { key: this.key.privateKey, dsaEncoding: 'ieee-p1363' }) + + const header = SmartBuffer.fromSize(signature.length + 12) + header.writeInt32BE(1) // Policy Version + header.writeBigUInt64BE(windowsTimestamp) + header.writeBuffer(signature) // Add signature at end of header + + return header.toBuffer() + } + + // If we don't need Xbox Title Authentication, we can have xboxreplay lib + // handle the auth, otherwise we need to build the request ourselves with + // the extra token data. + async getXSTSToken (xblUserToken, deviceToken, titleToken) { + if (deviceToken && titleToken) return this.getXSTSTokenWithTitle(xblUserToken, deviceToken, titleToken) + + debug('[xbl] obtaining xsts token with xbox user token (with XboxReplay)', xblUserToken.Token) + const xsts = await XboxLiveAuth.exchangeUserTokenForXSTSIdentity(xblUserToken.Token, { XSTSRelyingParty: this.relyingParty, raw: false }) this.setCachedXstsToken(xsts) debug('[xbl] xsts', xsts) return xsts } + + async getXSTSTokenWithTitle (xblUserToken, deviceToken, titleToken, optionalDisplayClaims) { + const userToken = xblUserToken.Token + debug('[xbl] obtaining xsts token with xbox user token', userToken) + + const payload = { + RelyingParty: this.relyingParty, + TokenType: 'JWT', + Properties: { + UserTokens: [userToken], + DeviceToken: deviceToken, + TitleToken: titleToken, + OptionalDisplayClaims: optionalDisplayClaims, + ProofKey: this.jwk, + SandboxId: 'RETAIL' + } + } + + const body = JSON.stringify(payload) + const signature = this.sign(authConstants.XstsAuthorize, '', body).toString('base64') + + const headers = { ...this.headers, Signature: signature } + + const ret = await fetch(authConstants.XstsAuthorize, { method: 'post', headers, body }).then(checkStatus) + const xsts = { + userXUID: ret.DisplayClaims.xui[0].xid || null, + userHash: ret.DisplayClaims.xui[0].uhs, + XSTSToken: ret.Token, + expiresOn: ret.NotAfter + } + + this.setCachedXstsToken(xsts) + debug('[xbl] xsts', xsts) + return xsts + } + + /** + * Requests an Xbox Live-related device token that uniquely links the XToken (aka xsts token) + * @param {{ DeviceType, Version }} asDevice The hardware type and version to auth as, for example Android or Nintendo + */ + async getDeviceToken (asDevice) { + const payload = { + Properties: { + AuthMethod: 'ProofOfPossession', + Id: `{${nextUUID()}}`, + DeviceType: asDevice.DeviceType || 'Android', + SerialNumber: `{${nextUUID()}}`, + Version: asDevice.Version || '10', + ProofKey: this.jwk + }, + RelyingParty: 'http://auth.xboxlive.com', + TokenType: 'JWT' + } + + const body = JSON.stringify(payload) + + const signature = this.sign(authConstants.XboxDeviceAuth, '', body).toString('base64') + + const headers = { ...this.headers, Signature: signature } + + const ret = await fetch(authConstants.XboxDeviceAuth, { method: 'post', headers, body }).then(checkStatus) + debug('Xbox Device Token', ret) + return ret.Token + } + + // This *only* works with live.com auth + async getTitleToken (msaAccessToken, deviceToken) { + const payload = { + Properties: { + AuthMethod: 'RPS', + DeviceToken: deviceToken, + RpsTicket: 't=' + msaAccessToken, + SiteName: 'user.auth.xboxlive.com', + ProofKey: this.jwk + }, + RelyingParty: 'http://auth.xboxlive.com', + TokenType: 'JWT' + } + const body = JSON.stringify(payload) + const signature = this.sign(authConstants.XboxTitleAuth, '', body).toString('base64') + + const headers = { ...this.headers, Signature: signature } + + const ret = await fetch(authConstants.XboxTitleAuth, { method: 'post', headers, body }).then(checkStatus) + debug('Xbox Title Token', ret) + return ret.Token + } } // Manages Minecraft tokens for sessionserver.mojang.com @@ -276,16 +563,14 @@ class MinecraftTokenManager { async getAccessToken (clientPublicKey, xsts) { debug('[mc] authing to minecraft', clientPublicKey, xsts) - const getFetchOptions = { - headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'node-minecraft-protocol', - Authorization: `XBL3.0 x=${xsts.userHash};${xsts.XSTSToken}` - } + const headers = { + 'Content-Type': 'application/json', + 'User-Agent': 'node-minecraft-protocol', + Authorization: `XBL3.0 x=${xsts.userHash};${xsts.XSTSToken}` } const MineServicesResponse = await fetch(authConstants.MinecraftAuth, { method: 'post', - ...getFetchOptions, + headers, body: JSON.stringify({ identityPublicKey: clientPublicKey }) }).then(checkStatus) @@ -299,8 +584,9 @@ function checkStatus (res) { if (res.ok) { // res.status >= 200 && res.status < 300 return res.json() } else { + debug('Request fail', res) throw Error(res.statusText) } } -module.exports = { MsaTokenManager, XboxTokenManager, MinecraftTokenManager } +module.exports = { LiveTokenManager, MsaTokenManager, XboxTokenManager, MinecraftTokenManager } From f0fbf4f85979ac47a723ceda3df3afb40ca543d9 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 24 May 2021 10:17:09 -0400 Subject: [PATCH 183/458] Send skin data, protocol updates (#88) * Add skin data * Serialization updates * Dynamic shield item id * NBT reading/writing on void type uses 0 length, fix some third party servers * Fix proxy empty chunk issue * Fix scoreboards compiler needs ../ * fix indentation * Fix set_score packet * Fix readme title auth doc * Implement new compiler vars --- README.md | 4 +- data/1.16.201/biome_definitions.nbt | Bin 37626 -> 0 bytes data/1.16.201/creativeitems.json | 4898 ------------------------- data/1.16.201/skin_geom.txt | 1 - data/1.16.201/steve.json | 120 + data/1.16.201/steveGeometry.json | 5147 +++++++++++++++++++++++++++ data/1.16.201/steveSkin.bin | Bin 0 -> 262144 bytes data/1.16.220/protocol.json | 292 +- data/latest/proto.yml | 43 +- data/latest/types.yaml | 36 +- package.json | 6 +- src/client.js | 28 +- src/connection.js | 24 +- src/createClient.js | 2 +- src/datatypes/minecraft.js | 6 +- src/handshake/login.js | 40 +- src/relay.js | 49 +- src/transforms/serializer.js | 19 +- tools/compileProtocol.js | 6 +- 19 files changed, 5557 insertions(+), 5164 deletions(-) delete mode 100644 data/1.16.201/biome_definitions.nbt delete mode 100644 data/1.16.201/creativeitems.json delete mode 100644 data/1.16.201/skin_geom.txt create mode 100644 data/1.16.201/steve.json create mode 100644 data/1.16.201/steveGeometry.json create mode 100644 data/1.16.201/steveSkin.bin diff --git a/README.md b/README.md index 1c87815..124f1b2 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ const client = bedrock.createClient({ port: 19132, // optional, default 19132 username: 'Notch', // the username you want to join as, optional if online mode offline: true // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. + // Optional for some servers which verify the title ID: + // authTitle: bedrock.title.MinecraftNintendoSwitch }) client.on('text', (packet) => { // Listen for chat messages and echo them back. @@ -66,8 +68,6 @@ const server = new bedrock.createServer({ host: '0.0.0.0', // optional. host to bind as. port: 19132, // optional version: '1.16.220', // optional. The server version, latest if not specified. - // Optional for some servers which verify the title ID: - // authTitle: bedrock.title.MinecraftNintendoSwitch }) server.on('connect', client => { diff --git a/data/1.16.201/biome_definitions.nbt b/data/1.16.201/biome_definitions.nbt deleted file mode 100644 index 68705c5d4f97c43f712894fcf5f25cb07bcf5892..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37626 zcmeHQ+m74D8CKVlEOF24-5!z_XoLX0F#^Zii`GEaet-gffFK|!X|!TOkqeUY)-eM3 z0eaE9*16~t^sW!!K7joceUbj0gE&Xdkdii9m(EQrYp9v;KOg3&*YOU=!D5^w{i zzvL*M!n4uz8u@t|#MvxKVQcUmZ*MT1B=IyX{_?Nx>k*v8PiCWMU%wtD_{WoU^z6&W zqii|;7ESWevnP*7Im+OFM)M%^$6>O7X9m}!$D@}4AOoKh#6~|nZvKd5f`S-7A&6hC zyB|1gv0-sPaEuy9nk3P5tq07*D9YA)!UA0f>pftZ12?XBjB%Jw=A$3Jf&aV*7r=i0 zO^{__eC@|5yq=GfG}{{Emq`vozCzaqoZ;rS@lQ| zL?3^bTP=&tunXLn4ZMC3gZM>#vbs-x`r#spvmB+vmAv$$wZssk_^ z26fOeNc4dy(LIde8gdN=J`1AUpQ0!aG8c(1%zZ-xk3EGd0}o$#AsYA>9q+T!z{e<` zqg1i(z2iJcuTk#9Ny2Vq_p_VeHukTi)%j50yzY7gEUqhK<3p~;8$ z@2?utq*yBRny|GG@BgGYUGf5IZotA7J67#W_cllu)~9+0*s}V>RdG4@k8gj~)Y&YS z%Eu6Ph`-Rx*}S0cCn}EOQx7=v_8#zNwo{sKi|s$-VUbP$@M3{o8k6I2E-WVBot8gs zVr!;n_QweM^I#l;+XS8nI6i$s9+k*;^fU*#&s44k{u2Rstfzfv_>ZWXH^NU8e-k29 z?8}81g*s@gYCw}zsejP3uBwIsB=DpN%0r6w`O3}Z42Qt1y5IG*f^!cMGO`e3o;7ju zim=dkHdQ~qecRMj6-z7m2YB-<(R~0{#VtQ@p3NaZHYri=jCR#Ytzfsng<)(6wX_>1 zKZb*U7j^^Jp{YO?ODh4zU)Z7z?3ZW`&(jdnH`Nrtpzv!Ps3xs38N7i&uO41ypqdsH zLbW^yuLBpVZPR0e{k>}_22P&KfTsX4Y^!7k%cqg7#R=987?iqx%Ne&+F`L5;iYxPU zF#XNW4WX>y!0BLCPJEApKLen3A(J`5wjouF$e`XMRDYH>YCbOwFpLW_lL1=o4DF zQdEWN5vFLg{0p=O(&kP+X_1ZPU3G#^uOC1yS8d+%YUGzIN=yv!e^xdQg zx?{-EZ=z)eDISD4wc?zkbJA~njH&y!mWl(yU3C)^M|7E*l=w|c;wS@_(~(#fFzRXd zsfaVv&1C_kRErus3iR7W9bq{0fT=Ys5=~AnvEV&CJ3DoCro+kthk|x-!C}kghbtw% z+M=EKw`eD{O@f!&4!;nTaM@Prlb*#@@8Xj$o<1Rep8oLreJXbO{Jz06zx?7! z(}uY-fyi>-oNIx{U_82}n!ND2P^Tc4%#iVRuy?kK{e^hmwd_pGBDl4(GS=A7@+3y2 zg2|i*SY_1Sq@_|+Jxre&>=)GeRL!8_>z&kKZoy}Dv7jEttCCFNDeHkAERtmmneey{ z;(E#2MbHh*$NG8om@s2n2NI*c+C@}c6I(=Ono7yP74>WBud3}imaw=PSBu1xDvpi# z+Ipg0B&LDIne11h)P&OyXHjws4F>MzupMc2^7sxO@f6JLSn$yHH&MoOVU4>6!d1@o zZI+vM=?)0T)Xfu!l(IV(Ot|Hr49125K29`%(U#$a>u#i^ zdcapFOAfVIJ;N%q!@O?Yjr|}lKe@0nBy_jg5~o%MH{l}J>M`uoVkV~%2s*qd;Ka7v zz1N+iC~^exZZqoJZU(_{)NKY?^#mNz?vF!y2jv!ScA)HtbaxatOVb64Ps>IS+Wx^` z1fl=R-2tIjL*%9rd-dV4Nba)`$o1OJM=lcsDiaR?8=D)g6%DVfm^cc^E+T43bcvTw zRxO;?Dv8KxoRP5HJ2@@EgzMblcYMXiQZN?uJ@<>%DTZ45ljjwV?3_BaDpK`;ZcOv0 zIn%tcc5Cl|Y4WHTaZATBZqX$gm7;w^Fs)N@nr+>tw2b@fXy>W<5 zI5?ma4lw4N{ogl(r!FJIz+f9eGBTkx*Tp@Xy zwS>HAyk6@8t)4N@G_VyuA90gW)Lgtx3v`QOkx>=cwSex|TW!!zI1zgv>iG<w|07j zC(dkoFriJBB`IFhL_eapCHTsui*!Touz6n9J_Vz3UbXtloaV4xzN9+etwX9@Y@!+~ z9NO-)ss}z|*X-JhkK&LE37C=wmO8p|or!jXP26-W(wH!+)_F|H_NG1IaXxZ+dW-Gy ze>U8zs&^dTQCcQAn zDNb7|*(>(zkJDEZRIakvW6Trfw@vKW$KO+hUtl`mnitAdFm6*WvVPaBXHb1CW*3gl zy!=x4*^hsKX#zKra}+Fh5dd$C&c}a6G1T7Gt0zzt$hCx0Bh~d1+_YBPIOddPZq3_# zVw2PAD)^r5D!8-_n|3+pIaxJib$po-O{|ZY196UCFIcPS$hB?DtnX7bJX+|jB$_bpXdfu*grliqxA%i7t3s(CdtAN zvnYtCZXj&0r@QDtPy$J}96|LgFi6=52lercgp&I#oNHTdik`bCizE?#xMX0#FVP-c z|EvGEG%|tQuL2p<*$y=+5V=9S)zVv2_TO+*vvwk(F7e%4|n`dq4h3(_l0>qt6uefNBEq}2ne6sODAk7rf{vgq^y24CU|j{%=k&RjOkng zGODk9q>1`0AID#iW(-m4QbuUr;1$IK#g67(7mbd0z%>Slipw$$ z^9uC6gN{WTefjIB#;MbRVe3*Q)qs;!Owl4#a*?K-qWdkcw<}k(RsMGLl`1Dhk>lA# zv&$i;y^gJJ?+|>=8BB}c-Kiw&>18p#UFl_OMphX_xvrJXyW-_%d7E_7Qps0#x+mAcd!orhWQGKk}!ybcQ$VpTBR^oEm@ zx$-)!S)F5wNHMp!sFIZ`$HxAvmCm>42GnAzzQc+xyz`(1N&ZzA&W5miYn^%@-v3ph zq=B=U8^w;#Sh|#QEeyI}@K!KTvN^)A#l`}-DK7Z~u4!*ZM@%P51SRWZ;tLa#6!;Pijh+aJR{4j98w zyaT={()0$?iGCwBJg++^wB@<2X-p%C1%}!OX*aVuoh6?mOhKxf?fz?zIb&vIw;MV2v zcb#^SIhYP6XY#3wvQ<;z9BmJ?+h75L?V4ELrm55<12)?L1H9^LbzF*LeDGjNtDLT2 zRt=P`JEJ=oPLdd27#=3^KYK#YFxRyMs?$$qqi0{g9+fS1^-8hiJp$|X@8DNI%Qx2R z^%3DrNzuUbSU79bQ_=otcv#aXXzt+GJJG6$Cv2kLGd7G$ISgqt^!}#lFm)xa?r`k> z_q~m<0J+A$nS-uD!eSo4TANt$K!f+5@H0iqC=ROnm5HX(JaB6a7RnsI^|1C6{1ULw zsvE6pNf!eRT77E{v~HV*+_@BY2I_W%C-@#e=*|FgF} z5s$mN*u?Z*+j)QfdGm1UdOX|Vt0upiTh=@bxNuLizI-ms*XiaZV11wFFQ3zV^xifB z?)^J^&iyU-3 zmU-&hnLmDF&>v&)Ge_*yuXca;#^(}@rZP5u9s;TDw!W)&qO()}j758~8B2U(qm?`l zpx1VMVi@0N`_`{>C1xnUsbo*h-KUQ^Gr*Pr(NqG z{nx%@<8w}ATr^eNQ}dhp&Q4wb*nZ*5USV`>JmW6SC+qsPN&-BeWAn4Lzkm4l(Um^@ zv8{ir{nRX1>XcedZPBKmaoCJ$YnqtOSJyr(zlrZ`UBBIb{rLvt=H!zcl2grrys*_r zdmpptUa{xL&rt6GB`)PAVpn1-M*rI=OU|n*gpFQBm zPJL^b7Y@ve9bBKiJ~N+l^UFS_GBW-)38Z#w{idCIKwGiY6*|Drm`C@2^dC*5>z$7G z_jvRli~bwU*E585$&+=l^pod7eiPps)^F#}I=Sd)9R1j9^I_dSKFJY(wG$B;exn4U zovNRYICit7%?W{ij{W z_q552JZjx05Awp++|r)<&a~^-`I8IlVyl0<{;B=uoa6auA|LYXdXYFnOY;%4Ru6) zVdKXa`^kqtZ9e+o`@Q|*#h;t@`t0Lh-v2zH(?iA+ldl*OE;>Wgp_UB#Bfn4>x<6Ok{>A#N8S-|VGFK|94->Hm@zfA(vY_;en zHW#}8^~)Dq9klgb^`CaDeO_<%-PLX^+Hc1*h8Xlue#wQr$O9j?=6{LWW?ndCPS%d4 zA6tFNrSi$X>)vQ@_l>r%d_E@M+pJ!*mca89K>yf!zNC%rZ}ogs|Ic4Tt{?#kNI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}ocL0y zz*PNCjh}Dlt}FowOx5qy_{F{h`Ha7J@3x=WSO2E^V7?_TpEX46V4MRaFav?9`kfj- z!!r)N6zNc7*?QTi`&>VM|< z(B%&ZpvzPG&6rbud>Pm3yTv@n8>i?v8je=;8ejbzi1F3_j6>s`8~CeF{m)SOE*Sz<+i4H! zKi{+0Yij&r--W92s#Wge$8_Arab~pVMx9grFSZQsJu&plJv{nH-)YCsm{@$+>Px#X zK65iaaoEN3ZFS6Z{Lp>;+_=SpFtK|k5Y1K%58eO!{Ae5f*D-bOKL1kL^7n$U`8zxO zZ7}+<_+sh9^7n@Nd^K*V9L(#!2}F}sqgA_U)8n7rj=k;=`ix_H2m1jbpy} zYTT{!GXEPV!0)Ma77fP^?yAJyyZ+HD8phI({^^g6{_#ii_|*SkWjWxQ1h|iPdQOdU z1`MWv{>MHy3{E`nfatSc=r~$N!@qv{Vmk(XqkrNuE`9jv$I>4=?`~av^#ss=XGiJ3 z#BpXk>A7L`zy%_q7BhFdG4W1|6H9_tk%==I7gtsXqF~#?7`-7nXno4hXb5=HH^C zb+pZxKK*k>;7dGxeQ^f~*dYN4%toMUHEr}C+v-1k_|Z1;^vBXie9i`9XWOU?OF#k# z1gch}*LojEzgT>+#9`5Yd>PLbe~mjxzzzvWU^W8i7mHS-XEc0D|BPw%&wT2Cwzt-W zB``<;{i0X&-`>YF4vn{GLws!<^R;n<2{}Ll61WoMm{nH;C{o~J^_|*T^ z-bxpez-R*KAB&EoWi;&Xw~WSWfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drdo|iy=AFq5S zPkxp+>T@}EpZ}A%_S(*y-~Tyv4ehSUujZEZhQjqrKmsQSp#7aaNB_}e-?i62zZ=}z zoC`x=O@8Ws2$+5ej37|&ubtLL>uVQt75#U)jy|78pm3-JR!5-fziXeP|Mt0`*Zceb z1)u-b|LQ8#4PS~tpAMt{d=^hEpXE`<@i{-(>U;HS^YGhm+c^IJ9{)dRJ6GR)>C0MN z%**RKf7*;E$JS3gb}Xx`%l8;vd-VCz#d6-Y_BqbK(dYA69*)0X0%(Wt!_gPoicKH> zSagN0{z{mE zoBW5qn*7xN5HS5m38da~QHQO5qO()}=#1Fd8lTwcGtUF)wH=?Bs@1mLw|<=~8O|^UTi~kT$Wg=)d+I8=rF` zn9$&->3}(F6|I{q?T*s!JtMic`7G0A^^5V)E`msm0{=U1_Z}Q~ zJHDy;_3ha{33LR|6xxn$^;5^-M}x8Z`b?eXqRwNvS7FoF)^i=7dgt{{7k%s39OFm- zY1iDIqW>Dp`BCR+=g*w+Gv<+=a~3rDALzQC7u^5*Vs^~fKY6k)mVWX)$j?fbz!3t} z7PS+Lw%Yol&ZsZ!Cm;T_`RIf1H`p&;{JCkb&p!U;-}_wZywiWi6O*y=Z^v-&>&E4E zd^NXLpUI*6(*K@L{4-|gJ!OB`#BgOU=8er5eAt8MnLM{} z<-FtBhi9Ai`G>JbEP0U!`(u6b!qSf&+P{7YteF71LTBg(iyxbQG#I?V{&=nd&SLld-Z2b6Q>+?^ZYwEKL z?d@|7+V1qfr0;)*_~@6wJrh9x*sATc(fz%C|8vjpt$UMz1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-I3)1u ztA952dinC@re22;k9%rt+BG)q$D@5E0SPRLz*PNCjb9QAbCJN>2u#)Q)cCo1PtAX7 z{M`F@{dE(VTEA1{=cYe3|EckF@89*;MS#!!<1_vE%o}X|e4MoTT+iySW9Y|LU)uD? zZa-INVYsL2cWV5?aG1`W6No0OMyo#4#y5064Eb57oquU~r|NfV{L*-s&wUd>m#6g0 z84%m*xBAZU&rLTu*F6mF@7|w(=6*k1|GEU8QvYN0F{Gc?f8E_4uJ)Au=WIN6K0d|I zI!oLCArX7lM4)Or?Y2ItTk1dezj{rLpPO~NzoGs2`C)U6-zopx`*;0y6F|SzXzCk% zr`_rUAC`E=^~Gmy<|ht2H~qf+tH#;avHYjT&%J-wUpIlazH9AQ{WIUCf0>`T({AUV zd;hM#ZUX%Oe00#(C;g0j^XAQ_Ui33=Z2a8x$s2nt|L5}0y?@tVHv#mEt=dkTe(a_F zbJJ&EL;7aivHhPLKllD!f87MAYwWT5elGvq^w}47ZTp{_zw0lAK>o(Oa@-zd!EJn741=Uo|G}jE_IDt*^#C?{22g zp8TWb&W_T5iBtd6-v(#65`k#-_3M8xbevj_W~(n_s*Z_?%{Y9V8~Cd)W0v-n{OXmx z=VBk##~x#Af7{U1Sl*L;8ukHMM3M0qdErF`lw9$WT ztN--jN87~HA4?zc(LJ$C1KH+U_d)*bl|5uX^bud<=p%l~`(N7oVLsO-P-`{ynp&k^ zsb4Iy&SbSJC-fE-jhB)Snuf|<>cf+f( zH}YNE{)Y)U;+_fg)jxVg6IlAuKmD=M4gSoD?-upXKG*}6{(IX0J=eB-8zzAMvFJE8 zPTl|d<%{jJKwJOBWL$js>BrI^JDkyVN01|SZTr72ZC6_w0qP#Rw)$t^*tP9{Y4vD6 z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv zAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnw zfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz z0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8< z2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drd zBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU z0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb z1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ! z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv TAOQ(TKmrnwfCMCPIRgI&V?knt literal 0 HcmV?d00001 diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index 115676d..ed967de 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -422,7 +422,7 @@ { "compareTo": "network_id", "fields": { - "355": [ + "/ShieldItemID": [ "encapsulated", { "lengthType": "varint", @@ -502,7 +502,7 @@ { "compareTo": "network_id", "fields": { - "355": [ + "/ShieldItemID": [ "encapsulated", { "lengthType": "varint", @@ -1933,157 +1933,6 @@ } ] ], - "ScoreEntries": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "change", - "1": "remove" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "remove": [ - "container", - [ - { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": "zigzag64", - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "custom_name", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "fake_player": "string" - }, - "default": "void" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "ScoreboardIdentityEntries": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "TYPE_REGISTER_IDENTITY", - "1": "TYPE_CLEAR_IDENTITY" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "TYPE_REGISTER_IDENTITY": "zigzag64" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], "Enchant": [ "container", [ @@ -6982,9 +6831,102 @@ "packet_set_score": [ "container", [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "change", + "1": "remove" + } + } + ] + }, { "name": "entries", - "type": "ScoreEntries" + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "../action", + "fields": { + "change": [ + "container", + [ + { + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": "zigzag64", + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "custom_name", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "fake_player": "string" + }, + "default": "void" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] } ] ], @@ -7146,9 +7088,49 @@ "packet_set_scoreboard_identity": [ "container", [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "register_identity", + "1": "clear_identity" + } + } + ] + }, { "name": "entries", - "type": "ScoreboardIdentityEntries" + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "../action", + "fields": { + "register_identity": "zigzag64" + }, + "default": "void" + } + ] + } + ] + ] + } + ] } ] ], diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 57bbd76..e9ad376 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -1854,10 +1854,32 @@ packet_set_display_objective: criteria_name: string sort_order: zigzag32 +# SetScore is sent by the server to send the contents of a scoreboard to the player. It may be used to either +# add, remove or edit entries on the scoreboard. packet_set_score: !id: 0x6c !bound: client - entries: ScoreEntries + # ActionType is the type of the action to execute upon the scoreboard with the entries that the packet + # has. If ActionType is ScoreboardActionModify, all entries will be added to the scoreboard if not yet + # present, or modified if already present. If set to ScoreboardActionRemove, all scoreboard entries set + # will be removed from the scoreboard. + action: u8 => + 0: change + 1: remove + entries: []varint + scoreboard_id: zigzag64 + objective_name: string + score: li32 + _: ../action ? + if change: + entry_type: i8 => + 1: player + 2: entity + 3: fake_player + entity_unique_id: entry_type ? + if player or entity: zigzag64 + custom_name: entry_type ? + if fake_player: string packet_lab_table: !id: 0x6d @@ -1942,10 +1964,27 @@ DeltaMoveFlags: [ "bitflags", } ] +# SetScoreboardIdentity is sent by the server to change the identity type of one of the entries on a +# scoreboard. This is used to change, for example, an entry pointing to a player, to a fake player when it +# leaves the server, and to change it back to a real player when it joins again. +# In non-vanilla situations, the packet is quite useless. packet_set_scoreboard_identity: !id: 0x70 !bound: client - entries: ScoreboardIdentityEntries + # ActionType is the type of the action to execute. The action is either ScoreboardIdentityActionRegister + # to associate an identity with the entry, or ScoreboardIdentityActionClear to remove associations with + # an entity. + action: i8 => + 0: register_identity + 1: clear_identity + # Entries is a list of all entries in the packet. Each of these entries points to one of the entries on + # a scoreboard. Depending on ActionType, their identity will either be registered or cleared. + entries: []varint + scoreboard_id: zigzag64 + entity_unique_id: ../action ? + if register_identity: zigzag64 + default: void + # SetLocalPlayerAsInitialised is sent by the client in response to a PlayStatus packet with the status set # to spawn. The packet marks the moment at which the client is fully initialised and can receive any packet diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 8174c0f..9410467 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -112,7 +112,8 @@ ItemLegacy: metadata: varint block_runtime_id: zigzag32 extra: network_id ? - if 355: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' + # The Shield Item ID is sent in the StartGame packet. It is usually 355 in vanilla. + if /ShieldItemID: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]' # An "ItemStack" here represents an Item instance. You can think about it like a pointer @@ -137,7 +138,9 @@ Item: default: zigzag32 block_runtime_id: zigzag32 extra: network_id ? - if 355: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' + # The Shield Item ID is sent in the StartGame packet. It is usually 355 in vanilla. + ## Really bad compiler hack to allow us to use a global variable + if /ShieldItemID: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]' vec3i: @@ -708,35 +711,6 @@ PlayerRecords: verified: type ? if add: bool[]$records_count -ScoreEntries: - type: u8 => - 0: change - 1: remove - entries: []varint - scoreboard_id: zigzag64 - objective_name: string - score: li32 - _: type? - if remove: - entry_type: i8 => - 1: player - 2: entity - 3: fake_player - entity_unique_id: entry_type? - if player or entity: zigzag64 - custom_name: entry_type? - if fake_player: string - -ScoreboardIdentityEntries: - type: i8 => - 0: TYPE_REGISTER_IDENTITY - 1: TYPE_CLEAR_IDENTITY - entries: []varint - scoreboard_id: zigzag64 - entity_unique_id: type ? - if TYPE_REGISTER_IDENTITY: zigzag64 - default: void - Enchant: id: u8 level: u8 diff --git a/package.json b/package.json index ba7d7d6..dc2463b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", - "protodef": "extremeheat/node-protodef#patch-1", + "protodef": "github:extremeheat/node-protodef#vars", "smart-buffer": "^4.1.0", "uuid-1345": "^1.0.2" }, @@ -42,9 +42,9 @@ "bedrock-provider": "^1.0.0", "babel-eslint": "^10.1.0", "mocha": "^8.3.2", - "protodef-yaml": "^1.0.3", + "protodef-yaml": "^1.1.0", "standard": "^16.0.3", - "leveldb-zlib": "0.0.26", + "leveldb-zlib": "^0.0.26", "bedrock-protocol": "file:." }, "standard": { diff --git a/src/client.js b/src/client.js index 68c8886..0f82802 100644 --- a/src/client.js +++ b/src/client.js @@ -2,7 +2,6 @@ const { ClientStatus, Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { RakClient } = require('./rak') const { serialize } = require('./datatypes/util') -const fs = require('fs') const debug = require('debug')('minecraft-protocol') const Options = require('./options') const auth = require('./client/auth') @@ -152,33 +151,16 @@ class Client extends Connection { this.status = ClientStatus.Disconnected } - tryRencode (name, params, actual) { - const packet = this.serializer.createPacketBuffer({ name, params }) - - console.assert(packet.equals(actual)) - if (!packet.equals(actual)) { - const ours = packet.toString('hex').match(/.{1,16}/g).join('\n') - const theirs = actual.toString('hex').match(/.{1,16}/g).join('\n') - - fs.writeFileSync('ours.txt', ours) - fs.writeFileSync('theirs.txt', theirs) - fs.writeFileSync('ours.json', serialize(params)) - fs.writeFileSync('theirs.json', serialize(this.deserializer.parsePacketBuffer(packet).data.params)) - - throw new Error(name + ' Packet comparison failed!') - } - } - readPacket (packet) { const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } - this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100) */) + this.inLog('-> C', pakData.name, this.options.loggging ? serialize(pakData.params) : '') this.emit('packet', des) if (debugging) { // Packet verifying (decode + re-encode + match test) if (pakData.name) { - this.tryRencode(pakData.name, pakData.params, packet) + this.deserializer.verify(packet, this.serializer) } } @@ -193,6 +175,12 @@ class Client extends Connection { break case 'start_game': this.startGameData = pakData.params + this.startGameData.itemstates.forEach(state => { + if (state.name === 'minecraft:shield') { + this.serializer.proto.setVariable('ShieldItemID', state.runtime_id) + this.deserializer.proto.setVariable('ShieldItemID', state.runtime_id) + } + }) break case 'play_status': if (this.status === ClientStatus.Authenticating) { diff --git a/src/connection.js b/src/connection.js index 247dc0d..bf08245 100644 --- a/src/connection.js +++ b/src/connection.js @@ -40,8 +40,25 @@ class Connection extends EventEmitter { this.encrypt = cipher.createEncryptor(this, iv) } + updateItemPalette (palette) { + // In the future, we can send down the whole item palette if we need + // but since it's only one item, we can just make a single variable. + let shieldItemID + for (const state of palette) { + if (state.name === 'minecraft:shield') { + shieldItemID = state.runtime_id + break + } + } + if (shieldItemID) { + this.serializer.proto.setVariable('ShieldItemID', shieldItemID) + this.deserializer.proto.setVariable('ShieldItemID', shieldItemID) + } + } + write (name, params) { this.outLog('sending', name, params) + if (name === 'start_game') this.updateItemPalette(params.itemstates) const batch = new Framer() const packet = this.serializer.createPacketBuffer({ name, params }) batch.addEncodedPacket(packet) @@ -55,6 +72,7 @@ class Connection extends EventEmitter { queue (name, params) { this.outLog('Q <- ', name, params) + if (name === 'start_game') this.updateItemPalette(params.itemstates) const packet = this.serializer.createPacketBuffer({ name, params }) if (name === 'level_chunk') { // Skip queue, send ASAP @@ -113,7 +131,11 @@ class Connection extends EventEmitter { sendMCPE (buffer, immediate) { if (this.connection.connected === false || this.status === ClientStatus.Disconnected) return - this.connection.sendReliable(buffer, immediate) + try { + this.connection.sendReliable(buffer, immediate) + } catch (e) { + debug('while sending to', this.connection, e) + } } // These are callbacks called from encryption.js diff --git a/src/createClient.js b/src/createClient.js index 85856f9..77b2fc9 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -37,10 +37,10 @@ function connect (client) { response_status: 'completed', resourcepackids: [] }) + client.queue('request_chunk_radius', { chunk_radius: client.renderDistance || 10 }) }) client.queue('client_cache_status', { enabled: false }) - client.queue('request_chunk_radius', { chunk_radius: client.renderDistance || 1 }) client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) }) diff --git a/src/datatypes/minecraft.js b/src/datatypes/minecraft.js index ae5d324..a52d9c8 100644 --- a/src/datatypes/minecraft.js +++ b/src/datatypes/minecraft.js @@ -38,14 +38,18 @@ function sizeOfNbt (value) { // Little Endian function readNbtLE (buffer, offset) { - return protoLE.read(buffer, offset, 'nbt') + const r = protoLE.read(buffer, offset, 'nbt') + if (r.value.type === 'end') return { value: r.value, size: 0 } + return r } function writeNbtLE (value, buffer, offset) { + if (value.type === 'end') return offset return protoLE.write(value, buffer, offset, 'nbt') } function sizeOfNbtLE (value) { + if (value.type === 'end') return 0 return protoLE.sizeOf(value, 'nbt') } diff --git a/src/handshake/login.js b/src/handshake/login.js index c55665c..e4a9be8 100644 --- a/src/handshake/login.js +++ b/src/handshake/login.js @@ -6,7 +6,10 @@ const { PUBLIC_KEY } = require('./constants') const algorithm = 'ES384' module.exports = (client, server, options) => { - const skinGeom = fs.readFileSync(DataProvider(options.protocolVersion).getPath('skin_geom.txt'), 'utf-8') + const dp = DataProvider(options.protocolVersion) + const skinTex = fs.readFileSync(dp.getPath('steveSkin.bin')).toString('base64') + const skinGeom = fs.readFileSync(dp.getPath('steveGeometry.json')).toString('base64') + const skinData = JSON.parse(fs.readFileSync(dp.getPath('steve.json'), 'utf-8')) client.createClientChain = (mojangKey, offline) => { const privateKey = client.ecdhKeyPair.privateKey @@ -22,12 +25,12 @@ module.exports = (client, server, options) => { certificateAuthority: true, identityPublicKey: client.clientX509 } - token = JWT.sign(payload, privateKey, { algorithm, notBefore: 0, issuer: 'self', expiresIn: 60 * 60, header: { x5u: client.clientX509 } }) + token = JWT.sign(payload, privateKey, { algorithm, notBefore: 0, issuer: 'self', expiresIn: 60 * 60, header: { x5u: client.clientX509, typ: undefined } }) } else { token = JWT.sign({ identityPublicKey: mojangKey || PUBLIC_KEY, certificateAuthority: true - }, privateKey, { algorithm, header: { x5u: client.clientX509 } }) + }, privateKey, { algorithm, header: { x5u: client.clientX509, typ: undefined } }) } client.clientIdentityChain = token @@ -36,49 +39,38 @@ module.exports = (client, server, options) => { client.createClientUserChain = (privateKey) => { let payload = { - AnimatedImageData: [], - ArmSize: 'wide', - CapeData: '', - CapeId: '', - CapeImageHeight: 0, - CapeImageWidth: 0, - CapeOnClassicSkin: false, + ...skinData, + ClientRandomId: Date.now(), CurrentInputMode: 1, DefaultInputMode: 1, DeviceId: nextUUID(), - DeviceModel: '', + DeviceModel: 'PrismarineJS', DeviceOS: client.session?.deviceOS || 7, GameVersion: options.version || '1.16.201', GuiScale: -1, LanguageCode: 'en_GB', // TODO locale - PersonaPieces: [], - PersonaSkin: true, - PieceTintColors: [], + PlatformOfflineId: '', PlatformOnlineId: '', // chat // PlayFabID is the PlayFab ID produced for the skin. PlayFab is the company that hosts the Marketplace, // skins and other related features from the game. This ID is the ID of the skin used to store the skin // inside of PlayFab. - PlayFabId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', // 1.16.210 - PremiumSkin: false, + PlayFabId: nextUUID().replace(/-/g, '').slice(0, 16), // 1.16.210 + SelfSignedId: nextUUID(), ServerAddress: `${options.host}:${options.port}`, - SkinAnimationData: '', - SkinColor: '#ffffcd96', - SkinData: 'AAAAAA==', + SkinData: skinTex, SkinGeometryData: skinGeom, - SkinId: '5eb65f73-af11-448e-82aa-1b7b165316ad.persona-e199672a8c1a87e0-0', - SkinImageHeight: 1, - SkinImageWidth: 1, - SkinResourcePatch: '', + ThirdPartyName: client.profile.name, ThirdPartyNameOnly: false, UIProfile: 0 } const customPayload = options.skinData || {} payload = { ...payload, ...customPayload } + payload.ServerAddress = `${options.host}:${options.port}` - client.clientUserChain = JWT.sign(payload, privateKey, { algorithm, header: { x5u: client.clientX509 } }) + client.clientUserChain = JWT.sign(payload, privateKey, { algorithm, header: { x5u: client.clientX509, typ: undefined }, noTimestamp: true /* pocketmine.. */ }) } } diff --git a/src/relay.js b/src/relay.js index 9e7992a..26a44e2 100644 --- a/src/relay.js +++ b/src/relay.js @@ -30,6 +30,7 @@ class RelayPlayer extends Player { this.outLog = this.downOutLog this.inLog = this.downInLog + this.chunkSendCache = [] } // Called when we get a packet from backend server (Backend -> PROXY -> Client) @@ -45,16 +46,23 @@ class RelayPlayer extends Player { if (name === 'play_status' && params.status === 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect if (debugging) { // some packet encode/decode testing stuff - const rpacket = this.server.serializer.createPacketBuffer({ name, params }) - if (!rpacket.equals(packet)) { - console.warn('New', rpacket.toString('hex')) - console.warn('Old', packet.toString('hex')) - console.log('Failed to re-encode', name, params) - process.exit(1) - } + this.server.deserializer.verify(des, this.server.serializer) } this.emit('clientbound', des.data) + + // If we're sending a chunk, but player isn't yet initialized, wait until it is. + // This is wrong and should not be an issue to send chunks before the client + // is in the world; need to investigate further, but for now it's fine. + if (name === 'level_chunk' && this.status !== 3) { + this.chunkSendCache.push([name, params]) + return + } else if (this.status === 3 && this.chunkSendCache.length) { + for (const chunk of this.chunkSendCache) { + this.queue(...chunk) + } + this.chunkSendCache = [] + } this.queue(name, params) } @@ -82,33 +90,36 @@ class RelayPlayer extends Player { // Called when the server gets a packet from the downstream player (Client -> PROXY -> Backend) readPacket (packet) { - if (this.startRelaying) { // The downstream client conn is established & we got a packet to send to upstream server - if (!this.upstream) { // Upstream is still connecting/handshaking + // The downstream client conn is established & we got a packet to send to upstream server + if (this.startRelaying) { + // Upstream is still connecting/handshaking + if (!this.upstream) { this.downInLog('Got downstream connected packet but upstream is not connected yet, added to q', this.upQ.length) this.upQ.push(packet) // Put into a queue return } - this.flushUpQueue() // Send queued packets + + // Send queued packets + this.flushUpQueue() this.downInLog('recv', packet) + // TODO: If we fail to parse a packet, proxy it raw and log an error const des = this.server.deserializer.parsePacketBuffer(packet) if (debugging) { // some packet encode/decode testing stuff - const rpacket = this.server.serializer.createPacketBuffer(des.data) - if (!rpacket.equals(packet)) { - console.warn('New', rpacket.toString('hex')) - console.warn('Old', packet.toString('hex')) - console.log('Failed to re-encode', des.data) - process.exit(1) - } + this.server.deserializer.verify(des, this.server.serializer) } this.emit('serverbound', des.data) switch (des.data.name) { case 'client_cache_status': + // Force the chunk cache off. this.upstream.queue('client_cache_status', { enabled: false }) break + case 'set_local_player_as_initialized': + this.status = 3 + break default: // Emit the packet as-is back to the upstream server this.downInLog('Relaying', des.data) @@ -149,6 +160,10 @@ class Relay extends Server { client.outLog = ds.upOutLog client.inLog = ds.upInLog client.once('join', () => { // Intercept once handshaking done + // Tell the server to disable chunk cache for this connection as a client. + // Wait a bit for the server to ack and process, the continue with proxying + // otherwise the player can get stuck in an empty world. + client.write('client_cache_status', { enabled: false }) ds.upstream = client ds.flushUpQueue() this.conLog('Connected to upstream server') diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index f78e4c8..4a6102f 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -11,6 +11,18 @@ class Parser extends FullPacketParser { throw e } } + + verify (deserialized, serializer) { + const { name, params } = deserialized.data + const oldBuffer = deserialized.fullBuffer + const newBuffer = serializer.createPacketBuffer({ name, params }) + if (!newBuffer.equals(oldBuffer)) { + console.warn('New', newBuffer.toString('hex')) + console.warn('Old', oldBuffer.toString('hex')) + console.log('Failed to re-encode', name, params) + process.exit(1) + } + } } // Compiles the ProtoDef schema at runtime @@ -31,11 +43,8 @@ function getProtocol (version) { compiler.addTypes(require(join(__dirname, '../datatypes/compiler-minecraft'))) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) - const compile = (compiler, file) => { - global.native = compiler.native // eslint-disable-line - const { PartialReadError } = require('protodef/src/utils') // eslint-disable-line - return require(file)() // eslint-disable-line - } + global.PartialReadError = require('protodef/src/utils').PartialReadError + const compile = (compiler, file) => require(file)(compiler.native) return new CompiledProtodef( compile(compiler.sizeOfCompiler, join(__dirname, `../../data/${version}/size.js`)), diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index 4163094..bed7b2c 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -55,9 +55,9 @@ function createProtocol () { compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) compiler.addTypesToCompile(protocol) - fs.writeFileSync('./read.js', 'module.exports = ' + compiler.readCompiler.generate()) - fs.writeFileSync('./write.js', 'module.exports = ' + compiler.writeCompiler.generate()) - fs.writeFileSync('./size.js', 'module.exports = ' + compiler.sizeOfCompiler.generate()) + fs.writeFileSync('./read.js', 'module.exports = ' + compiler.readCompiler.generate().replace('() =>', 'native =>')) + fs.writeFileSync('./write.js', 'module.exports = ' + compiler.writeCompiler.generate().replace('() =>', 'native =>')) + fs.writeFileSync('./size.js', 'module.exports = ' + compiler.sizeOfCompiler.generate().replace('() =>', 'native =>')) const compiledProto = compiler.compileProtoDefSync() return compiledProto From 9cb4a888f4adc5b328309a46fcbe146c944144b7 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 24 May 2021 12:07:03 -0400 Subject: [PATCH 184/458] Fix empty chunks on proxy spawn (#89) * Fix empty chunks on proxy spawn Hack to fix issue with chunks not loading when client joins the proxy * Queue chunk, respawn packets and only send them after player spawn * fix lint --- data/latest/proto.yml | 10 +++++++++- src/relay.js | 14 +++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/data/latest/proto.yml b/data/latest/proto.yml index e9ad376..1513e1f 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -923,7 +923,15 @@ packet_set_spawn_position: packet_animate: !id: 0x2c !bound: both - action_id: zigzag32 + action_id: zigzag32 => + 0: none + 1: swing_arm + 2: unknown + 3: wake_up + 4: critical_hit + 5: magic_critical_hit + 6: row_right + 7: row_left runtime_entity_id: varint64 packet_respawn: diff --git a/src/relay.js b/src/relay.js index 26a44e2..d7aa98c 100644 --- a/src/relay.js +++ b/src/relay.js @@ -31,6 +31,7 @@ class RelayPlayer extends Player { this.outLog = this.downOutLog this.inLog = this.downInLog this.chunkSendCache = [] + this.respawnPacket = [] } // Called when we get a packet from backend server (Backend -> PROXY -> Client) @@ -54,14 +55,21 @@ class RelayPlayer extends Player { // If we're sending a chunk, but player isn't yet initialized, wait until it is. // This is wrong and should not be an issue to send chunks before the client // is in the world; need to investigate further, but for now it's fine. - if (name === 'level_chunk' && this.status !== 3) { - this.chunkSendCache.push([name, params]) - return + if (this.status !== 3) { + if (name === 'level_chunk') { + this.chunkSendCache.push([name, params]) + return + } + if (name === 'respawn') this.respawnPacket.push([name, params]) } else if (this.status === 3 && this.chunkSendCache.length) { for (const chunk of this.chunkSendCache) { this.queue(...chunk) } + for (const rp of this.respawnPacket) { + this.queue(...rp) + } this.chunkSendCache = [] + this.respawnPacket = [] } this.queue(name, params) } From 025c2cfac6703c51ef0f2b97ed51f30d197e233b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 24 May 2021 12:14:15 -0400 Subject: [PATCH 185/458] Release 3.2.0 --- HISTORY.md | 8 ++++++++ data/1.16.220/protocol.json | 17 ++++++++++++++++- package.json | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 4eac540..d6f0347 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,11 @@ +## 3.2.0 + +* Fix empty chunks on proxy spawn (#89) +* Send skin data to server (#88) +* Support xbox title + live.com auth (#86) +* Protocol updates and fixes +* Fix third party servers, optional client encryption (#83) + ## 3.1.0 * Add support for 1.16 * New docs and examples diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index ed967de..4d0de82 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -5110,7 +5110,22 @@ [ { "name": "action_id", - "type": "zigzag32" + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "none", + "1": "swing_arm", + "2": "unknown", + "3": "wake_up", + "4": "critical_hit", + "5": "magic_critical_hit", + "6": "row_right", + "7": "row_left" + } + } + ] }, { "name": "runtime_entity_id", diff --git a/package.json b/package.json index dc2463b..4f6280b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.1.0", + "version": "3.2.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 6a7ad6ab98f5a8317ae30d4fb3d8ceaeb71832d1 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 26 May 2021 11:08:19 -0400 Subject: [PATCH 186/458] protocol: Fix position serialization --- data/1.16.220/protocol.json | 88 +++++++------------------------------ data/latest/proto.yml | 32 ++++---------- 2 files changed, 25 insertions(+), 95 deletions(-) diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index 4d0de82..0fb610a 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -4177,28 +4177,12 @@ "type": "string" }, { - "name": "x", - "type": "lf32" + "name": "position", + "type": "vec3f" }, { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" + "name": "velocity", + "type": "vec3f" }, { "name": "pitch", @@ -4274,28 +4258,12 @@ "type": "string" }, { - "name": "x", - "type": "lf32" + "name": "position", + "type": "vec3f" }, { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" + "name": "velocity", + "type": "vec3f" }, { "name": "pitch", @@ -4348,28 +4316,12 @@ "type": "Item" }, { - "name": "x", - "type": "lf32" + "name": "position", + "type": "vec3f" }, { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" + "name": "velocity", + "type": "vec3f" }, { "name": "metadata", @@ -4547,7 +4499,7 @@ }, { "name": "coordinates", - "type": "BlockCoordinates" + "type": "vec3f" }, { "name": "direction", @@ -5137,16 +5089,8 @@ "container", [ { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" + "name": "position", + "type": "vec3f" }, { "name": "state", @@ -7192,7 +7136,7 @@ "container", [ { - "name": "dimension_id", + "name": "dimension", "type": "u8" }, { diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 1513e1f..fc04f94 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -401,12 +401,8 @@ packet_add_player: # Nintendo Switch). It is otherwise an empty string, and is used to decide which players # are able to chat with each other. platform_chat_id: string - x: lf32 - y: lf32 - z: lf32 - speed_x: lf32 - speed_y: lf32 - speed_z: lf32 + position: vec3f + velocity: vec3f pitch: lf32 yaw: lf32 head_yaw: lf32 @@ -428,12 +424,8 @@ packet_add_entity: entity_id_self: zigzag64 runtime_entity_id: varint64 entity_type: string - x: lf32 - y: lf32 - z: lf32 - speed_x: lf32 - speed_y: lf32 - speed_z: lf32 + position: vec3f + velocity: vec3f pitch: lf32 yaw: lf32 head_yaw: lf32 @@ -452,12 +444,8 @@ packet_add_item_entity: entity_id_self: zigzag64 runtime_entity_id: varint64 item: Item - x: lf32 - y: lf32 - z: lf32 - speed_x: lf32 - speed_y: lf32 - speed_z: lf32 + position: vec3f + velocity: vec3f metadata: MetadataDictionary is_from_fishing: bool @@ -573,7 +561,7 @@ packet_add_painting: !bound: client entity_id_self: zigzag64 runtime_entity_id: varint64 - coordinates: BlockCoordinates + coordinates: vec3f direction: zigzag32 title: string @@ -937,9 +925,7 @@ packet_animate: packet_respawn: !id: 0x2d !bound: both - x: lf32 - y: lf32 - z: lf32 + position: vec3f state: u8 runtime_entity_id: varint64 @@ -2023,7 +2009,7 @@ packet_script_custom_event: packet_spawn_particle_effect: !id: 0x76 !bound: client - dimension_id: u8 + dimension: u8 entity_id: zigzag64 position: vec3f particle_name: string From 5af828bcb7aa0df4705702ae43ec2ef0875721a3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 29 May 2021 21:09:51 -0400 Subject: [PATCH 187/458] Update types, add `authTitle` option to relay, client renderDistance -> viewDistance --- .npmignore | 6 +++++- data/latest/proto.yml | 30 +++++++++++++++++++++++++++++- examples/createRelay.js | 7 +++++-- index.d.ts | 35 +++++++++++++++++++++++++++-------- src/createClient.js | 5 ++++- src/relay.js | 5 +++-- 6 files changed, 73 insertions(+), 15 deletions(-) diff --git a/.npmignore b/.npmignore index a085593..c80c616 100644 --- a/.npmignore +++ b/.npmignore @@ -4,4 +4,8 @@ __* src/**/*.json # Runtime generated data data/**/sample -tools/bds* \ No newline at end of file +tools/bds* +# Extra data +examples +test +.github \ No newline at end of file diff --git a/data/latest/proto.yml b/data/latest/proto.yml index fc04f94..079f2d3 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -1014,6 +1014,16 @@ packet_container_set_data: window_id: WindowID # Key is the key of the property. It is one of the constants that can be found above. Multiple properties # share the same key, but the functionality depends on the type of the container that the data is set to. + # IF FURNACE: + # 0: furnace_tick_count + # 1: furnace_lit_time + # 2: furnace_lit_duration + # 3: furnace_stored_xp + # 4: furnace_fuel_aux + # IF BREWING STAND: + # 0: brew_time + # 1: brew_fuel_amount + # 2: brew_fuel_total property: zigzag32 # Value is the value of the property. Its use differs per property. value: zigzag32 @@ -1329,14 +1339,24 @@ packet_map_info_request: !bound: both map_id: zigzag64 +# RequestChunkRadius is sent by the client to the server to update the server on the chunk view radius that +# it has set in the settings. The server may respond with a ChunkRadiusUpdated packet with either the chunk +# radius requested, or a different chunk radius if the server chooses so. packet_request_chunk_radius: !id: 0x45 !bound: both + # ChunkRadius is the requested chunk radius. This value is always the value set in the settings of the + # player. chunk_radius: zigzag32 +# ChunkRadiusUpdated is sent by the server in response to a RequestChunkRadius packet. It defines the chunk +# radius that the server allows the client to have. This may be lower than the chunk radius requested by the +# client in the RequestChunkRadius packet. packet_chunk_radius_update: !id: 0x46 !bound: client + # ChunkRadius is the final chunk radius that the client will adapt when it receives the packet. It does + # not have to be the same as the requested chunk radius. chunk_radius: zigzag32 packet_item_frame_drop_item: @@ -1994,11 +2014,19 @@ packet_update_soft_enum: !id: 0x72 !bound: client +# NetworkStackLatency is sent by the server (and the client, on development builds) to measure the latency +# over the entire Minecraft stack, rather than the RakNet latency. It has other usages too, such as the +# ability to be used as some kind of acknowledgement packet, to know when the client has received a certain +# other packet. packet_network_stack_latency: !id: 0x73 !bound: both + # Timestamp is the timestamp of the network stack latency packet. The client will, if NeedsResponse is + # set to true, send a NetworkStackLatency packet with this same timestamp packet in response. timestamp: lu64 - unknown_flag: u8 + # NeedsResponse specifies if the sending side of this packet wants a response to the packet, meaning that + # the other side should send a NetworkStackLatency packet back. + needs_response: u8 packet_script_custom_event: !id: 0x75 diff --git a/examples/createRelay.js b/examples/createRelay.js index 7209904..f99a0ee 100644 --- a/examples/createRelay.js +++ b/examples/createRelay.js @@ -1,4 +1,4 @@ -const { Relay } = require('../src/relay') +const { Relay, title } = require('bedrock-protocol') function createRelay () { console.log('Creating relay') @@ -7,10 +7,13 @@ function createRelay () { /* host and port for clients to listen to */ host: '0.0.0.0', port: 19130, + offline: false, + authTitle: title.MinecraftNintendoSwitch, /* Where to send upstream packets to */ destination: { host: '127.0.0.1', - port: 19132 + port: 19132, + offline: false } }) relay.conLog = console.debug diff --git a/index.d.ts b/index.d.ts index b08e207..e403471 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,15 +7,27 @@ declare module "bedrock-protocol" { export interface Options { // The string version to start the client or server as - version: number, + version: string // For the client, the host of the server to connect to (default: 127.0.0.1) // For the server, the host to bind to (default: 0.0.0.0) - host: string, + host: string // The port to connect or bind to, default: 19132 - port: number, - // The maximum number of players allowed on the server at any time. - maxPlayers: number, + port: number + // For the client, if we should login with Microsoft/Xbox Live. + // For the server, if we should verify client's authentication with Xbox Live. + offline: boolean + } + export interface ClientOptions extends Options { + // The view distance in chunks + viewDistance: number, + // Specifies which game edition to sign in as. Optional, but some servers verify this. + authTitle: title | string + } + + export interface ServerOptions extends Options { + // The maximum number of players allowed on the server at any time. + maxPlayers: number motd: { // The header for the MOTD shown in the server list. motd: string, @@ -109,12 +121,19 @@ declare module "bedrock-protocol" { port: number, // Toggle packet logging. logging: boolean, + // Skip authentication for connecting clients? + offline: false, + // Specifies which game edition to sign in as to the destination server. Optional, but some servers verify this. + authTitle: title | string // Where to proxy requests to. destination: { host: string, - port: number + port: number, + // Skip authentication connecting to the remote server? + offline: false, } } + export class Relay extends Server { constructor(options: RelayOptions) } @@ -132,8 +151,8 @@ declare module "bedrock-protocol" { serverId: string } - export function createClient(options: Options): Client - export function createServer(options: Options): Server + export function createClient(options: ClientOptions): Client + export function createServer(options: ServerOptions): Server export function ping({ host, port }) : ServerAdvertisement } \ No newline at end of file diff --git a/src/createClient.js b/src/createClient.js index 77b2fc9..34a07db 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -2,6 +2,7 @@ const { Client } = require('./client') const { RakClient } = require('./rak') const assert = require('assert') const advertisement = require('./server/advertisement') +const { sleep } = require('./datatypes/util') /** @param {{ version?: number, host: string, port?: number, connectTimeout?: number }} options */ function createClient (options) { @@ -37,11 +38,13 @@ function connect (client) { response_status: 'completed', resourcepackids: [] }) - client.queue('request_chunk_radius', { chunk_radius: client.renderDistance || 10 }) }) client.queue('client_cache_status', { enabled: false }) client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) + if (client.viewDistance) { + sleep(500).then(() => client.queue('request_chunk_radius', { chunk_radius: client.viewDistance })) + } }) const KEEPALIVE_INTERVAL = 10 // Send tick sync packets every 10 ticks diff --git a/src/relay.js b/src/relay.js index d7aa98c..0a382b4 100644 --- a/src/relay.js +++ b/src/relay.js @@ -3,7 +3,7 @@ const { Server } = require('./server') const { Player } = require('./serverPlayer') const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol') -const debugging = true // Do re-encoding tests +const debugging = false // Do re-encoding tests class RelayPlayer extends Player { constructor (server, conn) { @@ -154,7 +154,8 @@ class Relay extends Server { openUpstreamConnection (ds, clientAddr) { const client = new Client({ - offline: this.options.offline, + authTitle: this.options.authTitle, + offline: this.options.destination.offline ?? this.options.offline, username: this.options.offline ? ds.profile.name : null, version: this.options.version, host: this.options.destination.host, From e9098aa744584e7e2083aeb1fa5833cb7ff8867d Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 29 May 2021 23:56:33 -0400 Subject: [PATCH 188/458] test/proxy: extra debug logging --- data/1.16.220/protocol.json | 2 +- data/latest/types.yaml | 5 +++-- src/client.js | 6 +++--- test/proxy.js | 4 ++++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index 0fb610a..b9e00f0 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -7114,7 +7114,7 @@ "type": "lu64" }, { - "name": "unknown_flag", + "name": "needs_response", "type": "u8" } ] diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 9410467..5e05b31 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -1015,8 +1015,9 @@ MapDecoration: # automatically, whereas others may be changed. color_abgr: varint -# Some arbitrary definitions from CBMC, Window IDs are normally -# unique + sequential +# List of Window IDs. When a new container is opened (container_open), a new sequential Window ID is created. +# Below window IDs are hard-coded and created when the game starts and the server does not +# send a `container_open` for them. WindowID: i8 => -100: drop_contents -24: beacon diff --git a/src/client.js b/src/client.js index 0f82802..e675367 100644 --- a/src/client.js +++ b/src/client.js @@ -43,7 +43,7 @@ class Client extends Connection { this.on('session', this._connect) if (this.options.offline) { - console.debug('offline mode, not authenticating', this.options) + debug('offline mode, not authenticating', this.options) auth.createOfflineSession(this, this.options) } else { auth.authenticateDeviceCode(this, this.options) @@ -122,7 +122,7 @@ class Client extends Connection { } onDisconnectRequest (packet) { - console.warn(`C Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) + console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) this.emit('kick', packet) this.close() } @@ -140,7 +140,7 @@ class Client extends Connection { close () { if (this.status !== ClientStatus.Disconnected) { this.emit('close') // Emit close once - console.log('Client closed!') + debug('Client closed!') } clearInterval(this.loop) clearTimeout(this.connectTimeout) diff --git a/test/proxy.js b/test/proxy.js index 5c98785..2ea17b9 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -11,7 +11,9 @@ function proxyTest (version, timeout = 1000 * 40) { }) server.on('connect', client => { + console.debug('Client has connected') client.on('join', () => { // The client has joined the server. + console.debug('Client has authenticated') setTimeout(() => { client.disconnect('Hello world !') }, 1000) // allow some time for client to connect @@ -41,6 +43,8 @@ function proxyTest (version, timeout = 1000 * 40) { console.debug('Client started') + client.on('packet', console.log) + client.on('disconnect', packet => { console.assert(packet.message === 'Hello world !') From d981515a7540327c554e67b8cc3583c7debfaf2b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 30 May 2021 00:09:33 -0400 Subject: [PATCH 189/458] Release 3.2.1 --- HISTORY.md | 12 ++++++++---- data/latest/types.yaml | 2 +- package.json | 2 +- src/createClient.js | 4 +--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index d6f0347..b731bf8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,10 +1,14 @@ +## 3.2.1 +* Add `authTitle` option to Relay proxy [#92](https://github.com/PrismarineJS/bedrock-protocol/pull/92) +* Protocol, type definition fixes + ## 3.2.0 -* Fix empty chunks on proxy spawn (#89) -* Send skin data to server (#88) -* Support xbox title + live.com auth (#86) +* Fix empty chunks on proxy spawn [#89](https://github.com/PrismarineJS/bedrock-protocol/pull/89) +* Send skin data to server [#88](https://github.com/PrismarineJS/bedrock-protocol/pull/88) +* Support xbox title + live.com auth [#86](https://github.com/PrismarineJS/bedrock-protocol/pull/86) * Protocol updates and fixes -* Fix third party servers, optional client encryption (#83) +* Fix third party servers, optional client encryption [#83](https://github.com/PrismarineJS/bedrock-protocol/pull/83) ## 3.1.0 * Add support for 1.16 diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 5e05b31..95f395e 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -130,7 +130,7 @@ Item: # When server authoritative inventory is enabled, all allocated items have a unique ID used to identify # a specifc item instance. has_stack_id: u8 - # StackNetworkID is the network ID of the item stack. If the stack is empty, 0 is always written for this + # StackNetworkID is the network ID of this item *instance*. If the stack is empty, 0 is always written for this # field. If not, the field should be set to 1 if the server authoritative inventories are disabled in the # StartGame packet, or to a unique stack ID if it is enabled. stack_id: has_stack_id ? diff --git a/package.json b/package.json index 4f6280b..eb8a935 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.2.0", + "version": "3.2.1", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { diff --git a/src/createClient.js b/src/createClient.js index 34a07db..50009be 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -42,9 +42,7 @@ function connect (client) { client.queue('client_cache_status', { enabled: false }) client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) - if (client.viewDistance) { - sleep(500).then(() => client.queue('request_chunk_radius', { chunk_radius: client.viewDistance })) - } + sleep(500).then(() => client.queue('request_chunk_radius', { chunk_radius: client.viewDistance || 10 })) }) const KEEPALIVE_INTERVAL = 10 // Send tick sync packets every 10 ticks From 01575ecd6f84a3a2a41e27fe2776af82f42f9b19 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 3 Jun 2021 04:25:47 +0000 Subject: [PATCH 190/458] temporary install fix --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index eb8a935..eb3d8c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.2.1", + "version": "3.2.2", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { @@ -30,7 +30,7 @@ "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", - "protodef": "github:extremeheat/node-protodef#vars", + "protodef": "npm:protodef-compiler-fix@latest", "smart-buffer": "^4.1.0", "uuid-1345": "^1.0.2" }, @@ -39,13 +39,13 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", - "bedrock-provider": "^1.0.0", "babel-eslint": "^10.1.0", + "bedrock-protocol": "file:.", + "bedrock-provider": "^1.0.0", + "leveldb-zlib": "^0.0.26", "mocha": "^8.3.2", "protodef-yaml": "^1.1.0", - "standard": "^16.0.3", - "leveldb-zlib": "^0.0.26", - "bedrock-protocol": "file:." + "standard": "^16.0.3" }, "standard": { "parser": "babel-eslint" From 0f0d064b13de394ccf7aba7cd9228b2cd6da130a Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 3 Jun 2021 04:38:49 +0000 Subject: [PATCH 191/458] Revert "temporary install fix" This reverts commit 01575ecd6f84a3a2a41e27fe2776af82f42f9b19. --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index eb3d8c2..eb8a935 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.2.2", + "version": "3.2.1", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { @@ -30,7 +30,7 @@ "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", - "protodef": "npm:protodef-compiler-fix@latest", + "protodef": "github:extremeheat/node-protodef#vars", "smart-buffer": "^4.1.0", "uuid-1345": "^1.0.2" }, @@ -39,13 +39,13 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", - "babel-eslint": "^10.1.0", - "bedrock-protocol": "file:.", "bedrock-provider": "^1.0.0", - "leveldb-zlib": "^0.0.26", + "babel-eslint": "^10.1.0", "mocha": "^8.3.2", "protodef-yaml": "^1.1.0", - "standard": "^16.0.3" + "standard": "^16.0.3", + "leveldb-zlib": "^0.0.26", + "bedrock-protocol": "file:." }, "standard": { "parser": "babel-eslint" From 6da8a9b2fcfd2c810dce038d200eb3a61ee29597 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 2 Jun 2021 19:38:08 -0400 Subject: [PATCH 192/458] Minor protocol fix for entity data --- data/1.16.220/protocol.json | 8 ++++++-- data/latest/types.yaml | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index b9e00f0..5382c19 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -723,8 +723,12 @@ "117": "nearby_cured_discount_timestamp", "118": "hitbox", "119": "is_buoyant", - "120": "buoyancy_data", - "121": "goat_horn_count" + "120": "freezing_effect_strength", + "121": "buoyancy_data", + "122": "goat_horn_count", + "123": "base_runtime_id", + "124": "define_properties", + "125": "update_properties" } } ] diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 95f395e..74898ca 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -283,8 +283,12 @@ MetadataDictionary: []varint 117: nearby_cured_discount_timestamp 118: hitbox 119: is_buoyant - 120: buoyancy_data - 121: goat_horn_count + 120: freezing_effect_strength + 121: buoyancy_data + 122: goat_horn_count + 123: base_runtime_id + 124: define_properties + 125: update_properties type: varint => 0: byte 1: short From ab70115bd876394d725ecf3bdccce6bac2e52729 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 3 Jun 2021 16:33:33 -0400 Subject: [PATCH 193/458] Protocol updates for 1.16 * Login packet uses new Encapsulated type * Add missing packet schemas * Add more docs Breaking: revises some field names --- data/1.16.201/protocol.json | 21 +- data/1.16.210/protocol.json | 21 +- data/1.16.220/protocol.json | 487 +++++++++++++++++++++++++++++------- data/latest/proto.yml | 405 ++++++++++++++++++++++++++++-- data/latest/types.yaml | 38 ++- src/client.js | 8 +- src/serverPlayer.js | 5 +- 7 files changed, 850 insertions(+), 135 deletions(-) diff --git a/data/1.16.201/protocol.json b/data/1.16.201/protocol.json index 361d139..a62a5ed 100644 --- a/data/1.16.201/protocol.json +++ b/data/1.16.201/protocol.json @@ -2948,15 +2948,26 @@ "type": "i32" }, { - "name": "payload_size", - "type": "varint" - }, + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] + ], + "LoginTokens": [ + "container", + [ { - "name": "chain", + "name": "identity", "type": "LittleString" }, { - "name": "client_data", + "name": "client", "type": "LittleString" } ] diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 47043ad..1010531 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -3159,15 +3159,26 @@ "type": "i32" }, { - "name": "payload_size", - "type": "varint" - }, + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] + ], + "LoginTokens": [ + "container", + [ { - "name": "chain", + "name": "identity", "type": "LittleString" }, { - "name": "client_data", + "name": "client", "type": "LittleString" } ] diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index 5382c19..b49072a 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -1950,62 +1950,56 @@ } ] ], - "EnchantOptions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ + "EnchantOption": [ + "container", + [ + { + "name": "cost", + "type": "varint" + }, + { + "name": "slot_flags", + "type": "li32" + }, + { + "name": "equip_enchants", + "type": [ + "array", { - "name": "cost", - "type": "varint" - }, - { - "name": "slot_flags", - "type": "li32" - }, - { - "name": "equip_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "held_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "self_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "name", - "type": "string" - }, - { - "name": "option_id", - "type": "zigzag32" + "countType": "varint", + "type": "Enchant" } ] - ] - } + }, + { + "name": "held_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "self_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "name", + "type": "string" + }, + { + "name": "option_id", + "type": "zigzag32" + } + ] ], "Action": [ "mapper", @@ -2583,6 +2577,55 @@ } ] ], + "StructureBlockSettings": [ + "container", + [ + { + "name": "palette_name", + "type": "string" + }, + { + "name": "ignore_entities", + "type": "bool" + }, + { + "name": "ignore_blocks", + "type": "bool" + }, + { + "name": "size", + "type": "BlockCoordinates" + }, + { + "name": "structure_offset", + "type": "BlockCoordinates" + }, + { + "name": "last_editing_player_unique_id", + "type": "zigzag64" + }, + { + "name": "rotation", + "type": "u8" + }, + { + "name": "mirror", + "type": "u8" + }, + { + "name": "integrity", + "type": "lf32" + }, + { + "name": "seed", + "type": "lu32" + }, + { + "name": "pivot", + "type": "vec3f" + } + ] + ], "WindowID": [ "mapper", { @@ -3567,15 +3610,26 @@ "type": "i32" }, { - "name": "payload_size", - "type": "varint" - }, + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] + ], + "LoginTokens": [ + "container", + [ { - "name": "chain", + "name": "identity", "type": "LittleString" }, { - "name": "client_data", + "name": "client", "type": "LittleString" } ] @@ -6170,6 +6224,81 @@ { "name": "is_block", "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "is_block", + "fields": { + "true": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "impulse", + "1": "repeat", + "2": "chain" + } + } + ] + }, + { + "name": "needs_redstone", + "type": "bool" + }, + { + "name": "conditional", + "type": "bool" + } + ] + ] + }, + "default": [ + "container", + [ + { + "name": "minecart_entity_runtime_id", + "type": "varint64" + } + ] + ] + } + ] + }, + { + "name": "command", + "type": "string" + }, + { + "name": "last_output", + "type": "string" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "should_track_output", + "type": "bool" + }, + { + "name": "tick_delay", + "type": "li32" + }, + { + "name": "execute_on_first_tick", + "type": "bool" } ] ], @@ -6320,7 +6449,7 @@ "container", [ { - "name": "package_id", + "name": "pack_id", "type": "string" }, { @@ -6332,7 +6461,7 @@ "type": "lu32" }, { - "name": "compressed_package_size", + "name": "size", "type": "lu64" }, { @@ -6345,7 +6474,22 @@ }, { "name": "pack_type", - "type": "u8" + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "addon", + "2": "cached", + "3": "copy_protected", + "4": "behavior", + "5": "persona_piece", + "6": "resources", + "7": "skins", + "8": "world_template" + } + } + ] } ] ], @@ -6353,7 +6497,7 @@ "container", [ { - "name": "package_id", + "name": "pack_id", "type": "string" }, { @@ -6374,7 +6518,7 @@ "container", [ { - "name": "package_id", + "name": "pack_id", "type": "string" }, { @@ -6482,24 +6626,72 @@ ], "packet_structure_block_update": [ "container", - [] + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "structure_name", + "type": "string" + }, + { + "name": "data_field", + "type": "string" + }, + { + "name": "include_players", + "type": "bool" + }, + { + "name": "show_bounding_box", + "type": "bool" + }, + { + "name": "structure_block_type", + "type": "zigzag32" + }, + { + "name": "settings", + "type": "StructureBlockSettings" + }, + { + "name": "redstone_save_mode", + "type": "zigzag32" + }, + { + "name": "should_trigger", + "type": "bool" + } + ] ], "packet_show_store_offer": [ "container", [ { - "name": "unknown0", + "name": "offer_id", "type": "string" }, { - "name": "unknown1", + "name": "show_all", "type": "bool" } ] ], "packet_purchase_receipt": [ "container", - [] + [ + { + "name": "receipts", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] ], "packet_player_skin": [ "container", @@ -6528,7 +6720,18 @@ ], "packet_sub_client_login": [ "container", - [] + [ + { + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] ], "packet_initiate_web_socket_connection": [ "container", @@ -6543,7 +6746,7 @@ "container", [ { - "name": "unknown", + "name": "entity_type", "type": "varint" } ] @@ -6666,15 +6869,28 @@ "type": "varint64" }, { - "name": "unknown0", - "type": "u8" + "name": "request_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "set_actions", + "1": "execute_action", + "2": "execute_closing_commands", + "3": "set_name", + "4": "set_skin", + "5": "set_interaction_text" + } + } + ] }, { - "name": "unknown1", + "name": "command", "type": "string" }, { - "name": "unknown2", + "name": "action_type", "type": "u8" } ] @@ -6683,7 +6899,7 @@ "container", [ { - "name": "file_name", + "name": "image_name", "type": "string" }, { @@ -6691,7 +6907,7 @@ "type": "string" }, { - "name": "unknown2", + "name": "book_id", "type": "string" } ] @@ -6897,20 +7113,21 @@ "container", [ { - "name": "useless_byte", - "type": "u8" + "name": "action_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "combine", + "1": "react" + } + } + ] }, { - "name": "lab_table_x", - "type": "varint" - }, - { - "name": "lab_table_y", - "type": "varint" - }, - { - "name": "lab_table_z", - "type": "varint" + "name": "position", + "type": "vec3u" }, { "name": "reaction_type", @@ -7229,7 +7446,7 @@ "type": "vec3f" }, { - "name": "block_id", + "name": "extra_data", "type": "zigzag32" }, { @@ -7334,19 +7551,95 @@ ], "packet_on_screen_texture_animation": [ "container", - [] + [ + { + "name": "animation_type", + "type": "lu32" + } + ] ], "packet_map_create_locked_copy": [ "container", - [] + [ + { + "name": "original_map_id", + "type": "zigzag64" + }, + { + "name": "new_map_id", + "type": "zigzag64" + } + ] ], "packet_structure_template_data_export_request": [ "container", - [] + [ + { + "name": "name", + "type": "string" + }, + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "settings", + "type": "StructureBlockSettings" + }, + { + "name": "request_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "export_from_save", + "2": "export_from_load", + "3": "query_saved_structure" + } + } + ] + } + ] ], "packet_structure_template_data_export_response": [ "container", - [] + [ + { + "name": "name", + "type": "string" + }, + { + "name": "success", + "type": "bool" + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "success", + "fields": { + "true": "nbt" + }, + "default": "void" + } + ] + }, + { + "name": "response_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "export", + "2": "query" + } + } + ] + } + ] ], "packet_update_block_properties": [ "container", @@ -7796,8 +8089,14 @@ "container", [ { - "name": "enchant_options", - "type": "EnchantOptions" + "name": "options", + "type": [ + "array", + { + "countType": "varint", + "type": "EnchantOption" + } + ] } ] ], diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 079f2d3..50574a8 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -51,13 +51,14 @@ packet_login: !bound: server # Protocol version (Big Endian!) protocol_version: i32 - # The combined size of the `chain` and `client_data` - payload_size: varint + tokens: '["encapsulated", { "lengthType": "varint", "type": "LoginTokens" }]' + +LoginTokens: # JSON array of JWT data: contains the display name, UUID and XUID # It should be signed by the Mojang public key - chain: LittleString + identity: LittleString # Skin related data - client_data: LittleString + client: LittleString packet_play_status: !id: 0x02 @@ -1156,7 +1157,6 @@ packet_player_input: jumping: bool sneaking: bool - # LevelChunk is sent by the server to provide the client with a chunk of a world data (16xYx16 blocks). # Typically a certain amount of chunks is sent to the client before sending it the spawn PlayStatus packet, # so that the client spawns in a loaded world. @@ -1558,10 +1558,55 @@ packet_command_request: interval: bool +# CommandBlockUpdate is sent by the client to update a command block at a specific position. The command +# block may be either a physical block or an entity. packet_command_block_update: !id: 0x4e !bound: server + # Block specifies if the command block updated was an actual physical block. If false, the command block + # is in a minecart and has an entity runtime ID instead. is_block: bool + # Position is the position of the command block updated. It is only set if Block is set to true. Nothing + # happens if no command block is set at this position. + _: is_block ? + if true: + # Position is the position of the command block updated. It is only set if Block is set to true. Nothing + # happens if no command block is set at this position. + position: BlockCoordinates + # Mode is the mode of the command block. It is either CommandBlockImpulse, CommandBlockChain or + # CommandBlockRepeat. It is only set if Block is set to true. + mode: varint => + 0: impulse + 1: repeat + 2: chain + # NeedsRedstone specifies if the command block needs to be powered by redstone to be activated. If false, + # the command block is always active. The field is only set if Block is set to true. + needs_redstone: bool + # Conditional specifies the behaviour of the command block if the command block before it (the opposite + # side of the direction the arrow if facing) fails to execute. If set to false, it will activate at all + # times, whereas if set to true, it will activate only if the previous command block executed + # successfully. The field is only set if Block is set to true. + conditional: bool + default: + minecart_entity_runtime_id: varint64 + # Command is the command currently entered in the command block. This is the command that is executed + # when the command block is activated. + command: string + # LastOutput is the output of the last command executed by the command block. It may be left empty to + # show simply no output at all, in combination with setting ShouldTrackOutput to false. + last_output: string + # Name is the name of the command block updated. If not empty, it will show this name hovering above the + # command block when hovering over the block with the cursor. + name: string + # ShouldTrackOutput specifies if the command block tracks output. If set to false, the output box won't + # be shown within the command block. + should_track_output: bool + # TickDelay is the delay in ticks between executions of a command block, if it is a repeating command + # block. + tick_delay: li32 + # ExecuteOnFirstTick specifies if the command block should execute on the first tick, AKA as soon as the + # command block is enabled. + execute_on_first_tick: bool packet_command_output: !id: 0x4f @@ -1659,29 +1704,69 @@ packet_update_equipment: # make sure only saddles can be put in the saddle slot etc. inventory: nbt + +# ResourcePackDataInfo is sent by the server to the client to inform the client about the data contained in +# one of the resource packs that are about to be sent. packet_resource_pack_data_info: !id: 0x52 !bound: client - package_id: string + # UUID is the unique ID of the resource pack that the info concerns. + pack_id: string + # DataChunkSize is the maximum size in bytes of the chunks in which the total size of the resource pack + # to be sent will be divided. A size of 1MB (1024*1024) means that a resource pack of 15.5MB will be + # split into 16 data chunks. max_chunk_size: lu32 + # ChunkCount is the total amount of data chunks that the sent resource pack will exist out of. It is the + # total size of the resource pack divided by the DataChunkSize field. + # The client doesn't actually seem to use this field. Rather, it divides the size by the chunk size to + # calculate it itself. chunk_count: lu32 - compressed_package_size: lu64 + # Size is the total size in bytes that the resource pack occupies. This is the size of the compressed + # archive (zip) of the resource pack. + size: lu64 + # Hash is a SHA256 hash of the content of the resource pack. hash: ByteArray + # Premium specifies if the resource pack was a premium resource pack, meaning it was bought from the + # Minecraft store. is_premium: bool - pack_type: u8 + # PackType is the type of the resource pack. It is one of the resource pack types listed. + pack_type: u8 => + 1: addon + 2: cached + 3: copy_protected + 4: behavior + 5: persona_piece + 6: resources + 7: skins + 8: world_template +# ResourcePackChunkData is sent to the client so that the client can download the resource pack. Each packet +# holds a chunk of the compressed resource pack, of which the size is defined in the ResourcePackDataInfo +# packet sent before. packet_resource_pack_chunk_data: !id: 0x53 !bound: client - package_id: string + # UUID is the unique ID of the resource pack that the chunk of data is taken out of. + pack_id: string + # ChunkIndex is the current chunk index of the chunk. It is a number that starts at 0 and is incremented + # for each resource pack data chunk sent to the client. chunk_index: lu32 + # DataOffset is the current progress in bytes or offset in the data that the resource pack data chunk is + # taken from. progress: lu64 + # RawPayload is a byte slice containing a chunk of data from the resource pack. It must be of the same size or + # less than the DataChunkSize set in the ResourcePackDataInfo packet. payload: ByteArray +# ResourcePackChunkRequest is sent by the client to request a chunk of data from a particular resource pack, +# that it has obtained information about in a ResourcePackDataInfo packet. packet_resource_pack_chunk_request: !id: 0x54 !bound: server - package_id: string + # UUID is the unique ID of the resource pack that the chunk of data is requested from. + pack_id: string + # ChunkIndex is the requested chunk index of the chunk. It is a number that starts at 0 and is + # incremented for each resource pack data chunk requested. chunk_index: lu32 packet_transfer: @@ -1739,19 +1824,66 @@ packet_add_behavior_tree: !bound: client behaviortree: string +# StructureBlockUpdate is sent by the client when it updates a structure block using the in-game UI. The +# data it contains depends on the type of structure block that it is. In Minecraft Bedrock Edition v1.11, +# there is only the Export structure block type, but in v1.13 the ones present in Java Edition will, +# according to the wiki, be added too. packet_structure_block_update: !id: 0x5a !bound: client + # Position is the position of the structure block that is updated. + position: BlockCoordinates + # StructureName is the name of the structure that was set in the structure block's UI. This is the name + # used to export the structure to a file. + structure_name: string + # DataField is the name of a function to run, usually used during natural generation. A description can + # be found here: https://minecraft.gamepedia.com/Structure_Block#Data. + data_field: string + # IncludePlayers specifies if the 'Include Players' toggle has been enabled, meaning players are also + # exported by the structure block. + include_players: bool + # ShowBoundingBox specifies if the structure block should have its bounds outlined. A thin line will + # encapsulate the bounds of the structure if set to true. + show_bounding_box: bool + # StructureBlockType is the type of the structure block updated. A list of structure block types that + # will be used can be found in the constants above. + structure_block_type: zigzag32 + # Settings is a struct of settings that should be used for exporting the structure. These settings are + # identical to the last sent in the StructureBlockUpdate packet by the client. + settings: StructureBlockSettings + # RedstoneSaveMode is the mode that should be used to save the structure when used with redstone. In + # Java Edition, this is always stored in memory, but in Bedrock Edition it can be stored either to disk + # or memory. See the constants above for the options. + redstone_save_mode: zigzag32 + # ShouldTrigger specifies if the structure block should be triggered immediately after this packet + # reaches the server. + should_trigger: bool +# ShowStoreOffer is sent by the server to show a Marketplace store offer to a player. It opens a window +# client-side that displays the item. +# The ShowStoreOffer packet only works on the partnered servers: Servers that are not partnered will not have +# a store buttons show up in the in-game pause menu and will, as a result, not be able to open store offers +# on the client side. Sending the packet does therefore not work when using a proxy that is not connected to +# with the domain of one of the partnered servers. packet_show_store_offer: !id: 0x5b !bound: client - unknown0: string - unknown1: bool + # OfferID is a string that identifies the offer for which a window should be opened. While typically a + # UUID, the ID could be anything. + offer_id: string + # ShowAll specifies if all other offers of the same 'author' as the one of the offer associated with the + # OfferID should also be displayed, alongside the target offer. + show_all: bool + +# PurchaseReceipt is sent by the client to the server to notify the server it purchased an item from the +# Marketplace store that was offered by the server. The packet is only used for partnered servers. packet_purchase_receipt: !id: 0x5c !bound: server + # Receipts is a list of receipts, or proofs of purchases, for the offers that have been purchased by the + # player. + receipts: string[]varint packet_player_skin: !id: 0x5d @@ -1762,20 +1894,40 @@ packet_player_skin: old_skin_name: string is_verified: bool +# SubClientLogin is sent when a sub-client joins the server while another client is already connected to it. +# The packet is sent as a result of split-screen game play, and allows up to four players to play using the +# same network connection. After an initial Login packet from the 'main' client, each sub-client that +# connects sends a SubClientLogin to request their own login. packet_sub_client_login: !id: 0x5e !bound: client + # ConnectionRequest is a string containing information about the player and JWTs that may be used to + # verify if the player is connected to XBOX Live. The connection request also contains the necessary + # client public key to initiate encryption. + # The ConnectionRequest in this packet is identical to the one found in the Login packet. + tokens: '["encapsulated", { "lengthType": "varint", "type": "LoginTokens" }]' +# AutomationClientConnect is used to make the client connect to a websocket server. This websocket server has +# the ability to execute commands on the behalf of the client and it can listen for certain events fired by +# the client. packet_initiate_web_socket_connection: !id: 0x5f !bound: client + # ServerURI is the URI to make the client connect to. It can be, for example, 'localhost:8000/ws' to + # connect to a websocket server on the localhost at port 8000. server: string + +# SetLastHurtBy is sent by the server to let the client know what entity type it was last hurt by. At this +# moment, the packet is useless and should not be used. There is no behaviour that depends on if this +# packet is sent or not. packet_set_last_hurt_by: !id: 0x60 !bound: client - unknown: varint + entity_type: varint +# BookEdit is sent by the client when it edits a book. It is sent each time a modification was made and the +# player stops its typing 'session', rather than simply after closing the book. packet_book_edit: !id: 0x61 !bound: client @@ -1790,6 +1942,7 @@ packet_book_edit: if replace_page or add_page: page_number: u8 text: string + # Only available on Education Edition. photo_name: string if delete_page: page_number: u8 @@ -1802,46 +1955,103 @@ packet_book_edit: xuid: string +# NPCRequest is sent by the client when it interacts with an NPC. +# The packet is specifically made for Education Edition, where NPCs are available to use. packet_npc_request: !id: 0x62 !bound: both + # EntityRuntimeID is the runtime ID of the NPC entity that the player interacted with. It is the same + # as sent by the server when spawning the entity. runtime_entity_id: varint64 - unknown0: u8 - unknown1: string - unknown2: u8 + # RequestType is the type of the request, which depends on the permission that the player has. It will + # be either a type that indicates that the NPC should show its dialog, or that it should open the + # editing window. + request_type: u8 => + 0: set_actions + 1: execute_action + 2: execute_closing_commands + 3: set_name + 4: set_skin + 5: set_interaction_text + # CommandString is the command string set in the NPC. It may consist of multiple commands, depending on + # what the player set in it. + command: string + # ActionType is the type of the action to execute. + action_type: u8 +# PhotoTransfer is sent by the server to transfer a photo (image) file to the client. It is typically used +# to transfer photos so that the client can display it in a portfolio in Education Edition. +# While previously usable in the default Bedrock Edition, the displaying of photos in books was disabled and +# the packet now has little use anymore. packet_photo_transfer: !id: 0x63 !bound: server - file_name: string + # PhotoName is the name of the photo to transfer. It is the exact file name that the client will download + # the photo as, including the extension of the file. + image_name: string + # PhotoData is the raw data of the photo image. The format of this data may vary: Formats such as JPEG or + # PNG work, as long as PhotoName has the correct extension. image_data: string - unknown2: string + # BookID is the ID of the book that the photo is associated with. If the PhotoName in a book with this ID + # is set to PhotoName, it will display the photo (provided Education Edition is used). + # The photo image is downloaded to a sub-folder with this book ID. + book_id: string +# ModalFormRequest is sent by the server to make the client open a form. This form may be either a modal form +# which has two options, a menu form for a selection of options and a custom form for properties. packet_modal_form_request: !id: 0x64 !bound: client + # FormID is an ID used to identify the form. The ID is saved by the client and sent back when the player + # submits the form, so that the server can identify which form was submitted. form_id: varint + # FormData is a JSON encoded object of form data. The content of the object differs, depending on the + # type of the form sent, which is also set in the JSON. data: string +# ModalFormResponse is sent by the client in response to a ModalFormRequest, after the player has submitted +# the form sent. It contains the options/properties selected by the player, or a JSON encoded 'null' if +# the form was closed by clicking the X at the top right corner of the form. packet_modal_form_response: !id: 0x65 !bound: server + # FormID is the form ID of the form the client has responded to. It is the same as the ID sent in the + # ModalFormRequest, and may be used to identify which form was submitted. form_id: varint + # ResponseData is a JSON encoded value representing the response of the player. If the form was + # cancelled, a JSON encoded 'null' is in the response. For a modal form, the response is either true or + # false, for a menu form, the response is an integer specifying the index of the button clicked, and for + # a custom form, the response is an array containing a value for each element. data: string +# ServerSettingsRequest is sent by the client to request the settings specific to the server. These settings +# are shown in a separate tab client-side, and have the same structure as a custom form. +# ServerSettingsRequest has no fields. packet_server_settings_request: !id: 0x66 !bound: server +# ServerSettingsResponse is optionally sent by the server in response to a ServerSettingsRequest from the +# client. It is structured the same as a ModalFormRequest packet, and if filled out correctly, will show +# a specific tab for the server in the settings of the client. A ModalFormResponse packet is sent by the +# client in response to a ServerSettingsResponse, when the client fills out the settings and closes the +# settings again. packet_server_settings_response: !id: 0x67 !bound: client + # FormID is an ID used to identify the form. The ID is saved by the client and sent back when the player + # submits the form, so that the server can identify which form was submitted. form_id: varint + # FormData is a JSON encoded object of form data. The content of the object differs, depending on the + # type of the form sent, which is also set in the JSON. data: string +# ShowProfile is sent by the server to show the XBOX Live profile of one player to another. packet_show_profile: !id: 0x68 !bound: client + # XUID is the XBOX Live User ID of the player whose profile should be shown to the player. If it is not + # a valid XUID, the client ignores the packet. xuid: string # SetDefaultGameType is sent by the client when it toggles the default game type in the settings UI, and is @@ -1854,18 +2064,33 @@ packet_set_default_game_type: # game type. gamemode: GameMode +# RemoveObjective is sent by the server to remove a scoreboard objective. It is used to stop showing a +# scoreboard to a player. packet_remove_objective: !id: 0x6a !bound: client + # ObjectiveName is the name of the objective that the scoreboard currently active has. This name must + # be identical to the one sent in the SetDisplayObjective packet. objective_name: string +# SetDisplayObjective is sent by the server to display an object as a scoreboard to the player. Once sent, +# it should be followed up by a SetScore packet to set the lines of the packet. packet_set_display_objective: !id: 0x6b !bound: client + # DisplaySlot is the slot in which the scoreboard should be displayed. Available options can be found in + # the constants above. display_slot: string + # ObjectiveName is the name of the objective that the scoreboard displays. Filling out a random unique + # value for this field works: It is not displayed in the scoreboard. objective_name: string + # DisplayName is the name, or title, that is displayed at the top of the scoreboard. display_name: string + # CriteriaName is the name of the criteria that need to be fulfilled in order for the score to be + # increased. This can be any kind of string and does not show up client-side. criteria_name: string + # SortOrder is the order in which entries on the scoreboard should be sorted. It is one of the constants + # that may be found above. sort_order: zigzag32 # SetScore is sent by the server to send the contents of a scoreboard to the player. It may be used to either @@ -1895,13 +2120,22 @@ packet_set_score: custom_name: entry_type ? if fake_player: string +# LabTable is sent by the client to let the server know it started a chemical reaction in Education Edition, +# and is sent by the server to other clients to show the effects. +# The packet is only functional if Education features are enabled. packet_lab_table: !id: 0x6d !bound: both - useless_byte: u8 - lab_table_x: varint - lab_table_y: varint - lab_table_z: varint + # ActionType is the type of the action that was executed. It is one of the constants above. Typically, + # only LabTableActionCombine is sent by the client, whereas LabTableActionReact is sent by the server. + action_type: u8 => + 0: combine + 1: react + # Position is the position at which the lab table used was located. + position: vec3u + # ReactionType is the type of the reaction that took place as a result of the items put into the lab + # table. The reaction type can be either that of an item or a particle, depending on whatever the result + # was of the reaction. reaction_type: u8 # UpdateBlockSynced is sent by the server to synchronise the falling of a falling block entity with the @@ -2028,25 +2262,50 @@ packet_network_stack_latency: # the other side should send a NetworkStackLatency packet back. needs_response: u8 +# ScriptCustomEvent is sent by both the client and the server. It is a way to let scripts communicate with +# the server, so that the client can let the server know it triggered an event, or the other way around. +# It is essentially an RPC kind of system. packet_script_custom_event: !id: 0x75 !bound: both + # EventName is the name of the event. The script and the server will use this event name to identify the + # data that is sent. event_name: string + # EventData is the data of the event. This data is typically a JSON encoded string, that the script is + # able to encode and decode too. event_data: string +# SpawnParticleEffect is sent by the server to spawn a particle effect client-side. Unlike other packets that +# result in the appearing of particles, this packet can show particles that are not hardcoded in the client. +# They can be added and changed through behaviour packs to implement custom particles. packet_spawn_particle_effect: !id: 0x76 !bound: client + # Dimension is the dimension that the particle is spawned in. Its exact usage is not clear, as the + # dimension has no direct effect on the particle. dimension: u8 + # EntityUniqueID is the unique ID of the entity that the spawned particle may be attached to. If this ID + # is not -1, the Position below will be interpreted as relative to the position of the entity associated + # with this unique ID. entity_id: zigzag64 + # Position is the position that the particle should be spawned at. If the position is too far away from + # the player, it will not show up. + # If EntityUniqueID is not -1, the position will be relative to the position of the entity. position: vec3f + # ParticleName is the name of the particle that should be shown. This name may point to a particle effect + # that is built-in, or to one implemented by behaviour packs. particle_name: string +# AvailableActorIdentifiers is sent by the server at the start of the game to let the client know all +# entities that are available on the server. packet_available_entity_identifiers: !id: 0x77 !bound: client + # SerialisedEntityIdentifiers is a network NBT serialised compound of all entity identifiers that are + # available in the server. nbt: nbt +# Not used. Use `packet_level_sound_event`. packet_level_sound_event_v2: !id: 0x78 !bound: both @@ -2057,15 +2316,32 @@ packet_level_sound_event_v2: is_baby_mob: bool is_global: bool +# NetworkChunkPublisherUpdate is sent by the server to change the point around which chunks are and remain +# loaded. This is useful for mini-game servers, where only one area is ever loaded, in which case the +# NetworkChunkPublisherUpdate packet can be sent in the middle of it, so that no chunks ever need to be +# additionally sent during the course of the game. +# In reality, the packet is not extraordinarily useful, and most servers just send it constantly at the +# position of the player. +# If the packet is not sent at all, no chunks will be shown to the player, regardless of where they are sent. packet_network_chunk_publisher_update: !id: 0x79 !bound: client + # Position is the block position around which chunks loaded will remain shown to the client. Most servers + # set this position to the position of the player itself. coordinates: BlockCoordinates + # Radius is the radius in blocks around Position that chunks sent show up in and will remain loaded in. + # Unlike the RequestChunkRadius and ChunkRadiusUpdated packets, this radius is in blocks rather than + # chunks, so the chunk radius needs to be multiplied by 16. (Or shifted to the left by 4.) radius: varint +# BiomeDefinitionList is sent by the server to let the client know all biomes that are available and +# implemented on the server side. It is much like the AvailableActorIdentifiers packet, but instead +# functions for biomes. packet_biome_definition_list: !id: 0x7a !bound: client + # SerialisedBiomeDefinitions is a network NBT serialised compound of all definitions of biomes that are + # available on the server. nbt: nbt # LevelSoundEvent is sent by the server to make any kind of built-in sound heard to a player. It is sent to, @@ -2075,11 +2351,24 @@ packet_biome_definition_list: packet_level_sound_event: !id: 0x7b !bound: both + # SoundType is the type of the sound to play. Some of the sound types + # require additional data, which is set in the EventData field. sound_id: SoundType + # Position is the position of the sound event. The player will be able to hear the direction of the sound + # based on what position is sent here. position: vec3f - block_id: zigzag32 + # ExtraData is a packed integer that some sound types use to provide extra data. An example of this is + # the note sound, which is composed of a pitch and an instrument type. + extra_data: zigzag32 + # EntityType is the string entity type of the entity that emitted the sound, for example + # 'minecraft:skeleton'. Some sound types use this entity type for additional data. entity_type: string + # BabyMob specifies if the sound should be that of a baby mob. It is most notably used for parrot + # imitations, which will change based on if this field is set to true or not. is_baby_mob: bool + # DisableRelativeVolume specifies if the sound should be played relatively or not. If set to true, the + # sound will have full volume, regardless of where the Position is, whereas if set to false, the sound's + # volume will be based on the distance to Position. is_global: bool # LevelEventGeneric is sent by the server to send a 'generic' level event to the client. This packet sends an @@ -2113,6 +2402,7 @@ packet_lectern_update: # DropBook specifies if the book currently set on display in the lectern should be dropped server-side. drop_book: bool +# This packet was removed. packet_video_stream_connect: !id: 0x7e !bound: client @@ -2143,27 +2433,73 @@ packet_remove_ecs_entity: # EntityNetworkID is the network ID of the entity that should be removed. network_id: varint64 +# ClientCacheStatus is sent by the client to the server at the start of the game. It is sent to let the +# server know if it supports the client-side blob cache. Clients such as Nintendo Switch do not support the +# cache, and attempting to use it anyway will fail. packet_client_cache_status: !id: 0x81 !bound: both + # Enabled specifies if the blob cache is enabled. If false, the server should not attempt to use the + # blob cache. If true, it may do so, but it may also choose not to use it. enabled: bool +# OnScreenTextureAnimation is sent by the server to show a certain animation on the screen of the player. +# The packet is used, as an example, for when a raid is triggered and when a raid is defeated. packet_on_screen_texture_animation: !id: 0x82 !bound: client + # AnimationType is the type of the animation to show. The packet provides no further extra data to allow + # modifying the duration or other properties of the animation. + animation_type: lu32 + +# MapCreateLockedCopy is sent by the server to create a locked copy of one map into another map. In vanilla, +# it is used in the cartography table to create a map that is locked and cannot be modified. packet_map_create_locked_copy: !id: 0x83 !bound: client + # OriginalMapID is the ID of the map that is being copied. The locked copy will obtain all content that + # is visible on this map, except the content will not change. + original_map_id: zigzag64 + # NewMapID is the ID of the map that holds the locked copy of the map that OriginalMapID points to. Its + # contents will be impossible to change. + new_map_id: zigzag64 + +# StructureTemplateDataRequest is sent by the client to request data of a structure. packet_structure_template_data_export_request: !id: 0x84 !bound: client + # StructureName is the name of the structure that was set in the structure block's UI. This is the name + # used to export the structure to a file. + name: string + # Position is the position of the structure block that has its template data requested. + position: BlockCoordinates + # Settings is a struct of settings that should be used for exporting the structure. These settings are + # identical to the last sent in the StructureBlockUpdate packet by the client. + settings: StructureBlockSettings + # RequestType specifies the type of template data request that the player sent. + request_type: u8 => + 1: export_from_save + 2: export_from_load + 3: query_saved_structure +# StructureTemplateDataResponse is sent by the server to send data of a structure to the client in response +# to a StructureTemplateDataRequest packet. packet_structure_template_data_export_response: !id: 0x85 !bound: client + name: string + success: bool + nbt: success ? + if true: nbt + # ResponseType specifies the response type of the packet. This depends on the RequestType field sent in + # the StructureTemplateDataRequest packet and is one of the constants above. + response_type: u8 => + 1: export + 2: query +# No longer used. packet_update_block_properties: !id: 0x86 !bound: client @@ -2401,17 +2737,31 @@ InputFlag: [ "bitflags", { ] }] +# CreativeContent is a packet sent by the server to set the creative inventory's content for a player. +# Introduced in 1.16, this packet replaces the previous method - sending an InventoryContent packet with +# creative inventory window ID. +# As of v1.16.100, this packet must be sent during the login sequence. Not sending it will stop the client +# from joining the server. packet_creative_content: !id: 0x91 !bound: client + # Items is a list of the items that should be added to the creative inventory. items: []varint entry_id: varint item: ItemLegacy +# PlayerEnchantOptions is sent by the server to update the enchantment options displayed when the user opens +# the enchantment table and puts an item in. This packet was added in 1.16 and allows the server to decide on +# the enchantments that can be selected by the player. +# The PlayerEnchantOptions packet should be sent once for every slot update of the enchantment table. The +# vanilla server sends an empty PlayerEnchantOptions packet when the player opens the enchantment table +# (air is present in the enchantment table slot) and sends the packet with actual enchantments in it when +# items are put in that can have enchantments. packet_player_enchant_options: !id: 0x92 !bound: client - enchant_options: EnchantOptions + # Options is a list of possible enchantment options for the item that was put into the enchantment table. + options: EnchantOption[]varint # ItemStackRequest is sent by the client to change item stacks in an inventory. It is essentially a # replacement of the InventoryTransaction packet added in 1.16 for inventory specific actions, such as moving @@ -2422,9 +2772,16 @@ packet_item_stack_request: !bound: server requests: ItemStackRequest[]varint +# ItemStackResponse is sent by the server in response to an ItemStackRequest packet from the client. This +# packet is used to either approve or reject ItemStackRequests from the client. If a request is approved, the +# client will simply continue as normal. If rejected, the client will undo the actions so that the inventory +# should be in sync with the server again. packet_item_stack_response: !id: 0x94 !bound: client + # Responses is a list of responses to ItemStackRequests sent by the client before. Responses either + # approve or reject a request from the client. + # Vanilla limits the size of this slice to 4096. responses: ItemStackResponses # PlayerArmourDamage is sent by the server to damage the armour of a player. It is a very efficient packet, diff --git a/data/latest/types.yaml b/data/latest/types.yaml index 74898ca..f047936 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -719,7 +719,7 @@ Enchant: id: u8 level: u8 -EnchantOptions: []varint +EnchantOption: cost: varint slot_flags: li32 equip_enchants: Enchant[]varint @@ -1019,6 +1019,42 @@ MapDecoration: # automatically, whereas others may be changed. color_abgr: varint + +StructureBlockSettings: + # PaletteName is the name of the palette used in the structure. Currently, it seems that this field is + # always 'default'. + palette_name: string + # IgnoreEntities specifies if the structure should ignore entities or include them. If set to false, + # entities will also show up in the exported structure. + ignore_entities: bool + # IgnoreBlocks specifies if the structure should ignore blocks or include them. If set to false, blocks + # will show up in the exported structure. + ignore_blocks: bool + # Size is the size of the area that is about to be exported. The area exported will start at the + # Position + Offset, and will extend as far as Size specifies. + size: BlockCoordinates + # Offset is the offset position that was set in the structure block. The area exported is offset by this + # position. + # **TODO**: This will be renamed to offset soon + structure_offset: BlockCoordinates + # LastEditingPlayerUniqueID is the unique ID of the player that last edited the structure block that + # these settings concern. + last_editing_player_unique_id: zigzag64 + # Rotation is the rotation that the structure block should obtain. See the constants above for available + # options. + rotation: u8 + # Mirror specifies the way the structure should be mirrored. It is either no mirror at all, mirror on the + # x/z axis or both. + mirror: u8 + # Integrity is usually 1, but may be set to a number between 0 and 1 to omit blocks randomly, using + # the Seed that follows. + integrity: lf32 + # Seed is the seed used to omit blocks if Integrity is not equal to one. If the Seed is 0, a random + # seed is selected to omit blocks. + seed: lu32 + # Pivot is the pivot around which the structure may be rotated. + pivot: vec3f + # List of Window IDs. When a new container is opened (container_open), a new sequential Window ID is created. # Below window IDs are hard-coded and created when the game starts and the server does not # send a `container_open` for them. diff --git a/src/client.js b/src/client.js index e675367..26d8662 100644 --- a/src/client.js +++ b/src/client.js @@ -108,15 +108,15 @@ class Client extends Connection { ] const encodedChain = JSON.stringify({ chain }) - const bodyLength = this.clientUserChain.length + encodedChain.length + 8 debug('Auth chain', chain) this.write('login', { protocol_version: this.options.protocolVersion, - payload_size: bodyLength, - chain: encodedChain, - client_data: this.clientUserChain + tokens: { + identity: encodedChain, + client: this.clientUserChain + } }) this.emit('loggingIn') } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 7335d6d..7e638fe 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -47,8 +47,9 @@ class Player extends Connection { } // Parse login data - const authChain = JSON.parse(body.params.chain) - const skinChain = body.params.client_data + const tokens = body.params.tokens + const authChain = JSON.parse(tokens.identity) + const skinChain = tokens.client try { var { key, userData, skinData } = this.decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line From 69b7c5c9f4a8417ef2064904f367f5314bc850f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jun 2021 04:40:39 +0000 Subject: [PATCH 194/458] Bump leveldb-zlib from 0.0.26 to 1.0.1 Bumps [leveldb-zlib](https://github.com/extremeheat/node-leveldb-zlib) from 0.0.26 to 1.0.1. - [Release notes](https://github.com/extremeheat/node-leveldb-zlib/releases) - [Changelog](https://github.com/extremeheat/node-leveldb-zlib/blob/master/HISTORY.md) - [Commits](https://github.com/extremeheat/node-leveldb-zlib/compare/v0.0.26...1.0.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eb8a935..0b24ec9 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "mocha": "^8.3.2", "protodef-yaml": "^1.1.0", "standard": "^16.0.3", - "leveldb-zlib": "^0.0.26", + "leveldb-zlib": "^1.0.1", "bedrock-protocol": "file:." }, "standard": { From 187e74b82320aa7a8f14ca583c91d930b4927d69 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 4 Jun 2021 19:51:22 -0400 Subject: [PATCH 195/458] use protodef-compiler-fix to fix npm install --- package.json | 2 +- src/transforms/framer.js | 2 +- src/transforms/serializer.js | 6 +++--- tools/compileProtocol.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index eb8a935..e4aae9b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", - "protodef": "github:extremeheat/node-protodef#vars", + "protodef-compiler-fix": "latest", "smart-buffer": "^4.1.0", "uuid-1345": "^1.0.2" }, diff --git a/src/transforms/framer.js b/src/transforms/framer.js index 77f41e9..aa1b496 100644 --- a/src/transforms/framer.js +++ b/src/transforms/framer.js @@ -1,4 +1,4 @@ -const [readVarInt, writeVarInt, sizeOfVarInt] = require('protodef').types.varint +const [readVarInt, writeVarInt, sizeOfVarInt] = require('protodef-compiler-fix').types.varint const zlib = require('zlib') // Concatenates packets into one batch packet, and adds length prefixs. diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 4a6102f..2900cf3 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,5 +1,5 @@ -const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler -const { FullPacketParser, Serializer } = require('protodef') +const { ProtoDefCompiler, CompiledProtodef } = require('protodef-compiler-fix').Compiler +const { FullPacketParser, Serializer } = require('protodef-compiler-fix') const { join } = require('path') class Parser extends FullPacketParser { @@ -43,7 +43,7 @@ function getProtocol (version) { compiler.addTypes(require(join(__dirname, '../datatypes/compiler-minecraft'))) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) - global.PartialReadError = require('protodef/src/utils').PartialReadError + global.PartialReadError = require('protodef-compiler-fix/src/utils').PartialReadError const compile = (compiler, file) => require(file)(compiler.native) return new CompiledProtodef( diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index bed7b2c..c89cb28 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -6,7 +6,7 @@ * */ const fs = require('fs') -const { ProtoDefCompiler } = require('protodef').Compiler +const { ProtoDefCompiler } = require('protodef-compiler-fix').Compiler const { Versions } = require('../src/options') const { join } = require('path') From 700ee08e11e387b88b852ab83f4c316f874f1a30 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 4 Jun 2021 19:52:09 -0400 Subject: [PATCH 196/458] correct type definitions --- index.d.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index e403471..e501aed 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,22 +7,22 @@ declare module "bedrock-protocol" { export interface Options { // The string version to start the client or server as - version: string + version?: string // For the client, the host of the server to connect to (default: 127.0.0.1) // For the server, the host to bind to (default: 0.0.0.0) host: string // The port to connect or bind to, default: 19132 - port: number + port?: number // For the client, if we should login with Microsoft/Xbox Live. // For the server, if we should verify client's authentication with Xbox Live. - offline: boolean + offline?: boolean } export interface ClientOptions extends Options { // The view distance in chunks - viewDistance: number, + viewDistance?: number, // Specifies which game edition to sign in as. Optional, but some servers verify this. - authTitle: title | string + authTitle?: title | string } export interface ServerOptions extends Options { From 9aba6b436dc72bd6802aab5513114a6d293b5e47 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 5 Jun 2021 06:40:55 -0400 Subject: [PATCH 197/458] Release 3.3.0 (#96) * Update package.json * Update HISTORY.md * Update package.json --- HISTORY.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index b731bf8..d731a86 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## 3.3.0 +* Protocol updates for 1.16, with some minor breaking changes to protocol fields [#95](https://github.com/PrismarineJS/bedrock-protocol/pull/95) +* Fix npm install issues + ## 3.2.1 * Add `authTitle` option to Relay proxy [#92](https://github.com/PrismarineJS/bedrock-protocol/pull/92) * Protocol, type definition fixes diff --git a/package.json b/package.json index 8d09d0f..ec3ffd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.2.1", + "version": "3.3.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From e16e8381e56641817909d561a7e920f50604da1e Mon Sep 17 00:00:00 2001 From: JammSpread <61063879+JammSpread@users.noreply.github.com> Date: Tue, 8 Jun 2021 22:57:55 -0400 Subject: [PATCH 198/458] fix: ping types. (#100) * fix: ping types. Sets the TypeScript definition file to include more accurate types for the ping function. Signed-off-by: JK * fix: changed usage. Reverts the usage to the previous method of entering in ping options. This makes it so that the host and port can once again be entered by their order alone. Signed-off-by: JK --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index e501aed..e1187ca 100644 --- a/index.d.ts +++ b/index.d.ts @@ -154,5 +154,5 @@ declare module "bedrock-protocol" { export function createClient(options: ClientOptions): Client export function createServer(options: ServerOptions): Server - export function ping({ host, port }) : ServerAdvertisement + export function ping({ host, port }: { host: string, port: number }): Promise } \ No newline at end of file From d02eb6c04160f528a74ec65a53ecb274db3731e6 Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Wed, 9 Jun 2021 13:40:45 -0400 Subject: [PATCH 199/458] update connect version based on ping response & fix typings (#101) * update connect ver based on ping resp& add typings * Fixed and added extremeheat suggestion * Update API.md * Update createClient.js --- docs/API.md | 4 +--- index.d.ts | 4 +++- src/createClient.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/API.md b/docs/API.md index 23de8f1..a38da60 100644 --- a/docs/API.md +++ b/docs/API.md @@ -10,7 +10,7 @@ Returns a `Client` instance and connects to the server. | ----------- | ----------- |-| | host | **Required** | host to connect to, for example `127.0.0.1`. | | port | *optional* | port to connect to, default to **19132** | -| version | *optional* | Version to connect as.
(Future feature, see [#69][1]) If not specified, should automatically match server version.
(Current feature) Defaults to latest version. | +| version | *optional* | Version to connect as. If not specified, automatically match server version. | | offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth. | | username | Conditional | Required if `offline` set to true : Username to connect to server as. | | authTitle | *optional* | The title ID to connect as, see the README for usage. | @@ -160,5 +160,3 @@ relay.on('connect', player => { ``` 'Relay' emits 'clientbound' and 'serverbound' events, along with the data for the outgoing packet that can be modified. You can send a packet to the client with `player.queue()` or to the backend server with `player.upstream.queue()`. - -[1]: https://github.com/PrismarineJS/bedrock-protocol/issues/69 diff --git a/index.d.ts b/index.d.ts index e1187ca..e47c35c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -22,7 +22,9 @@ declare module "bedrock-protocol" { // The view distance in chunks viewDistance?: number, // Specifies which game edition to sign in as. Optional, but some servers verify this. - authTitle?: title | string + authTitle?: title | string, + // whether to skip initial ping and immediately connect + skipPing?: boolean } export interface ServerOptions extends Options { diff --git a/src/createClient.js b/src/createClient.js index 50009be..f8e205a 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -4,7 +4,7 @@ const assert = require('assert') const advertisement = require('./server/advertisement') const { sleep } = require('./datatypes/util') -/** @param {{ version?: number, host: string, port?: number, connectTimeout?: number }} options */ +/** @param {{ version?: number, host: string, port?: number, connectTimeout?: number, skipPing?: boolean }} options */ function createClient (options) { assert(options) const client = new Client({ port: 19132, ...options }) @@ -15,7 +15,7 @@ function createClient (options) { client.ping().then(data => { const advert = advertisement.fromServerName(data) console.log(`Connecting to server ${advert.motd} (${advert.name}), version ${advert.version}`) - // TODO: update connect version based on ping response + client.version = options.version ?? advert.version connect(client) }, client) } From 5f0adfab76699c1b78e4b265f9eea3beb43ada08 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 9 Jun 2021 17:26:44 -0400 Subject: [PATCH 200/458] 1.17 support (#99) --- .gitignore | 4 +- README.md | 2 +- data/1.17.0/protocol.json | 8902 +++++++++++++++++++++++++++++++++++++ data/latest/proto.yml | 38 +- data/latest/types.yaml | 60 +- index.d.ts | 4 +- src/options.js | 3 +- test/internal.js | 3 +- tools/genPacketDumps.js | 2 +- types/Item.js | 6 +- 10 files changed, 8999 insertions(+), 25 deletions(-) create mode 100644 data/1.17.0/protocol.json diff --git a/.gitignore b/.gitignore index 8bdb3f2..e698980 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,6 @@ data/**/sample data/**/read.js data/**/write.js data/**/size.js -tools/bds* \ No newline at end of file +tools/bds* +tools/*/* +*.txt \ No newline at end of file diff --git a/README.md b/README.md index 124f1b2..1218f51 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This is a work in progress. You can track the progress in https://github.com/Pri ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md) diff --git a/data/1.17.0/protocol.json b/data/1.17.0/protocol.json new file mode 100644 index 0000000..941c0e5 --- /dev/null +++ b/data/1.17.0/protocol.json @@ -0,0 +1,8902 @@ +{ + "types": { + "varint32": "varint", + "bool": "native", + "zigzag32": "native", + "zigzag64": "native", + "uuid": "native", + "byterot": "native", + "MapInfo": "native", + "nbt": "native", + "BehaviourPackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + } + ] + ] + } + ], + "TexturePackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "rtx_enabled", + "type": "bool" + } + ] + ] + } + ], + "ResourcePackIdVersions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "ResourcePackIds": [ + "array", + { + "countType": "li16", + "type": "string" + } + ], + "Experiment": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "enabled", + "type": "bool" + } + ] + ], + "Experiments": [ + "array", + { + "countType": "li32", + "type": "Experiment" + } + ], + "GameMode": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "survival", + "1": "creative", + "2": "adventure", + "3": "survival_spectator", + "4": "creative_spectator", + "5": "fallback" + } + } + ], + "GameRule": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "editable", + "type": "bool" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "bool", + "2": "int", + "3": "float" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "bool": "bool", + "int": "zigzag32", + "float": "lf32" + }, + "default": "void" + } + ] + } + ] + ], + "GameRules": [ + "array", + { + "countType": "varint", + "type": "GameRule" + } + ], + "Blob": [ + "container", + [ + { + "name": "hash", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "BlockProperties": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "state", + "type": "nbt" + } + ] + ] + } + ], + "Itemstates": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "runtime_id", + "type": "li16" + }, + { + "name": "component_based", + "type": "bool" + } + ] + ] + } + ], + "ItemExtraDataWithBlockingTick": [ + "container", + [ + { + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "false", + "65535": "true" + } + } + ] + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "true": [ + "container", + [ + { + "name": "version", + "type": "u8" + }, + { + "name": "nbt", + "type": "lnbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "blocking_tick", + "type": "li64" + } + ] + ], + "ItemExtraDataWithoutBlockingTick": [ + "container", + [ + { + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "false", + "65535": "true" + } + } + ] + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "true": [ + "container", + [ + { + "name": "version", + "type": "u8" + }, + { + "name": "nbt", + "type": "lnbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + } + ] + ], + "ItemLegacy": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "count", + "type": "lu16" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "block_runtime_id", + "type": "zigzag32" + }, + { + "name": "extra", + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "/ShieldItemID": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithBlockingTick" + } + ] + }, + "default": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithoutBlockingTick" + } + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "Item": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "count", + "type": "lu16" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "has_stack_id", + "type": "u8" + }, + { + "name": "stack_id", + "type": [ + "switch", + { + "compareTo": "has_stack_id", + "fields": { + "0": "void" + }, + "default": "zigzag32" + } + ] + }, + { + "name": "block_runtime_id", + "type": "zigzag32" + }, + { + "name": "extra", + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "/ShieldItemID": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithBlockingTick" + } + ] + }, + "default": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithoutBlockingTick" + } + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "vec3i": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "vec3u": [ + "container", + [ + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + } + ] + ], + "vec3f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "vec2f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "MetadataDictionary": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "key", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "flags", + "1": "health", + "2": "variant", + "3": "color", + "4": "nametag", + "5": "owner_eid", + "6": "target_eid", + "7": "air", + "8": "potion_color", + "9": "potion_ambient", + "10": "jump_duration", + "11": "hurt_time", + "12": "hurt_direction", + "13": "paddle_time_left", + "14": "paddle_time_right", + "15": "experience_value", + "16": "minecart_display_block", + "17": "minecart_display_offset", + "18": "minecart_has_display", + "20": "old_swell", + "21": "swell_dir", + "22": "charge_amount", + "23": "enderman_held_runtime_id", + "24": "entity_age", + "26": "player_flags", + "27": "player_index", + "28": "player_bed_position", + "29": "fireball_power_x", + "30": "fireball_power_y", + "31": "fireball_power_z", + "32": "aux_power", + "33": "fish_x", + "34": "fish_z", + "35": "fish_angle", + "36": "potion_aux_value", + "37": "lead_holder_eid", + "38": "scale", + "39": "interactive_tag", + "40": "npc_skin_id", + "41": "url_tag", + "42": "max_airdata_max_air", + "43": "mark_variant", + "44": "container_type", + "45": "container_base_size", + "46": "container_extra_slots_per_strength", + "47": "block_target", + "48": "wither_invulnerable_ticks", + "49": "wither_target_1", + "50": "wither_target_2", + "51": "wither_target_3", + "52": "aerial_attack", + "53": "boundingbox_width", + "54": "boundingbox_height", + "55": "fuse_length", + "56": "rider_seat_position", + "57": "rider_rotation_locked", + "58": "rider_max_rotation", + "59": "rider_min_rotation", + "60": "rider_rotation_offset", + "61": "area_effect_cloud_radius", + "62": "area_effect_cloud_waiting", + "63": "area_effect_cloud_particle_id", + "64": "shulker_peek_id", + "65": "shulker_attach_face", + "66": "shulker_attached", + "67": "shulker_attach_pos", + "68": "trading_player_eid", + "69": "trading_career", + "70": "has_command_block", + "71": "command_block_command", + "72": "command_block_last_output", + "73": "command_block_track_output", + "74": "controlling_rider_seat_number", + "75": "strength", + "76": "max_strength", + "77": "spell_casting_color", + "78": "limited_life", + "79": "armor_stand_pose_index", + "80": "ender_crystal_time_offset", + "81": "always_show_nametag", + "82": "color_2", + "83": "name_author", + "84": "score_tag", + "85": "balloon_attached_entity", + "86": "pufferfish_size", + "87": "bubble_time", + "88": "agent", + "89": "sitting_amount", + "90": "sitting_amount_previous", + "91": "eating_counter", + "92": "flags_extended", + "93": "laying_amount", + "94": "laying_amount_previous", + "95": "duration", + "96": "spawn_time", + "97": "change_rate", + "98": "change_on_pickup", + "99": "pickup_count", + "100": "interact_text", + "101": "trade_tier", + "102": "max_trade_tier", + "103": "trade_experience", + "104": "skin_id", + "105": "spawning_frames", + "106": "command_block_tick_delay", + "107": "command_block_execute_on_first_tick", + "108": "ambient_sound_interval", + "109": "ambient_sound_interval_range", + "110": "ambient_sound_event_name", + "111": "fall_damage_multiplier", + "112": "name_raw_text", + "113": "can_ride_target", + "114": "low_tier_cured_discount", + "115": "high_tier_cured_discount", + "116": "nearby_cured_discount", + "117": "nearby_cured_discount_timestamp", + "118": "hitbox", + "119": "is_buoyant", + "120": "base_runtime_id", + "121": "freezing_effect_strength", + "122": "buoyancy_data", + "123": "goat_horn_count", + "124": "update_properties" + } + } + ] + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "byte", + "1": "short", + "2": "int", + "3": "float", + "4": "string", + "5": "compound", + "6": "vec3i", + "7": "long", + "8": "vec3f" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "key", + "fields": { + "flags": "MetadataFlags1", + "flags_extended": "MetadataFlags2" + }, + "default": [ + "switch", + { + "compareTo": "type", + "fields": { + "byte": "i8", + "short": "li16", + "int": "zigzag32", + "float": "lf32", + "string": "string", + "compound": "nbt", + "vec3i": "vec3i", + "long": "zigzag64", + "vec3f": "vec3f" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ], + "Link": [ + "container", + [ + { + "name": "ridden_entity_id", + "type": "zigzag64" + }, + { + "name": "rider_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "immediate", + "type": "bool" + }, + { + "name": "rider_initiated", + "type": "bool" + } + ] + ], + "Links": [ + "array", + { + "countType": "varint", + "type": "Link" + } + ], + "EntityAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "min", + "type": "lf32" + }, + { + "name": "value", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + } + ] + ] + } + ], + "Rotation": [ + "container", + [ + { + "name": "yaw", + "type": "byterot" + }, + { + "name": "pitch", + "type": "byterot" + }, + { + "name": "head_yaw", + "type": "byterot" + } + ] + ], + "BlockCoordinates": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "PlayerAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "min", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + }, + { + "name": "current", + "type": "lf32" + }, + { + "name": "default", + "type": "lf32" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "TransactionUseItem": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "click_block", + "1": "click_air", + "2": "break_block" + } + } + ] + }, + { + "name": "block_position", + "type": "vec3i" + }, + { + "name": "face", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "varint" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + }, + { + "name": "block_runtime_id", + "type": "varint" + } + ] + ], + "TransactionActions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "source_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "container", + "1": "global", + "2": "world_interaction", + "3": "creative", + "100": "craft_slot", + "99999": "craft" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "container": [ + "container", + [ + { + "name": "inventory_id", + "type": "WindowIDVarint" + } + ] + ], + "craft": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "world_interaction": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "craft_slot": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + } + ] + ] + } + ], + "TransactionLegacy": [ + "container", + [ + { + "name": "legacy_request_id", + "type": "zigzag32" + }, + { + "name": "legacy_transactions", + "type": [ + "switch", + { + "compareTo": "legacy_request_id", + "fields": { + "0": "void" + }, + "default": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "changed_slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_id", + "type": "u8" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + } + ] + ], + "Transaction": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "transaction_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "inventory_mismatch", + "2": "item_use", + "3": "item_use_on_entity", + "4": "item_release" + } + } + ] + }, + { + "name": "actions", + "type": "TransactionActions" + }, + { + "name": "transaction_data", + "type": [ + "switch", + { + "compareTo": "transaction_type", + "fields": { + "normal": "void", + "inventory_mismatch": "void", + "item_use": "TransactionUseItem", + "item_use_on_entity": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "interact", + "1": "attack" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + } + ] + ], + "item_release": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "release", + "1": "consume" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "head_pos", + "type": "vec3f" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "ItemStacks": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ], + "RecipeIngredient": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "network_data", + "type": "zigzag32" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ], + "PotionTypeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "input_item_meta", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "ingredient_meta", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + }, + { + "name": "output_item_meta", + "type": "zigzag32" + } + ] + ] + } + ], + "PotionContainerChangeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + } + ] + ] + } + ], + "Recipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "shapeless", + "1": "shaped", + "2": "furnace", + "3": "furnace_with_metadata", + "4": "multi", + "5": "shulker_box", + "6": "shapeless_chemistry", + "7": "shaped_chemistry" + } + } + ] + }, + { + "name": "recipe", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "shapeless": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shulker_box": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shapeless_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shaped": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shaped_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "furnace": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "output", + "type": "ItemLegacy" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "furnace_with_metadata": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "input_meta", + "type": "zigzag32" + }, + { + "name": "output", + "type": "ItemLegacy" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "multi": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ], + "SkinImage": [ + "container", + [ + { + "name": "width", + "type": "li32" + }, + { + "name": "height", + "type": "li32" + }, + { + "name": "data", + "type": "ByteArray" + } + ] + ], + "Skin": [ + "container", + [ + { + "name": "skin_id", + "type": "string" + }, + { + "name": "play_fab_id", + "type": "string" + }, + { + "name": "skin_resource_pack", + "type": "string" + }, + { + "name": "skin_data", + "type": "SkinImage" + }, + { + "name": "animations", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "skin_image", + "type": "SkinImage" + }, + { + "name": "animation_type", + "type": "li32" + }, + { + "name": "animation_frames", + "type": "lf32" + }, + { + "name": "expression_type", + "type": "lf32" + } + ] + ] + } + ] + }, + { + "name": "cape_data", + "type": "SkinImage" + }, + { + "name": "geometry_data", + "type": "string" + }, + { + "name": "animation_data", + "type": "string" + }, + { + "name": "premium", + "type": "bool" + }, + { + "name": "persona", + "type": "bool" + }, + { + "name": "cape_on_classic", + "type": "bool" + }, + { + "name": "cape_id", + "type": "string" + }, + { + "name": "full_skin_id", + "type": "string" + }, + { + "name": "arm_size", + "type": "string" + }, + { + "name": "skin_color", + "type": "string" + }, + { + "name": "personal_pieces", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_id", + "type": "string" + }, + { + "name": "piece_type", + "type": "string" + }, + { + "name": "pack_id", + "type": "string" + }, + { + "name": "is_default_piece", + "type": "bool" + }, + { + "name": "product_id", + "type": "string" + } + ] + ] + } + ] + }, + { + "name": "piece_tint_colors", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_type", + "type": "string" + }, + { + "name": "colors", + "type": [ + "array", + { + "countType": "li32", + "type": "string" + } + ] + } + ] + ] + } + ] + } + ] + ], + "PlayerRecords": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "remove" + } + } + ] + }, + { + "name": "records_count", + "type": "varint" + }, + { + "name": "records", + "type": [ + "array", + { + "count": "records_count", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "xbox_user_id", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "build_platform", + "type": "li32" + }, + { + "name": "skin_data", + "type": "Skin" + }, + { + "name": "is_teacher", + "type": "bool" + }, + { + "name": "is_host", + "type": "bool" + } + ] + ], + "remove": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + }, + { + "name": "verified", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "array", + { + "count": "records_count", + "type": "bool" + } + ] + }, + "default": "void" + } + ] + } + ] + ], + "Enchant": [ + "container", + [ + { + "name": "id", + "type": "u8" + }, + { + "name": "level", + "type": "u8" + } + ] + ], + "EnchantOption": [ + "container", + [ + { + "name": "cost", + "type": "varint" + }, + { + "name": "slot_flags", + "type": "li32" + }, + { + "name": "equip_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "held_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "self_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "name", + "type": "string" + }, + { + "name": "option_id", + "type": "zigzag32" + } + ] + ], + "Action": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "start_break", + "1": "abort_break", + "2": "stop_break", + "3": "get_updated_block", + "4": "drop_item", + "5": "start_sleeping", + "6": "stop_sleeping", + "7": "respawn", + "8": "jump", + "9": "start_sprint", + "10": "stop_sprint", + "11": "start_sneak", + "12": "stop_sneak", + "13": "creative_player_destroy_block", + "14": "dimension_change_ack", + "15": "start_glide", + "16": "stop_glide", + "17": "build_denied", + "18": "crack_break", + "19": "change_skin", + "20": "set_enchatnment_seed", + "21": "swimming", + "22": "stop_swimming", + "23": "start_spin_attack", + "24": "stop_spin_attack", + "25": "interact_block", + "26": "predict_break", + "27": "continue_break" + } + } + ], + "StackRequestSlotInfo": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "stack_id", + "type": "zigzag32" + } + ] + ], + "ItemStackRequest": [ + "container", + [ + { + "name": "request_id", + "type": "varint" + }, + { + "name": "actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "take", + "1": "place", + "2": "swap", + "3": "drop", + "4": "destroy", + "5": "consume", + "6": "create", + "7": "lab_table_combine", + "8": "beacon_payment", + "9": "mine_block", + "10": "craft_recipe", + "11": "craft_recipe_auto", + "12": "craft_creative", + "13": "optional", + "14": "non_implemented", + "15": "results_deprecated" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type_id", + "fields": { + "take": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "place": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "swap": [ + "container", + [ + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "drop": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "randomly", + "type": "bool" + } + ] + ], + "destroy": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "consume": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "create": [ + "container", + [ + { + "name": "result_slot_id", + "type": "u8" + } + ] + ], + "beacon_payment": [ + "container", + [ + { + "name": "primary_effect", + "type": "zigzag32" + }, + { + "name": "secondary_effect", + "type": "zigzag32" + } + ] + ], + "mine_block": [ + "container", + [ + { + "name": "unknown1", + "type": "zigzag32" + }, + { + "name": "predicted_durability", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "craft_recipe": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_recipe_auto": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_creative": [ + "container", + [ + { + "name": "item_id", + "type": "varint32" + } + ] + ], + "optional": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + }, + { + "name": "filtered_string_index", + "type": "li32" + } + ] + ], + "non_implemented": "void", + "results_deprecated": [ + "container", + [ + { + "name": "result_items", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "times_crafted", + "type": "u8" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + { + "name": "custom_names", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "ItemStackResponses": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "ok", + "1": "error" + } + } + ] + }, + { + "name": "request_id", + "type": "varint32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "status", + "fields": { + "ok": [ + "container", + [ + { + "name": "containers", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot", + "type": "u8" + }, + { + "name": "hotbar_slot", + "type": "u8" + }, + { + "name": "count", + "type": "u8" + }, + { + "name": "item_stack_id", + "type": "varint32" + }, + { + "name": "custom_name", + "type": "string" + }, + { + "name": "durability_correction", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ], + "ItemComponentList": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + } + ], + "CommandOrigin": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "player", + "1": "block", + "2": "minecart_block", + "3": "dev_console", + "4": "test", + "5": "automation_player", + "6": "client_automation", + "7": "dedicated_server", + "8": "entity", + "9": "virtual", + "10": "game_argument", + "11": "entity_server", + "12": "precompiled", + "13": "game_director_entity_server", + "14": "script" + } + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "request_id", + "type": "string" + }, + { + "name": "player_entity_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "dev_console": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ], + "test": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "TrackedObject": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "entity", + "1": "block" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "block_position", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "block": "BlockCoordinates" + }, + "default": "void" + } + ] + } + ] + ], + "MapDecoration": [ + "container", + [ + { + "name": "type", + "type": "u8" + }, + { + "name": "rotation", + "type": "u8" + }, + { + "name": "x", + "type": "u8" + }, + { + "name": "y", + "type": "u8" + }, + { + "name": "label", + "type": "string" + }, + { + "name": "color_abgr", + "type": "varint" + } + ] + ], + "StructureBlockSettings": [ + "container", + [ + { + "name": "palette_name", + "type": "string" + }, + { + "name": "ignore_entities", + "type": "bool" + }, + { + "name": "ignore_blocks", + "type": "bool" + }, + { + "name": "size", + "type": "BlockCoordinates" + }, + { + "name": "structure_offset", + "type": "BlockCoordinates" + }, + { + "name": "last_editing_player_unique_id", + "type": "zigzag64" + }, + { + "name": "rotation", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "90_deg", + "2": "180_deg", + "3": "270_deg" + } + } + ] + }, + { + "name": "mirror", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "x_axis", + "2": "z_axis", + "3": "both_axes" + } + } + ] + }, + { + "name": "animation_mode", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "layers", + "2": "blocks" + } + } + ] + }, + { + "name": "animation_duration", + "type": "lf32" + }, + { + "name": "integrity", + "type": "lf32" + }, + { + "name": "seed", + "type": "lu32" + }, + { + "name": "pivot", + "type": "vec3f" + } + ] + ], + "WindowID": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], + "WindowIDVarint": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], + "WindowType": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "container", + "1": "workbench", + "2": "furnace", + "3": "enchantment", + "4": "brewing_stand", + "5": "anvil", + "6": "dispenser", + "7": "dropper", + "8": "hopper", + "9": "cauldron", + "10": "minecart_chest", + "11": "minecart_hopper", + "12": "horse", + "13": "beacon", + "14": "structure_editor", + "15": "trading", + "16": "command_block", + "17": "jukebox", + "18": "armor", + "19": "hand", + "20": "compound_creator", + "21": "element_constructor", + "22": "material_reducer", + "23": "lab_table", + "24": "loom", + "25": "lectern", + "26": "grindstone", + "27": "blast_furnace", + "28": "smoker", + "29": "stonecutter", + "30": "cartography", + "31": "hud", + "32": "jigsaw_editor", + "33": "smithing_table", + "-9": "none", + "-1": "inventory" + } + } + ], + "ContainerSlotType": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "anvil_input", + "1": "anvil_material", + "2": "anvil_result", + "3": "smithing_table_input", + "4": "smithing_table_material", + "5": "smithing_table_result", + "6": "armor", + "7": "container", + "8": "beacon_payment", + "9": "brewing_input", + "10": "brewing_result", + "11": "brewing_fuel", + "12": "hotbar_and_inventory", + "13": "crafting_input", + "14": "crafting_output", + "15": "recipe_construction", + "16": "recipe_nature", + "17": "recipe_items", + "18": "recipe_search", + "19": "recipe_search_bar", + "20": "recipe_equipment", + "21": "enchanting_input", + "22": "enchanting_lapis", + "23": "furnace_fuel", + "24": "furnace_ingredient", + "25": "furnace_output", + "26": "horse_equip", + "27": "hotbar", + "28": "inventory", + "29": "shulker", + "30": "trade_ingredient1", + "31": "trade_ingredient2", + "32": "trade_result", + "33": "offhand", + "34": "compcreate_input", + "35": "compcreate_output", + "36": "elemconstruct_output", + "37": "matreduce_input", + "38": "matreduce_output", + "39": "labtable_input", + "40": "loom_input", + "41": "loom_dye", + "42": "loom_material", + "43": "loom_result", + "44": "blast_furnace_ingredient", + "45": "smoker_ingredient", + "46": "trade2_ingredient1", + "47": "trade2_ingredient2", + "48": "trade2_result", + "49": "grindstone_input", + "50": "grindstone_additional", + "51": "grindstone_result", + "52": "stonecutter_input", + "53": "stonecutter_result", + "54": "cartography_input", + "55": "cartography_additional", + "56": "cartography_result", + "57": "barrel", + "58": "cursor", + "59": "creative_output" + } + } + ], + "SoundType": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "ItemUseOn", + "1": "Hit", + "2": "Step", + "3": "Fly", + "4": "Jump", + "5": "Break", + "6": "Place", + "7": "HeavyStep", + "8": "Gallop", + "9": "Fall", + "10": "Ambient", + "11": "AmbientBaby", + "12": "AmbientInWater", + "13": "Breathe", + "14": "Death", + "15": "DeathInWater", + "16": "DeathToZombie", + "17": "Hurt", + "18": "HurtInWater", + "19": "Mad", + "20": "Boost", + "21": "Bow", + "22": "SquishBig", + "23": "SquishSmall", + "24": "FallBig", + "25": "FallSmall", + "26": "Splash", + "27": "Fizz", + "28": "Flap", + "29": "Swim", + "30": "Drink", + "31": "Eat", + "32": "Takeoff", + "33": "Shake", + "34": "Plop", + "35": "Land", + "36": "Saddle", + "37": "Armor", + "38": "MobArmorStandPlace", + "39": "AddChest", + "40": "Throw", + "41": "Attack", + "42": "AttackNoDamage", + "43": "AttackStrong", + "44": "Warn", + "45": "Shear", + "46": "Milk", + "47": "Thunder", + "48": "Explode", + "49": "Fire", + "50": "Ignite", + "51": "Fuse", + "52": "Stare", + "53": "Spawn", + "54": "Shoot", + "55": "BreakBlock", + "56": "Launch", + "57": "Blast", + "58": "LargeBlast", + "59": "Twinkle", + "60": "Remedy", + "61": "Infect", + "62": "LevelUp", + "63": "BowHit", + "64": "BulletHit", + "65": "ExtinguishFire", + "66": "ItemFizz", + "67": "ChestOpen", + "68": "ChestClosed", + "69": "ShulkerBoxOpen", + "70": "ShulkerBoxClosed", + "71": "EnderChestOpen", + "72": "EnderChestClosed", + "73": "PowerOn", + "74": "PowerOff", + "75": "Attach", + "76": "Detach", + "77": "Deny", + "78": "Tripod", + "79": "Pop", + "80": "DropSlot", + "81": "Note", + "82": "Thorns", + "83": "PistonIn", + "84": "PistonOut", + "85": "Portal", + "86": "Water", + "87": "LavaPop", + "88": "Lava", + "89": "Burp", + "90": "BucketFillWater", + "91": "BucketFillLava", + "92": "BucketEmptyWater", + "93": "BucketEmptyLava", + "94": "ArmorEquipChain", + "95": "ArmorEquipDiamond", + "96": "ArmorEquipGeneric", + "97": "ArmorEquipGold", + "98": "ArmorEquipIron", + "99": "ArmorEquipLeather", + "100": "ArmorEquipElytra", + "101": "Record13", + "102": "RecordCat", + "103": "RecordBlocks", + "104": "RecordChirp", + "105": "RecordFar", + "106": "RecordMall", + "107": "RecordMellohi", + "108": "RecordStal", + "109": "RecordStrad", + "110": "RecordWard", + "111": "Record11", + "112": "RecordWait", + "113": "unknown1", + "114": "Flop", + "115": "ElderGuardianCurse", + "116": "MobWarning", + "117": "MobWarningBaby", + "118": "Teleport", + "119": "ShulkerOpen", + "120": "ShulkerClose", + "121": "Haggle", + "122": "HaggleYes", + "123": "HaggleNo", + "124": "HaggleIdle", + "125": "ChorusGrow", + "126": "ChorusDeath", + "127": "Glass", + "128": "PotionBrewed", + "129": "CastSpell", + "130": "PrepareAttack", + "131": "PrepareSummon", + "132": "PrepareWololo", + "133": "Fang", + "134": "Charge", + "135": "CameraTakePicture", + "136": "LeashKnotPlace", + "137": "LeashKnotBreak", + "138": "Growl", + "139": "Whine", + "140": "Pant", + "141": "Purr", + "142": "Purreow", + "143": "DeathMinVolume", + "144": "DeathMidVolume", + "145": "unknown2", + "146": "ImitateCaveSpider", + "147": "ImitateCreeper", + "148": "ImitateElderGuardian", + "149": "ImitateEnderDragon", + "150": "ImitateEnderman", + "151": "unknown3", + "152": "ImitateEvocationIllager", + "153": "ImitateGhast", + "154": "ImitateHusk", + "155": "ImitateIllusionIllager", + "156": "ImitateMagmaCube", + "157": "ImitatePolarBear", + "158": "ImitateShulker", + "159": "ImitateSilverfish", + "160": "ImitateSkeleton", + "161": "ImitateSlime", + "162": "ImitateSpider", + "163": "ImitateStray", + "164": "ImitateVex", + "165": "ImitateVindicationIllager", + "166": "ImitateWitch", + "167": "ImitateWither", + "168": "ImitateWitherSkeleton", + "169": "ImitateWolf", + "170": "ImitateZombie", + "171": "ImitateZombiePigman", + "172": "ImitateZombieVillager", + "173": "BlockEndPortalFrameFill", + "174": "BlockEndPortalSpawn", + "175": "RandomAnvilUse", + "176": "BottleDragonBreath", + "177": "PortalTravel", + "178": "ItemTridentHit", + "179": "ItemTridentReturn", + "180": "ItemTridentRiptide1", + "181": "ItemTridentRiptide2", + "182": "ItemTridentRiptide3", + "183": "ItemTridentThrow", + "184": "ItemTridentThunder", + "185": "ItemTridentHitGround", + "186": "Default", + "187": "BlockFletchingTableUse", + "188": "ElemConstructOpen", + "189": "IceBombHit", + "190": "BalloonPop", + "191": "LtReactionIceBomb", + "192": "LtReactionBleach", + "193": "LtReactionEPaste", + "194": "LtReactionEPaste2", + "195": "LtReactionFertilizer", + "196": "LtReactionFireball", + "197": "LtReactionMgsalt", + "198": "LtReactionMiscfire", + "199": "LtReactionFire", + "200": "LtReactionMiscexplosion", + "201": "LtReactionMiscmystical", + "202": "LtReactionMiscmystical2", + "203": "LtReactionProduct", + "204": "SparklerUse", + "205": "GlowstickUse", + "206": "SparklerActive", + "207": "ConvertToDrowned", + "208": "BucketFillFish", + "209": "BucketEmptyFish", + "210": "BubbleUp", + "211": "BubbleDown", + "212": "BubblePop", + "213": "BubbleUpInside", + "214": "BubbleDownInside", + "215": "HurtBaby", + "216": "DeathBaby", + "217": "StepBaby", + "218": "BabySpawn", + "219": "Born", + "220": "BlockTurtleEggBreak", + "221": "BlockTurtleEggCrack", + "222": "BlockTurtleEggHatch", + "223": "TurtleLayEgg", + "224": "BlockTurtleEggAttack", + "225": "BeaconActivate", + "226": "BeaconAmbient", + "227": "BeaconDeactivate", + "228": "BeaconPower", + "229": "ConduitActivate", + "230": "ConduitAmbient", + "231": "ConduitAttack", + "232": "ConduitDeactivate", + "233": "ConduitShort", + "234": "Swoop", + "235": "BlockBambooSaplingPlace", + "236": "PreSneeze", + "237": "Sneeze", + "238": "AmbientTame", + "239": "Scared", + "240": "BlockScaffoldingClimb", + "241": "CrossbowLoadingStart", + "242": "CrossbowLoadingMiddle", + "243": "CrossbowLoadingEnd", + "244": "CrossbowShoot", + "245": "CrossbowQuickChargeStart", + "246": "CrossbowQuickChargeMiddle", + "247": "CrossbowQuickChargeEnd", + "248": "AmbientAggressive", + "249": "AmbientWorried", + "250": "CantBreed", + "251": "ItemShieldBlock", + "252": "ItemBookPut", + "253": "BlockGrindstoneUse", + "254": "BlockBellHit", + "255": "BlockCampfireCrackle", + "256": "Roar", + "257": "Stun", + "258": "BlockSweetBerryBushHurt", + "259": "BlockSweetBerryBushPick", + "260": "UICartographyTableTakeResult", + "261": "UIStoneCutterTakeResult", + "262": "BlockComposterEmpty", + "263": "BlockComposterFill", + "264": "BlockComposterFillSuccess", + "265": "BlockComposterReady", + "266": "BlockBarrelOpen", + "267": "BlockBarrelClose", + "268": "RaidHorn", + "269": "BlockLoomUse", + "270": "AmbientRaid", + "271": "UICartographyTableUse", + "272": "UIStoneCutterUse", + "273": "UILoomUse", + "274": "SmokerUse", + "275": "BlastFurnaceUse", + "276": "SmithingTableUse", + "277": "Screech", + "278": "Sleep", + "279": "FurnaceUse", + "280": "MooshroomConvert", + "281": "MilkSuspiciously", + "282": "Celebrate", + "283": "JumpPrevent", + "284": "AmbientPollinate", + "285": "BeeHiveDrip", + "286": "BeeHiveEnter", + "287": "BeeHiveExit", + "288": "BeeHiveWork", + "289": "BeeHiveShear", + "290": "HoneyBottleDrink", + "291": "AmbientCave", + "292": "Retreat", + "293": "ConvertToZombified", + "294": "Admire", + "295": "StepLava", + "296": "Tempt", + "297": "Panic", + "298": "Angry", + "299": "AmbientWarpedForest", + "300": "AmbientSoulsandValley", + "301": "AmbientNetherWastes", + "302": "AmbientBasaltDeltas", + "303": "AmbientCrimsonForest", + "304": "RespawnAnchorCharge", + "305": "RespawnAnchorDeplete", + "306": "RespawnAnchorSetSpawn", + "307": "RespawnAnchorAmbient", + "308": "SoulEscapeQuiet", + "309": "SoulEscapeLoud", + "310": "RecordPigstep", + "311": "LinkCompassToLodestone", + "312": "BlockSmithingTableUse", + "313": "EquipNetherite", + "314": "AmbientLoopWarpedForest", + "315": "AmbientLoopSoulsandValley", + "316": "AmbientLoopNetherWastes", + "317": "AmbientLoopBasaltDeltas", + "318": "AmbientLoopCrimsonForest", + "319": "AmbientAdditionWarpedForest", + "320": "AmbientAdditionSoulsandValley", + "321": "AmbientAdditionNetherWastes", + "322": "AmbientAdditionBasaltDeltas", + "323": "AmbientAdditionCrimsonForest", + "324": "SculkSensorPowerOn", + "325": "SculkSensorPowerOff", + "326": "BucketFillPowderSnow", + "327": "BucketEmptyPowderSnow", + "328": "PointedDripstoneCauldronDripWater", + "329": "PointedDripstoneCauldronDripLava", + "330": "PointedDripstoneDripWater", + "331": "PointedDripstoneDripLava", + "332": "CaveVinesPickBerries", + "333": "BigDripleafTiltDown", + "334": "BigDripleafTiltUp", + "335": "unknown335", + "336": "unknown336", + "337": "unknown337", + "338": "unknown338", + "339": "copper_wax_on", + "340": "copper_wax_off", + "341": "scrape", + "342": "player_hurt_drown", + "343": "player_hurt_on_fire", + "344": "player_hurt_freeze", + "345": "use_spyglass", + "346": "stop_using_spyglass", + "347": "amethyst_block_chime", + "348": "ambient_screamer", + "349": "hurt_screamer", + "350": "death_screamer", + "351": "milk_screamer", + "352": "jump_to_block", + "353": "pre_ram", + "354": "pre_ram_screamer", + "355": "ram_impact", + "356": "ram_impact_screamer", + "357": "squid_ink_squirt", + "358": "glow_squid_ink_squirt", + "359": "convert_to_stray", + "360": "Undefined" + } + } + ], + "LegacyEntityType": [ + "mapper", + { + "type": "li32", + "mappings": { + "10": "chicken", + "11": "cow", + "12": "pig", + "13": "sheep", + "14": "wolf", + "15": "villager", + "16": "mooshroom", + "17": "squid", + "18": "rabbit", + "19": "bat", + "20": "iron_golem", + "21": "snow_golem", + "22": "ocelot", + "23": "horse", + "24": "donkey", + "25": "mule", + "26": "skeleton_horse", + "27": "zombie_horse", + "28": "polar_bear", + "29": "llama", + "30": "parrot", + "31": "dolphin", + "32": "zombie", + "33": "creeper", + "34": "skeleton", + "35": "spider", + "36": "zombie_pigman", + "37": "slime", + "38": "enderman", + "39": "silverfish", + "40": "cave_spider", + "41": "ghast", + "42": "magma_cube", + "43": "blaze", + "44": "zombie_villager", + "45": "witch", + "46": "stray", + "47": "husk", + "48": "wither_skeleton", + "49": "guardian", + "50": "elder_guardian", + "51": "npc", + "52": "wither", + "53": "ender_dragon", + "54": "shulker", + "55": "endermite", + "56": "agent", + "57": "vindicator", + "58": "phantom", + "61": "armor_stand", + "62": "tripod_camera", + "63": "player", + "64": "item", + "65": "tnt", + "66": "falling_block", + "67": "moving_block", + "68": "xp_bottle", + "69": "xp_orb", + "70": "eye_of_ender_signal", + "71": "ender_crystal", + "72": "fireworks_rocket", + "73": "thrown_trident", + "74": "turtle", + "75": "cat", + "76": "shulker_bullet", + "77": "fishing_hook", + "78": "chalkboard", + "79": "dragon_fireball", + "80": "arrow", + "81": "snowball", + "82": "egg", + "83": "painting", + "84": "minecart", + "85": "fireball", + "86": "splash_potion", + "87": "ender_pearl", + "88": "leash_knot", + "89": "wither_skull", + "90": "boat", + "91": "wither_skull_dangerous", + "93": "lightning_bolt", + "94": "small_fireball", + "95": "area_effect_cloud", + "96": "hopper_minecart", + "97": "tnt_minecart", + "98": "chest_minecart", + "100": "command_block_minecart", + "101": "lingering_potion", + "102": "llama_spit", + "103": "evocation_fang", + "104": "evocation_illager", + "105": "vex", + "106": "ice_bomb", + "107": "balloon", + "108": "pufferfish", + "109": "salmon", + "110": "drowned", + "111": "tropicalfish", + "112": "cod", + "113": "panda" + } + } + ], + "mcpe_packet": [ + "container", + [ + { + "name": "name", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "login", + "2": "play_status", + "3": "server_to_client_handshake", + "4": "client_to_server_handshake", + "5": "disconnect", + "6": "resource_packs_info", + "7": "resource_pack_stack", + "8": "resource_pack_client_response", + "9": "text", + "10": "set_time", + "11": "start_game", + "12": "add_player", + "13": "add_entity", + "14": "remove_entity", + "15": "add_item_entity", + "17": "take_item_entity", + "18": "move_entity", + "19": "move_player", + "20": "rider_jump", + "21": "update_block", + "22": "add_painting", + "23": "tick_sync", + "24": "level_sound_event_old", + "25": "level_event", + "26": "block_event", + "27": "entity_event", + "28": "mob_effect", + "29": "update_attributes", + "30": "inventory_transaction", + "31": "mob_equipment", + "32": "mob_armor_equipment", + "33": "interact", + "34": "block_pick_request", + "35": "entity_pick_request", + "36": "player_action", + "38": "hurt_armor", + "39": "set_entity_data", + "40": "set_entity_motion", + "41": "set_entity_link", + "42": "set_health", + "43": "set_spawn_position", + "44": "animate", + "45": "respawn", + "46": "container_open", + "47": "container_close", + "48": "player_hotbar", + "49": "inventory_content", + "50": "inventory_slot", + "51": "container_set_data", + "52": "crafting_data", + "53": "crafting_event", + "54": "gui_data_pick_item", + "55": "adventure_settings", + "56": "block_entity_data", + "57": "player_input", + "58": "level_chunk", + "59": "set_commands_enabled", + "60": "set_difficulty", + "61": "change_dimension", + "62": "set_player_game_type", + "63": "player_list", + "64": "simple_event", + "65": "event", + "66": "spawn_experience_orb", + "67": "clientbound_map_item_data", + "68": "map_info_request", + "69": "request_chunk_radius", + "70": "chunk_radius_update", + "71": "item_frame_drop_item", + "72": "game_rules_changed", + "73": "camera", + "74": "boss_event", + "75": "show_credits", + "76": "available_commands", + "77": "command_request", + "78": "command_block_update", + "79": "command_output", + "80": "update_trade", + "81": "update_equipment", + "82": "resource_pack_data_info", + "83": "resource_pack_chunk_data", + "84": "resource_pack_chunk_request", + "85": "transfer", + "86": "play_sound", + "87": "stop_sound", + "88": "set_title", + "89": "add_behavior_tree", + "90": "structure_block_update", + "91": "show_store_offer", + "92": "purchase_receipt", + "93": "player_skin", + "94": "sub_client_login", + "95": "initiate_web_socket_connection", + "96": "set_last_hurt_by", + "97": "book_edit", + "98": "npc_request", + "99": "photo_transfer", + "100": "modal_form_request", + "101": "modal_form_response", + "102": "server_settings_request", + "103": "server_settings_response", + "104": "show_profile", + "105": "set_default_game_type", + "106": "remove_objective", + "107": "set_display_objective", + "108": "set_score", + "109": "lab_table", + "110": "update_block_synced", + "111": "move_entity_delta", + "112": "set_scoreboard_identity", + "113": "set_local_player_as_initialized", + "114": "update_soft_enum", + "115": "network_stack_latency", + "117": "script_custom_event", + "118": "spawn_particle_effect", + "119": "available_entity_identifiers", + "120": "level_sound_event_v2", + "121": "network_chunk_publisher_update", + "122": "biome_definition_list", + "123": "level_sound_event", + "124": "level_event_generic", + "125": "lectern_update", + "126": "video_stream_connect", + "127": "add_ecs_entity", + "128": "remove_ecs_entity", + "129": "client_cache_status", + "130": "on_screen_texture_animation", + "131": "map_create_locked_copy", + "132": "structure_template_data_export_request", + "133": "structure_template_data_export_response", + "134": "update_block_properties", + "135": "client_cache_blob_status", + "136": "client_cache_miss_response", + "137": "education_settings", + "139": "multiplayer_settings", + "140": "settings_command", + "141": "anvil_damage", + "142": "completed_using_item", + "143": "network_settings", + "144": "player_auth_input", + "145": "creative_content", + "146": "player_enchant_options", + "147": "item_stack_request", + "148": "item_stack_response", + "149": "player_armor_damage", + "151": "update_player_game_type", + "153": "position_tracking_db_broadcast", + "154": "position_tracking_db_request", + "156": "packet_violation_warning", + "157": "motion_prediction_hints", + "158": "animate_entity", + "159": "camera_shake", + "160": "player_fog", + "161": "correct_player_move_prediction", + "162": "item_component", + "163": "filter_text_packet", + "164": "debug_renderer", + "165": "sync_entity_property", + "166": "add_volume_entity", + "167": "remove_volume_entity" + } + } + ] + }, + { + "name": "params", + "type": [ + "switch", + { + "compareTo": "name", + "fields": { + "login": "packet_login", + "play_status": "packet_play_status", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", + "disconnect": "packet_disconnect", + "resource_packs_info": "packet_resource_packs_info", + "resource_pack_stack": "packet_resource_pack_stack", + "resource_pack_client_response": "packet_resource_pack_client_response", + "text": "packet_text", + "set_time": "packet_set_time", + "start_game": "packet_start_game", + "add_player": "packet_add_player", + "add_entity": "packet_add_entity", + "remove_entity": "packet_remove_entity", + "add_item_entity": "packet_add_item_entity", + "take_item_entity": "packet_take_item_entity", + "move_entity": "packet_move_entity", + "move_player": "packet_move_player", + "rider_jump": "packet_rider_jump", + "update_block": "packet_update_block", + "add_painting": "packet_add_painting", + "tick_sync": "packet_tick_sync", + "level_sound_event_old": "packet_level_sound_event_old", + "level_event": "packet_level_event", + "block_event": "packet_block_event", + "entity_event": "packet_entity_event", + "mob_effect": "packet_mob_effect", + "update_attributes": "packet_update_attributes", + "inventory_transaction": "packet_inventory_transaction", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", + "interact": "packet_interact", + "block_pick_request": "packet_block_pick_request", + "entity_pick_request": "packet_entity_pick_request", + "player_action": "packet_player_action", + "hurt_armor": "packet_hurt_armor", + "set_entity_data": "packet_set_entity_data", + "set_entity_motion": "packet_set_entity_motion", + "set_entity_link": "packet_set_entity_link", + "set_health": "packet_set_health", + "set_spawn_position": "packet_set_spawn_position", + "animate": "packet_animate", + "respawn": "packet_respawn", + "container_open": "packet_container_open", + "container_close": "packet_container_close", + "player_hotbar": "packet_player_hotbar", + "inventory_content": "packet_inventory_content", + "inventory_slot": "packet_inventory_slot", + "container_set_data": "packet_container_set_data", + "crafting_data": "packet_crafting_data", + "crafting_event": "packet_crafting_event", + "gui_data_pick_item": "packet_gui_data_pick_item", + "adventure_settings": "packet_adventure_settings", + "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", + "level_chunk": "packet_level_chunk", + "set_commands_enabled": "packet_set_commands_enabled", + "set_difficulty": "packet_set_difficulty", + "change_dimension": "packet_change_dimension", + "set_player_game_type": "packet_set_player_game_type", + "player_list": "packet_player_list", + "simple_event": "packet_simple_event", + "event": "packet_event", + "spawn_experience_orb": "packet_spawn_experience_orb", + "clientbound_map_item_data": "packet_clientbound_map_item_data", + "map_info_request": "packet_map_info_request", + "request_chunk_radius": "packet_request_chunk_radius", + "chunk_radius_update": "packet_chunk_radius_update", + "item_frame_drop_item": "packet_item_frame_drop_item", + "game_rules_changed": "packet_game_rules_changed", + "camera": "packet_camera", + "boss_event": "packet_boss_event", + "show_credits": "packet_show_credits", + "available_commands": "packet_available_commands", + "command_request": "packet_command_request", + "command_block_update": "packet_command_block_update", + "command_output": "packet_command_output", + "update_trade": "packet_update_trade", + "update_equipment": "packet_update_equipment", + "resource_pack_data_info": "packet_resource_pack_data_info", + "resource_pack_chunk_data": "packet_resource_pack_chunk_data", + "resource_pack_chunk_request": "packet_resource_pack_chunk_request", + "transfer": "packet_transfer", + "play_sound": "packet_play_sound", + "stop_sound": "packet_stop_sound", + "set_title": "packet_set_title", + "add_behavior_tree": "packet_add_behavior_tree", + "structure_block_update": "packet_structure_block_update", + "show_store_offer": "packet_show_store_offer", + "purchase_receipt": "packet_purchase_receipt", + "player_skin": "packet_player_skin", + "sub_client_login": "packet_sub_client_login", + "initiate_web_socket_connection": "packet_initiate_web_socket_connection", + "set_last_hurt_by": "packet_set_last_hurt_by", + "book_edit": "packet_book_edit", + "npc_request": "packet_npc_request", + "photo_transfer": "packet_photo_transfer", + "modal_form_request": "packet_modal_form_request", + "modal_form_response": "packet_modal_form_response", + "server_settings_request": "packet_server_settings_request", + "server_settings_response": "packet_server_settings_response", + "show_profile": "packet_show_profile", + "set_default_game_type": "packet_set_default_game_type", + "remove_objective": "packet_remove_objective", + "set_display_objective": "packet_set_display_objective", + "set_score": "packet_set_score", + "lab_table": "packet_lab_table", + "update_block_synced": "packet_update_block_synced", + "move_entity_delta": "packet_move_entity_delta", + "set_scoreboard_identity": "packet_set_scoreboard_identity", + "set_local_player_as_initialized": "packet_set_local_player_as_initialized", + "update_soft_enum": "packet_update_soft_enum", + "network_stack_latency": "packet_network_stack_latency", + "script_custom_event": "packet_script_custom_event", + "spawn_particle_effect": "packet_spawn_particle_effect", + "available_entity_identifiers": "packet_available_entity_identifiers", + "level_sound_event_v2": "packet_level_sound_event_v2", + "network_chunk_publisher_update": "packet_network_chunk_publisher_update", + "biome_definition_list": "packet_biome_definition_list", + "level_sound_event": "packet_level_sound_event", + "level_event_generic": "packet_level_event_generic", + "lectern_update": "packet_lectern_update", + "video_stream_connect": "packet_video_stream_connect", + "add_ecs_entity": "packet_add_ecs_entity", + "remove_ecs_entity": "packet_remove_ecs_entity", + "client_cache_status": "packet_client_cache_status", + "on_screen_texture_animation": "packet_on_screen_texture_animation", + "map_create_locked_copy": "packet_map_create_locked_copy", + "structure_template_data_export_request": "packet_structure_template_data_export_request", + "structure_template_data_export_response": "packet_structure_template_data_export_response", + "update_block_properties": "packet_update_block_properties", + "client_cache_blob_status": "packet_client_cache_blob_status", + "client_cache_miss_response": "packet_client_cache_miss_response", + "education_settings": "packet_education_settings", + "multiplayer_settings": "packet_multiplayer_settings", + "settings_command": "packet_settings_command", + "anvil_damage": "packet_anvil_damage", + "completed_using_item": "packet_completed_using_item", + "network_settings": "packet_network_settings", + "player_auth_input": "packet_player_auth_input", + "creative_content": "packet_creative_content", + "player_enchant_options": "packet_player_enchant_options", + "item_stack_request": "packet_item_stack_request", + "item_stack_response": "packet_item_stack_response", + "player_armor_damage": "packet_player_armor_damage", + "update_player_game_type": "packet_update_player_game_type", + "position_tracking_db_request": "packet_position_tracking_db_request", + "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", + "packet_violation_warning": "packet_packet_violation_warning", + "motion_prediction_hints": "packet_motion_prediction_hints", + "animate_entity": "packet_animate_entity", + "camera_shake": "packet_camera_shake", + "player_fog": "packet_player_fog", + "correct_player_move_prediction": "packet_correct_player_move_prediction", + "item_component": "packet_item_component", + "filter_text_packet": "packet_filter_text_packet", + "debug_renderer": "packet_debug_renderer", + "sync_entity_property": "packet_sync_entity_property", + "add_volume_entity": "packet_add_volume_entity", + "remove_volume_entity": "packet_remove_volume_entity" + }, + "default": "void" + } + ] + } + ] + ], + "packet_login": [ + "container", + [ + { + "name": "protocol_version", + "type": "i32" + }, + { + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] + ], + "LoginTokens": [ + "container", + [ + { + "name": "identity", + "type": "LittleString" + }, + { + "name": "client", + "type": "LittleString" + } + ] + ], + "packet_play_status": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "i32", + "mappings": { + "0": "login_success", + "1": "failed_client", + "2": "failed_spawn", + "3": "player_spawn", + "4": "failed_invalid_tenant", + "5": "failed_vanilla_edu", + "6": "failed_edu_vanilla", + "7": "failed_server_full" + } + } + ] + } + ] + ], + "packet_server_to_client_handshake": [ + "container", + [ + { + "name": "token", + "type": "string" + } + ] + ], + "packet_client_to_server_handshake": [ + "container", + [] + ], + "packet_disconnect": [ + "container", + [ + { + "name": "hide_disconnect_reason", + "type": "bool" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "packet_resource_packs_info": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "behaviour_packs", + "type": "BehaviourPackInfos" + }, + { + "name": "texture_packs", + "type": "TexturePackInfos" + } + ] + ], + "packet_resource_pack_stack": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behavior_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "resource_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + } + ] + ], + "packet_resource_pack_client_response": [ + "container", + [ + { + "name": "response_status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "refused", + "2": "send_packs", + "3": "have_all_packs", + "4": "completed" + } + } + ] + }, + { + "name": "resourcepackids", + "type": "ResourcePackIds" + } + ] + ], + "packet_text": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "raw", + "1": "chat", + "2": "translation", + "3": "popup", + "4": "jukebox_popup", + "5": "tip", + "6": "system", + "7": "whisper", + "8": "announcement", + "9": "json_whisper", + "10": "json" + } + } + ] + }, + { + "name": "needs_translation", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "chat": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "whisper": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "announcement": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "raw": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "tip": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "system": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json_whisper": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "translation": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "jukebox_popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "xuid", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + } + ] + ], + "packet_set_time": [ + "container", + [ + { + "name": "time", + "type": "zigzag32" + } + ] + ], + "packet_start_game": [ + "container", + [ + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "player_gamemode", + "type": "GameMode" + }, + { + "name": "player_position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "vec2f" + }, + { + "name": "seed", + "type": "zigzag32" + }, + { + "name": "biome_type", + "type": "li16" + }, + { + "name": "biome_name", + "type": "string" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "generator", + "type": "zigzag32" + }, + { + "name": "world_gamemode", + "type": "GameMode" + }, + { + "name": "difficulty", + "type": "zigzag32" + }, + { + "name": "spawn_position", + "type": "BlockCoordinates" + }, + { + "name": "achievements_disabled", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", + "type": "zigzag32" + }, + { + "name": "edu_offer", + "type": "zigzag32" + }, + { + "name": "edu_features_enabled", + "type": "bool" + }, + { + "name": "edu_product_uuid", + "type": "string" + }, + { + "name": "rain_level", + "type": "lf32" + }, + { + "name": "lightning_level", + "type": "lf32" + }, + { + "name": "has_confirmed_platform_locked_content", + "type": "bool" + }, + { + "name": "is_multiplayer", + "type": "bool" + }, + { + "name": "broadcast_to_lan", + "type": "bool" + }, + { + "name": "xbox_live_broadcast_mode", + "type": "varint" + }, + { + "name": "platform_broadcast_mode", + "type": "varint" + }, + { + "name": "enable_commands", + "type": "bool" + }, + { + "name": "is_texturepacks_required", + "type": "bool" + }, + { + "name": "gamerules", + "type": "GameRules" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + }, + { + "name": "bonus_chest", + "type": "bool" + }, + { + "name": "map_enabled", + "type": "bool" + }, + { + "name": "permission_level", + "type": "zigzag32" + }, + { + "name": "server_chunk_tick_range", + "type": "li32" + }, + { + "name": "has_locked_behavior_pack", + "type": "bool" + }, + { + "name": "has_locked_resource_pack", + "type": "bool" + }, + { + "name": "is_from_locked_world_template", + "type": "bool" + }, + { + "name": "msa_gamertags_only", + "type": "bool" + }, + { + "name": "is_from_world_template", + "type": "bool" + }, + { + "name": "is_world_template_option_locked", + "type": "bool" + }, + { + "name": "only_spawn_v1_villagers", + "type": "bool" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "limited_world_width", + "type": "li32" + }, + { + "name": "limited_world_length", + "type": "li32" + }, + { + "name": "is_new_nether", + "type": "bool" + }, + { + "name": "experimental_gameplay_override", + "type": "bool" + }, + { + "name": "level_id", + "type": "string" + }, + { + "name": "world_name", + "type": "string" + }, + { + "name": "premium_world_template_id", + "type": "string" + }, + { + "name": "is_trial", + "type": "bool" + }, + { + "name": "movement_authority", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "client", + "1": "server", + "2": "server_with_rewind" + } + } + ] + }, + { + "name": "rewind_history_size", + "type": "zigzag32" + }, + { + "name": "server_authoritative_block_breaking", + "type": "bool" + }, + { + "name": "current_tick", + "type": "li64" + }, + { + "name": "enchantment_seed", + "type": "zigzag32" + }, + { + "name": "block_properties", + "type": "BlockProperties" + }, + { + "name": "itemstates", + "type": "Itemstates" + }, + { + "name": "multiplayer_correlation_id", + "type": "string" + }, + { + "name": "server_authoritative_inventory", + "type": "bool" + }, + { + "name": "engine", + "type": "string" + } + ] + ], + "packet_add_player": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "flags", + "type": "varint" + }, + { + "name": "command_permission", + "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + }, + { + "name": "links", + "type": "Links" + }, + { + "name": "device_id", + "type": "string" + }, + { + "name": "device_os", + "type": "li32" + } + ] + ], + "packet_add_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "attributes", + "type": "EntityAttributes" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "links", + "type": "Links" + } + ] + ], + "packet_remove_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + } + ] + ], + "packet_add_item_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "is_from_fishing", + "type": "bool" + } + ] + ], + "packet_take_item_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "target", + "type": "varint" + } + ] + ], + "packet_move_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "Rotation" + } + ] + ], + "packet_move_player": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "mode", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "normal", + "1": "reset", + "2": "teleport", + "3": "rotation" + } + } + ] + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "ridden_runtime_id", + "type": "varint" + }, + { + "name": "teleport", + "type": [ + "switch", + { + "compareTo": "mode", + "fields": { + "teleport": [ + "container", + [ + { + "name": "cause", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "unknown", + "1": "projectile", + "2": "chorus_fruit", + "3": "command", + "4": "behavior" + } + } + ] + }, + { + "name": "source_entity_type", + "type": "LegacyEntityType" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_rider_jump": [ + "container", + [ + { + "name": "jump_strength", + "type": "zigzag32" + } + ] + ], + "packet_update_block": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + } + ] + ], + "packet_add_painting": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "coordinates", + "type": "vec3f" + }, + { + "name": "direction", + "type": "zigzag32" + }, + { + "name": "title", + "type": "string" + } + ] + ], + "packet_tick_sync": [ + "container", + [ + { + "name": "request_time", + "type": "li64" + }, + { + "name": "response_time", + "type": "li64" + } + ] + ], + "packet_level_sound_event_old": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "zigzag32" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event": [ + "container", + [ + { + "name": "event", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "1000": "sound_click", + "1001": "sound_click_fail", + "1002": "sound_shoot", + "1003": "sound_door", + "1004": "sound_fizz", + "1005": "sound_ignite", + "1007": "sound_ghast", + "1008": "sound_ghast_shoot", + "1009": "sound_blaze_shoot", + "1010": "sound_door_bump", + "1012": "sound_door_crash", + "1018": "sound_enderman_teleport", + "1020": "sound_anvil_break", + "1021": "sound_anvil_use", + "1022": "sound_anvil_fall", + "1030": "sound_pop", + "1032": "sound_portal", + "1040": "sound_itemframe_add_item", + "1041": "sound_itemframe_remove", + "1042": "sound_itemframe_place", + "1043": "sound_itemframe_remove_item", + "1044": "sound_itemframe_rotate_item", + "1050": "sound_camera", + "1051": "sound_orb", + "1052": "sound_totem", + "1060": "sound_armor_stand_break", + "1061": "sound_armor_stand_hit", + "1062": "sound_armor_stand_fall", + "1063": "sound_armor_stand_place", + "1064": "pointed_dripstone_land", + "1065": "dye_used", + "1066": "ink_sack_used", + "2000": "particle_shoot", + "2001": "particle_destroy", + "2002": "particle_splash", + "2003": "particle_eye_despawn", + "2004": "particle_spawn", + "2005": "particle_crop_growth", + "2006": "particle_guardian_curse", + "2007": "particle_death_smoke", + "2008": "particle_block_force_field", + "2009": "particle_projectile_hit", + "2010": "particle_dragon_egg_teleport", + "2011": "particle_crop_eaten", + "2012": "particle_critical", + "2013": "particle_enderman_teleport", + "2014": "particle_punch_block", + "2015": "particle_bubble", + "2016": "particle_evaporate", + "2017": "particle_destroy_armor_stand", + "2018": "particle_breaking_egg", + "2019": "particle_destroy_egg", + "2020": "particle_evaporate_water", + "2021": "particle_destroy_block_no_sound", + "2022": "particle_knockback_roar", + "2023": "particle_teleport_trail", + "2024": "particle_point_cloud", + "2025": "particle_explosion", + "2026": "particle_block_explosion", + "2027": "particle_vibration_signal", + "2028": "particle_dripstone_drip", + "2029": "particle_fizz_effect", + "2030": "particle_wax_on", + "2031": "particle_wax_off", + "2032": "particle_scrape", + "2033": "particle_electric_spark", + "3001": "start_rain", + "3002": "start_thunder", + "3003": "stop_rain", + "3004": "stop_thunder", + "3005": "pause_game", + "3006": "pause_game_no_screen", + "3007": "set_game_speed", + "3500": "redstone_trigger", + "3501": "cauldron_explode", + "3502": "cauldron_dye_armor", + "3503": "cauldron_clean_armor", + "3504": "cauldron_fill_potion", + "3505": "cauldron_take_potion", + "3506": "cauldron_fill_water", + "3507": "cauldron_take_water", + "3508": "cauldron_add_dye", + "3509": "cauldron_clean_banner", + "3600": "block_start_break", + "3601": "block_stop_break", + "4000": "set_data", + "9800": "players_sleeping", + "16384": "add_particle_mask" + } + } + ] + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_block_event": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "sound", + "1": "change_state" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_entity_event": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "event_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "jump", + "2": "hurt_animation", + "3": "death_animation", + "4": "arm_swing", + "5": "stop_attack", + "6": "tame_fail", + "7": "tame_success", + "8": "shake_wet", + "9": "use_item", + "10": "eat_grass_animation", + "11": "fish_hook_bubble", + "12": "fish_hook_position", + "13": "fish_hook_hook", + "14": "fish_hook_tease", + "15": "squid_ink_cloud", + "16": "zombie_villager_cure", + "18": "respawn", + "19": "iron_golem_offer_flower", + "20": "iron_golem_withdraw_flower", + "21": "love_particles", + "22": "villager_angry", + "23": "villager_happy", + "24": "witch_spell_particles", + "25": "firework_particles", + "26": "in_love_particles", + "27": "silverfish_spawn_animation", + "28": "guardian_attack", + "29": "witch_drink_potion", + "30": "witch_throw_potion", + "31": "minecart_tnt_prime_fuse", + "32": "creeper_prime_fuse", + "33": "air_supply_expired", + "34": "player_add_xp_levels", + "35": "elder_guardian_curse", + "36": "agent_arm_swing", + "37": "ender_dragon_death", + "38": "dust_particles", + "39": "arrow_shake", + "57": "eating_item", + "60": "baby_animal_feed", + "61": "death_smoke_cloud", + "62": "complete_trade", + "63": "remove_leash", + "65": "consume_totem", + "66": "player_check_treasure_hunter_achievement", + "67": "entity_spawn", + "68": "dragon_puke", + "69": "item_entity_merge", + "70": "start_swim", + "71": "balloon_pop", + "72": "treasure_hunt", + "73": "agent_summon", + "74": "charged_crossbow", + "75": "fall" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_mob_effect": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "effect_id", + "type": "zigzag32" + }, + { + "name": "amplifier", + "type": "zigzag32" + }, + { + "name": "particles", + "type": "bool" + }, + { + "name": "duration", + "type": "zigzag32" + } + ] + ], + "packet_update_attributes": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "attributes", + "type": "PlayerAttributes" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_inventory_transaction": [ + "container", + [ + { + "name": "transaction", + "type": "Transaction" + } + ] + ], + "packet_mob_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "selected_slot", + "type": "u8" + }, + { + "name": "window_id", + "type": "WindowID" + } + ] + ], + "packet_mob_armor_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "helmet", + "type": "Item" + }, + { + "name": "chestplate", + "type": "Item" + }, + { + "name": "leggings", + "type": "Item" + }, + { + "name": "boots", + "type": "Item" + } + ] + ], + "packet_interact": [ + "container", + [ + { + "name": "action_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "3": "leave_vehicle", + "4": "mouse_over_entity", + "6": "open_inventory" + } + } + ] + }, + { + "name": "target_entity_id", + "type": "varint64" + }, + { + "name": "position", + "type": [ + "switch", + { + "compareTo": "action_id", + "fields": { + "mouse_over_entity": "vec3f", + "leave_vehicle": "vec3f" + }, + "default": "void" + } + ] + } + ] + ], + "packet_block_pick_request": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "add_user_data", + "type": "bool" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_entity_pick_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "lu64" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_player_action": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "action", + "type": "Action" + }, + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "packet_hurt_armor": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_entity_data": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "tick", + "type": "varint" + } + ] + ], + "packet_set_entity_motion": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + } + ] + ], + "packet_set_entity_link": [ + "container", + [ + { + "name": "link", + "type": "Link" + } + ] + ], + "packet_set_health": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_spawn_position": [ + "container", + [ + { + "name": "spawn_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "player", + "1": "world" + } + } + ] + }, + { + "name": "player_position", + "type": "BlockCoordinates" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "world_position", + "type": "BlockCoordinates" + } + ] + ], + "packet_animate": [ + "container", + [ + { + "name": "action_id", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "none", + "1": "swing_arm", + "2": "unknown", + "3": "wake_up", + "4": "critical_hit", + "5": "magic_critical_hit", + "6": "row_right", + "7": "row_left" + } + } + ] + }, + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_respawn": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "state", + "type": "u8" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_container_open": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "runtime_entity_id", + "type": "zigzag64" + } + ] + ], + "packet_container_close": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "server", + "type": "bool" + } + ] + ], + "packet_player_hotbar": [ + "container", + [ + { + "name": "selected_slot", + "type": "varint" + }, + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "select_slot", + "type": "bool" + } + ] + ], + "packet_inventory_content": [ + "container", + [ + { + "name": "window_id", + "type": "WindowIDVarint" + }, + { + "name": "input", + "type": "ItemStacks" + } + ] + ], + "packet_inventory_slot": [ + "container", + [ + { + "name": "window_id", + "type": "WindowIDVarint" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "item", + "type": "Item" + } + ] + ], + "packet_container_set_data": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "property", + "type": "zigzag32" + }, + { + "name": "value", + "type": "zigzag32" + } + ] + ], + "packet_crafting_data": [ + "container", + [ + { + "name": "recipes", + "type": "Recipes" + }, + { + "name": "potion_type_recipes", + "type": "PotionTypeRecipes" + }, + { + "name": "potion_container_recipes", + "type": "PotionContainerChangeRecipes" + }, + { + "name": "is_clean", + "type": "bool" + } + ] + ], + "packet_crafting_event": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "recipe_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "inventory", + "1": "crafting", + "2": "workbench" + } + } + ] + }, + { + "name": "recipe_id", + "type": "uuid" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "result", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + } + ] + ], + "packet_gui_data_pick_item": [ + "container", + [ + { + "name": "item_name", + "type": "string" + }, + { + "name": "item_effects", + "type": "string" + }, + { + "name": "hotbar_slot", + "type": "li32" + } + ] + ], + "packet_adventure_settings": [ + "container", + [ + { + "name": "flags", + "type": "AdventureFlags" + }, + { + "name": "command_permission", + "type": [ + "mapper", + { + "type": "varint32", + "mappings": { + "0": "normal", + "1": "operator", + "2": "host", + "3": "automation", + "4": "admin" + } + } + ] + }, + { + "name": "action_permissions", + "type": "ActionPermissions" + }, + { + "name": "permission_level", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "visitor", + "1": "member", + "2": "operator", + "3": "custom" + } + } + ] + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + } + ] + ], + "packet_block_entity_data": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_player_input": [ + "container", + [ + { + "name": "motion_x", + "type": "lf32" + }, + { + "name": "motion_z", + "type": "lf32" + }, + { + "name": "jumping", + "type": "bool" + }, + { + "name": "sneaking", + "type": "bool" + } + ] + ], + "packet_level_chunk": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "sub_chunk_count", + "type": "varint" + }, + { + "name": "cache_enabled", + "type": "bool" + }, + { + "name": "blobs", + "type": [ + "switch", + { + "compareTo": "cache_enabled", + "fields": { + "true": [ + "container", + [ + { + "name": "hashes", + "type": [ + "array", + { + "countType": "varint", + "type": "lu64" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_set_commands_enabled": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_set_difficulty": [ + "container", + [ + { + "name": "difficulty", + "type": "varint" + } + ] + ], + "packet_change_dimension": [ + "container", + [ + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "respawn", + "type": "bool" + } + ] + ], + "packet_set_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_player_list": [ + "container", + [ + { + "name": "records", + "type": "PlayerRecords" + } + ] + ], + "packet_simple_event": [ + "container", + [ + { + "name": "event_type", + "type": "lu16" + } + ] + ], + "packet_event": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint64" + }, + { + "name": "event_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "achievement_awarded", + "1": "entity_interact", + "2": "portal_built", + "3": "portal_used", + "4": "mob_killed", + "5": "cauldron_used", + "6": "player_death", + "7": "boss_killed", + "8": "agent_command", + "9": "agent_created", + "10": "banner_pattern_removed", + "11": "commaned_executed", + "12": "fish_bucketed", + "13": "mob_born", + "14": "pet_died", + "15": "cauldron_block_used", + "16": "composter_block_used", + "17": "bell_block_used", + "18": "actor_definition", + "19": "raid_update", + "20": "player_movement_anomaly", + "21": "player_moement_corrected", + "22": "honey_harvested", + "23": "target_block_hit", + "24": "piglin_barter", + "25": "waxed_or_unwaxed_copper" + } + } + ] + }, + { + "name": "use_player_id", + "type": "u8" + }, + { + "name": "event_data", + "type": "restBuffer" + } + ] + ], + "packet_spawn_experience_orb": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ], + "packet_clientbound_map_item_data": [ + "container", + [ + { + "name": "map_id", + "type": "zigzag64" + }, + { + "name": "update_flags", + "type": "UpdateMapFlags" + }, + { + "name": "dimension", + "type": "u8" + }, + { + "name": "locked", + "type": "bool" + }, + { + "name": "included_in", + "type": [ + "switch", + { + "compareTo": "update_flags.initialisation", + "fields": { + "true": [ + "array", + { + "countType": "varint", + "type": "zigzag64" + } + ] + }, + "default": "void" + } + ] + }, + { + "name": "scale", + "type": [ + "switch", + { + "compareTo": "update_flags.initialisation || update_flags.decoration || update_flags.texture", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "tracked", + "type": [ + "switch", + { + "compareTo": "update_flags.decoration", + "fields": { + "true": [ + "container", + [ + { + "name": "objects", + "type": [ + "array", + { + "countType": "varint", + "type": "TrackedObject" + } + ] + }, + { + "name": "decorations", + "type": [ + "array", + { + "countType": "varint", + "type": "MapDecoration" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "texture", + "type": [ + "switch", + { + "compareTo": "update_flags.texture", + "fields": { + "true": [ + "container", + [ + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "x_offset", + "type": "zigzag32" + }, + { + "name": "y_offset", + "type": "zigzag32" + }, + { + "name": "pixels", + "type": [ + "array", + { + "countType": "varint", + "type": "varint" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_map_info_request": [ + "container", + [ + { + "name": "map_id", + "type": "zigzag64" + } + ] + ], + "packet_request_chunk_radius": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_chunk_radius_update": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_item_frame_drop_item": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + } + ] + ], + "packet_game_rules_changed": [ + "container", + [ + { + "name": "rules", + "type": "GameRules" + } + ] + ], + "packet_camera": [ + "container", + [ + { + "name": "camera_entity_unique_id", + "type": "zigzag64" + }, + { + "name": "target_player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_boss_event": [ + "container", + [ + { + "name": "boss_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "show_bar", + "1": "register_player", + "2": "hide_bar", + "3": "unregister_player", + "4": "set_bar_progress", + "5": "set_bar_title", + "6": "update_properties", + "7": "texture" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "show_bar": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "progress", + "type": "lf32" + }, + { + "name": "screen_darkening", + "type": "li16" + }, + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], + "register_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "unregister_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "set_bar_progress": [ + "container", + [ + { + "name": "progress", + "type": "lf32" + } + ] + ], + "set_bar_title": [ + "container", + [ + { + "name": "title", + "type": "string" + } + ] + ], + "update_properties": [ + "container", + [ + { + "name": "screen_darkening", + "type": "li16" + }, + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], + "texture": [ + "container", + [ + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_show_credits": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "status", + "type": "zigzag32" + } + ] + ], + "packet_available_commands": [ + "container", + [ + { + "name": "values_len", + "type": "varint" + }, + { + "name": "_enum_type", + "type": [ + "enum_size_based_on_values_len" + ] + }, + { + "name": "enum_values", + "type": [ + "array", + { + "count": "values_len", + "type": "string" + } + ] + }, + { + "name": "suffixes", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + }, + { + "name": "enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "switch", + { + "compareTo": "../_enum_type", + "fields": { + "byte": "u8", + "short": "lu16", + "int": "lu32" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "command_data", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "description", + "type": "string" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "permission_level", + "type": "u8" + }, + { + "name": "alias", + "type": "li32" + }, + { + "name": "overloads", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "paramater_name", + "type": "string" + }, + { + "name": "value_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "1": "int", + "2": "float", + "3": "value", + "4": "wildcard_int", + "5": "operator", + "6": "target", + "16": "file_path", + "32": "string", + "40": "position", + "44": "message", + "46": "raw_text", + "50": "json", + "63": "command" + } + } + ] + }, + { + "name": "enum_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "16": "valid", + "32": "enum", + "256": "suffixed", + "1024": "soft_enum" + } + } + ] + }, + { + "name": "optional", + "type": "bool" + }, + { + "name": "options", + "type": "CommandFlags" + } + ] + ] + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "dynamic_enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "enum_constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "value_index", + "type": "li32" + }, + { + "name": "enum_index", + "type": "li32" + }, + { + "name": "constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "constraint", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "cheats_enabled", + "1": "operator_permissions", + "2": "host_permissions" + } + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_command_request": [ + "container", + [ + { + "name": "command", + "type": "string" + }, + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "interval", + "type": "bool" + } + ] + ], + "packet_command_block_update": [ + "container", + [ + { + "name": "is_block", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "is_block", + "fields": { + "true": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "impulse", + "1": "repeat", + "2": "chain" + } + } + ] + }, + { + "name": "needs_redstone", + "type": "bool" + }, + { + "name": "conditional", + "type": "bool" + } + ] + ] + }, + "default": [ + "container", + [ + { + "name": "minecart_entity_runtime_id", + "type": "varint64" + } + ] + ] + } + ] + }, + { + "name": "command", + "type": "string" + }, + { + "name": "last_output", + "type": "string" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "should_track_output", + "type": "bool" + }, + { + "name": "tick_delay", + "type": "li32" + }, + { + "name": "execute_on_first_tick", + "type": "bool" + } + ] + ], + "packet_command_output": [ + "container", + [ + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "output_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "last", + "2": "silent", + "3": "all", + "4": "data_set" + } + } + ] + }, + { + "name": "success_count", + "type": "varint" + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "success", + "type": "bool" + }, + { + "name": "message_id", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "data_set", + "type": [ + "switch", + { + "compareTo": "output_type", + "fields": { + "data_set": "string" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_trade": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "varint" + }, + { + "name": "trade_tier", + "type": "varint" + }, + { + "name": "villager_unique_id", + "type": "varint64" + }, + { + "name": "entity_unique_id", + "type": "varint64" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "new_trading_ui", + "type": "bool" + }, + { + "name": "economic_trades", + "type": "bool" + }, + { + "name": "offers", + "type": "nbt" + } + ] + ], + "packet_update_equipment": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "inventory", + "type": "nbt" + } + ] + ], + "packet_resource_pack_data_info": [ + "container", + [ + { + "name": "pack_id", + "type": "string" + }, + { + "name": "max_chunk_size", + "type": "lu32" + }, + { + "name": "chunk_count", + "type": "lu32" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "hash", + "type": "ByteArray" + }, + { + "name": "is_premium", + "type": "bool" + }, + { + "name": "pack_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "addon", + "2": "cached", + "3": "copy_protected", + "4": "behavior", + "5": "persona_piece", + "6": "resources", + "7": "skins", + "8": "world_template" + } + } + ] + } + ] + ], + "packet_resource_pack_chunk_data": [ + "container", + [ + { + "name": "pack_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + }, + { + "name": "progress", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_resource_pack_chunk_request": [ + "container", + [ + { + "name": "pack_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + } + ] + ], + "packet_transfer": [ + "container", + [ + { + "name": "server_address", + "type": "string" + }, + { + "name": "port", + "type": "lu16" + } + ] + ], + "packet_play_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "volume", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + } + ] + ], + "packet_stop_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "stop_all", + "type": "bool" + } + ] + ], + "packet_set_title": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "clear", + "1": "reset", + "2": "set_title", + "3": "set_subtitle", + "4": "action_bar_message", + "5": "set_durations", + "6": "set_title_json", + "7": "set_subtitle_json", + "8": "action_bar_message_json" + } + } + ] + }, + { + "name": "text", + "type": "string" + }, + { + "name": "fade_in_time", + "type": "zigzag32" + }, + { + "name": "stay_time", + "type": "zigzag32" + }, + { + "name": "fade_out_time", + "type": "zigzag32" + } + ] + ], + "packet_add_behavior_tree": [ + "container", + [ + { + "name": "behaviortree", + "type": "string" + } + ] + ], + "packet_structure_block_update": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "structure_name", + "type": "string" + }, + { + "name": "data_field", + "type": "string" + }, + { + "name": "include_players", + "type": "bool" + }, + { + "name": "show_bounding_box", + "type": "bool" + }, + { + "name": "structure_block_type", + "type": "zigzag32" + }, + { + "name": "settings", + "type": "StructureBlockSettings" + }, + { + "name": "redstone_save_mode", + "type": "zigzag32" + }, + { + "name": "should_trigger", + "type": "bool" + } + ] + ], + "packet_show_store_offer": [ + "container", + [ + { + "name": "offer_id", + "type": "string" + }, + { + "name": "show_all", + "type": "bool" + } + ] + ], + "packet_purchase_receipt": [ + "container", + [ + { + "name": "receipts", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "packet_player_skin": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "skin", + "type": "Skin" + }, + { + "name": "skin_name", + "type": "string" + }, + { + "name": "old_skin_name", + "type": "string" + }, + { + "name": "is_verified", + "type": "bool" + } + ] + ], + "packet_sub_client_login": [ + "container", + [ + { + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] + ], + "packet_initiate_web_socket_connection": [ + "container", + [ + { + "name": "server", + "type": "string" + } + ] + ], + "packet_set_last_hurt_by": [ + "container", + [ + { + "name": "entity_type", + "type": "varint" + } + ] + ], + "packet_book_edit": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "replace_page", + "1": "add_page", + "2": "delete_page", + "3": "swap_pages", + "4": "sign" + } + } + ] + }, + { + "name": "slot", + "type": "u8" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "replace_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "add_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "delete_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + } + ] + ], + "swap_pages": [ + "container", + [ + { + "name": "page1", + "type": "u8" + }, + { + "name": "page2", + "type": "u8" + } + ] + ], + "sign": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "author", + "type": "string" + }, + { + "name": "xuid", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_npc_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "request_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "set_actions", + "1": "execute_action", + "2": "execute_closing_commands", + "3": "set_name", + "4": "set_skin", + "5": "set_interaction_text" + } + } + ] + }, + { + "name": "command", + "type": "string" + }, + { + "name": "action_type", + "type": "u8" + } + ] + ], + "packet_photo_transfer": [ + "container", + [ + { + "name": "image_name", + "type": "string" + }, + { + "name": "image_data", + "type": "string" + }, + { + "name": "book_id", + "type": "string" + } + ] + ], + "packet_modal_form_request": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_modal_form_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_server_settings_request": [ + "container", + [] + ], + "packet_server_settings_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_show_profile": [ + "container", + [ + { + "name": "xuid", + "type": "string" + } + ] + ], + "packet_set_default_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_remove_objective": [ + "container", + [ + { + "name": "objective_name", + "type": "string" + } + ] + ], + "packet_set_display_objective": [ + "container", + [ + { + "name": "display_slot", + "type": "string" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "criteria_name", + "type": "string" + }, + { + "name": "sort_order", + "type": "zigzag32" + } + ] + ], + "packet_set_score": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "change", + "1": "remove" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "../action", + "fields": { + "change": [ + "container", + [ + { + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": "zigzag64", + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "custom_name", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "fake_player": "string" + }, + "default": "void" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_lab_table": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "combine", + "1": "react" + } + } + ] + }, + { + "name": "position", + "type": "vec3u" + }, + { + "name": "reaction_type", + "type": "u8" + } + ] + ], + "packet_update_block_synced": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "transition_type", + "type": [ + "mapper", + { + "type": "varint64", + "mappings": { + "0": "entity", + "1": "create", + "2": "destroy" + } + } + ] + } + ] + ], + "packet_move_entity_delta": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "flags", + "type": "DeltaMoveFlags" + }, + { + "name": "x", + "type": [ + "switch", + { + "compareTo": "flags.has_x", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "y", + "type": [ + "switch", + { + "compareTo": "flags.has_y", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "z", + "type": [ + "switch", + { + "compareTo": "flags.has_z", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "rot_x", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_x", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_y", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_y", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_z", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_z", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + } + ] + ], + "packet_set_scoreboard_identity": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "register_identity", + "1": "clear_identity" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "../action", + "fields": { + "register_identity": "zigzag64" + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_set_local_player_as_initialized": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_update_soft_enum": [ + "container", + [] + ], + "packet_network_stack_latency": [ + "container", + [ + { + "name": "timestamp", + "type": "lu64" + }, + { + "name": "needs_response", + "type": "u8" + } + ] + ], + "packet_script_custom_event": [ + "container", + [ + { + "name": "event_name", + "type": "string" + }, + { + "name": "event_data", + "type": "string" + } + ] + ], + "packet_spawn_particle_effect": [ + "container", + [ + { + "name": "dimension", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "particle_name", + "type": "string" + } + ] + ], + "packet_available_entity_identifiers": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event_v2": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_network_chunk_publisher_update": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "radius", + "type": "varint" + } + ] + ], + "packet_biome_definition_list": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event": [ + "container", + [ + { + "name": "sound_id", + "type": "SoundType" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "extra_data", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event_generic": [ + "container", + [ + { + "name": "event_id", + "type": "varint" + }, + { + "name": "nbt", + "type": "nbtLoop" + } + ] + ], + "packet_lectern_update": [ + "container", + [ + { + "name": "page", + "type": "u8" + }, + { + "name": "page_count", + "type": "u8" + }, + { + "name": "position", + "type": "vec3i" + }, + { + "name": "drop_book", + "type": "bool" + } + ] + ], + "packet_video_stream_connect": [ + "container", + [ + { + "name": "server_uri", + "type": "string" + }, + { + "name": "frame_send_frequency", + "type": "lf32" + }, + { + "name": "action", + "type": "u8" + }, + { + "name": "resolution_x", + "type": "li32" + }, + { + "name": "resolution_y", + "type": "li32" + } + ] + ], + "packet_add_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_remove_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_client_cache_status": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_on_screen_texture_animation": [ + "container", + [ + { + "name": "animation_type", + "type": "lu32" + } + ] + ], + "packet_map_create_locked_copy": [ + "container", + [ + { + "name": "original_map_id", + "type": "zigzag64" + }, + { + "name": "new_map_id", + "type": "zigzag64" + } + ] + ], + "packet_structure_template_data_export_request": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "settings", + "type": "StructureBlockSettings" + }, + { + "name": "request_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "export_from_save", + "2": "export_from_load", + "3": "query_saved_structure" + } + } + ] + } + ] + ], + "packet_structure_template_data_export_response": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "success", + "type": "bool" + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "success", + "fields": { + "true": "nbt" + }, + "default": "void" + } + ] + }, + { + "name": "response_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "export", + "2": "query" + } + } + ] + } + ] + ], + "packet_update_block_properties": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_client_cache_blob_status": [ + "container", + [ + { + "name": "misses", + "type": "varint" + }, + { + "name": "haves", + "type": "varint" + }, + { + "name": "missing", + "type": [ + "array", + { + "count": "misses", + "type": "lu64" + } + ] + }, + { + "name": "have", + "type": [ + "array", + { + "count": "haves", + "type": "lu64" + } + ] + } + ] + ], + "packet_client_cache_miss_response": [ + "container", + [ + { + "name": "blobs", + "type": [ + "array", + { + "countType": "varint", + "type": "Blob" + } + ] + } + ] + ], + "packet_education_settings": [ + "container", + [ + { + "name": "CodeBuilderDefaultURI", + "type": "string" + }, + { + "name": "CodeBuilderTitle", + "type": "string" + }, + { + "name": "CanResizeCodeBuilder", + "type": "bool" + }, + { + "name": "HasOverrideURI", + "type": "bool" + }, + { + "name": "OverrideURI", + "type": [ + "switch", + { + "compareTo": "HasOverrideURI", + "fields": { + "true": "string" + }, + "default": "void" + } + ] + }, + { + "name": "HasQuiz", + "type": "bool" + } + ] + ], + "packet_multiplayer_settings": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "enable_multiplayer", + "1": "disable_multiplayer", + "2": "refresh_join_code" + } + } + ] + } + ] + ], + "packet_settings_command": [ + "container", + [ + { + "name": "command_line", + "type": "string" + }, + { + "name": "suppress_output", + "type": "bool" + } + ] + ], + "packet_anvil_damage": [ + "container", + [ + { + "name": "damage", + "type": "u8" + }, + { + "name": "position", + "type": "BlockCoordinates" + } + ] + ], + "packet_completed_using_item": [ + "container", + [ + { + "name": "used_item_id", + "type": "li16" + }, + { + "name": "use_method", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "equip_armor", + "1": "eat", + "2": "attack", + "3": "consume", + "4": "throw", + "5": "shoot", + "6": "place", + "7": "fill_bottle", + "8": "fill_bucket", + "9": "pour_bucket", + "10": "use_tool", + "11": "interact", + "12": "retrieved", + "13": "dyed", + "14": "traded" + } + } + ] + } + ] + ], + "packet_network_settings": [ + "container", + [ + { + "name": "compression_threshold", + "type": "u16" + } + ] + ], + "packet_player_auth_input": [ + "container", + [ + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "move_vector", + "type": "vec2f" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "input_data", + "type": "InputFlag" + }, + { + "name": "input_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "unknown", + "1": "mouse", + "2": "touch", + "3": "game_pad", + "4": "motion_controller" + } + } + ] + }, + { + "name": "play_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "teaser", + "2": "screen", + "3": "viewer", + "4": "reality", + "5": "placement", + "6": "living_room", + "7": "exit_level", + "8": "exit_level_living_room", + "9": "num_modes" + } + } + ] + }, + { + "name": "gaze_direction", + "type": [ + "switch", + { + "compareTo": "play_mode", + "fields": { + "reality": "vec3f" + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "transaction", + "type": [ + "switch", + { + "compareTo": "input_data.item_interact", + "fields": { + "true": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "actions", + "type": "TransactionActions" + }, + { + "name": "data", + "type": "TransactionUseItem" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "item_stack_request", + "type": [ + "switch", + { + "compareTo": "input_data.item_stack_request", + "fields": { + "true": "ItemStackRequest" + }, + "default": "void" + } + ] + }, + { + "name": "block_action", + "type": [ + "switch", + { + "compareTo": "input_data.block_action", + "fields": { + "true": [ + "array", + { + "countType": "zigzag32", + "type": [ + "container", + [ + { + "name": "action", + "type": "Action" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "action", + "fields": { + "start_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "abort_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "crack_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "predict_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "continue_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_creative_content": [ + "container", + [ + { + "name": "items", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "entry_id", + "type": "varint" + }, + { + "name": "item", + "type": "ItemLegacy" + } + ] + ] + } + ] + } + ] + ], + "packet_player_enchant_options": [ + "container", + [ + { + "name": "options", + "type": [ + "array", + { + "countType": "varint", + "type": "EnchantOption" + } + ] + } + ] + ], + "packet_item_stack_request": [ + "container", + [ + { + "name": "requests", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemStackRequest" + } + ] + } + ] + ], + "packet_item_stack_response": [ + "container", + [ + { + "name": "responses", + "type": "ItemStackResponses" + } + ] + ], + "packet_player_armor_damage": [ + "container", + [ + { + "name": "type", + "type": "ArmorDamageType" + }, + { + "name": "helmet_damage", + "type": [ + "switch", + { + "compareTo": "type.head", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "chestplate_damage", + "type": [ + "switch", + { + "compareTo": "type.chest", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "leggings_damage", + "type": [ + "switch", + { + "compareTo": "type.legs", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "boots_damage", + "type": [ + "switch", + { + "compareTo": "type.feet", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + }, + { + "name": "player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_position_tracking_db_request": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "query" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + } + ] + ], + "packet_position_tracking_db_broadcast": [ + "container", + [ + { + "name": "broadcast_action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "update", + "1": "destory", + "2": "not_found" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_packet_violation_warning": [ + "container", + [ + { + "name": "violation_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "malformed" + } + } + ] + }, + { + "name": "severity", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "warning", + "1": "final_warning", + "2": "terminating" + } + } + ] + }, + { + "name": "packet_id", + "type": "zigzag32" + }, + { + "name": "reason", + "type": "string" + } + ] + ], + "packet_motion_prediction_hints": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + } + ] + ], + "packet_animate_entity": [ + "container", + [ + { + "name": "animation", + "type": "string" + }, + { + "name": "next_state", + "type": "string" + }, + { + "name": "stop_condition", + "type": "string" + }, + { + "name": "controller", + "type": "string" + }, + { + "name": "blend_out_time", + "type": "lf32" + }, + { + "name": "runtime_entity_ids", + "type": [ + "array", + { + "countType": "varint", + "type": "varint64" + } + ] + } + ] + ], + "packet_camera_shake": [ + "container", + [ + { + "name": "intensity", + "type": "lf32" + }, + { + "name": "duration", + "type": "lf32" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "stop" + } + } + ] + } + ] + ], + "packet_player_fog": [ + "container", + [ + { + "name": "stack", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "packet_correct_player_move_prediction": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_item_component": [ + "container", + [ + { + "name": "entries", + "type": "ItemComponentList" + } + ] + ], + "packet_filter_text_packet": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "from_server", + "type": "bool" + } + ] + ], + "packet_debug_renderer": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "1": "clear", + "2": "add_cube" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "clear": "void", + "add_cube": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "red", + "type": "lf32" + }, + { + "name": "green", + "type": "lf32" + }, + { + "name": "blue", + "type": "lf32" + }, + { + "name": "alpha", + "type": "lf32" + }, + { + "name": "duration", + "type": "li64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_sync_entity_property": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_add_volume_entity": [ + "container", + [ + { + "name": "entity_id", + "type": "varint64" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_remove_volume_entity": [ + "container", + [ + { + "name": "entity_id", + "type": "varint64" + } + ] + ], + "string": [ + "pstring", + { + "countType": "varint" + } + ], + "ByteArray": [ + "buffer", + { + "countType": "varint" + } + ], + "SignedByteArray": [ + "buffer", + { + "countType": "zigzag32" + } + ], + "LittleString": [ + "pstring", + { + "countType": "li32" + } + ], + "ShortArray": [ + "buffer", + { + "countType": "li16" + } + ], + "MetadataFlags1": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "flags": [ + "onfire", + "sneaking", + "riding", + "sprinting", + "action", + "invisible", + "tempted", + "inlove", + "saddled", + "powered", + "ignited", + "baby", + "converting", + "critical", + "can_show_nametag", + "always_show_nametag", + "no_ai", + "silent", + "wallclimbing", + "can_climb", + "swimmer", + "can_fly", + "walker", + "resting", + "sitting", + "angry", + "interested", + "charged", + "tamed", + "orphaned", + "leashed", + "sheared", + "gliding", + "elder", + "moving", + "breathing", + "chested", + "stackable", + "showbase", + "rearing", + "vibrating", + "idling", + "evoker_spell", + "charge_attack", + "wasd_controlled", + "can_power_jump", + "linger", + "has_collision", + "affected_by_gravity", + "fire_immune", + "dancing", + "enchanted", + "show_trident_rope", + "container_private", + "transforming", + "spin_attack", + "swimming", + "bribed", + "pregnant", + "laying_egg", + "rider_can_pick", + "transition_sitting", + "eating", + "laying_down" + ] + } + ], + "MetadataFlags2": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "flags": [ + "sneezing", + "trusting", + "rolling", + "scared", + "in_scaffolding", + "over_scaffolding", + "fall_through_scaffolding", + "blocking", + "transition_blocking", + "blocked_using_shield", + "blocked_using_damaged_shield", + "sleeping", + "wants_to_wake", + "trade_interest", + "door_breaker", + "breaking_obstruction", + "door_opener", + "illager_captain", + "stunned", + "roaring", + "delayed_attacking", + "avoiding_mobs", + "avoiding_block", + "facing_target_to_range_attack", + "hidden_when_invisible", + "is_in_ui", + "stalking", + "emoting", + "celebrating", + "admiring", + "celebrating_special", + "unknown95", + "ram_attack", + "playing_dead" + ] + } + ], + "UpdateBlockFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "neighbors": 1, + "network": 2, + "no_graphic": 4, + "unused": 8, + "priority": 16 + } + } + ], + "AdventureFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "world_immutable": 1, + "no_pvp": 2, + "auto_jump": 32, + "allow_flight": 64, + "no_clip": 128, + "world_builder": 256, + "flying": 512, + "muted": 1024 + } + } + ], + "ActionPermissions": [ + "bitflags", + { + "type": "varint", + "flags": { + "mine": 65537, + "doors_and_switches": 65538, + "open_containers": 65540, + "attack_players": 65544, + "attack_mobs": 65552, + "operator": 65568, + "teleport": 65664, + "build": 65792, + "default": 66048 + } + } + ], + "UpdateMapFlags": [ + "bitflags", + { + "type": "varint", + "flags": [ + "void", + "texture", + "decoration", + "initialisation" + ] + } + ], + "CommandFlags": [ + "bitfield", + [ + { + "name": "unused", + "size": 6, + "signed": false + }, + { + "name": "has_semantic_constraint", + "size": 1, + "signed": false + }, + { + "name": "collapse_enum", + "size": 1, + "signed": false + } + ] + ], + "DeltaMoveFlags": [ + "bitflags", + { + "type": "lu16", + "flags": { + "has_x": 1, + "has_y": 2, + "has_z": 4, + "has_rot_x": 8, + "has_rot_y": 16, + "has_rot_z": 32, + "on_ground": 64, + "teleport": 128, + "force_move": 256 + } + } + ], + "InputFlag": [ + "bitflags", + { + "type": "varint64", + "big": true, + "flags": [ + "ascend", + "descend", + "north_jump", + "jump_down", + "sprint_down", + "change_height", + "jumping", + "auto_jumping_in_water", + "sneaking", + "sneak_down", + "up", + "down", + "left", + "right", + "up_left", + "up_right", + "want_up", + "want_down", + "want_down_slow", + "want_up_slow", + "sprinting", + "ascend_scaffolding", + "descend_scaffolding", + "sneak_toggle_down", + "persist_sneak", + "start_sprinting", + "stop_sprinting", + "start_sneaking", + "stop_sneaking", + "start_swimming", + "stop_swimming", + "start_jumping", + "start_gliding", + "stop_gliding", + "item_interact", + "block_action", + "item_stack_request" + ] + } + ], + "ArmorDamageType": [ + "bitflags", + { + "type": "u8", + "flags": { + "head": 1, + "chest": 2, + "legs": 4, + "feet": 8 + } + } + ] + } +} \ No newline at end of file diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 50574a8..585c33c 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -1,7 +1,7 @@ # Created from MiNET and gophertunnel docs # The version below is the latest version this protocol schema was updated for. # The output protocol.json will be in the folder for the version -!version: 1.16.220 +!version: 1.17.0 # Some ProtoDef aliases string: ["pstring",{"countType":"varint"}] @@ -379,7 +379,8 @@ packet_start_game: # is a new system introduced in 1.16. Backwards compatibility with the inventory transactions has to # some extent been preserved, but will eventually be removed. server_authoritative_inventory: bool - + # The server's engine version, used for telemetry + engine: string packet_add_player: !id: 0x0c @@ -629,8 +630,8 @@ packet_level_event: 1065: dye_used 1066: ink_sack_used 2000: particle_shoot #TODO: check 2000-2017 - 2001: particle_destroy - 2002: particle_splash + 2001: particle_destroy + 2002: particle_splash 2003: particle_eye_despawn 2004: particle_spawn 2005: particle_crop_growth @@ -683,7 +684,7 @@ packet_level_event: 3600: block_start_break 3601: block_stop_break 4000: set_data - 9800: players_sleeping + 9800: players_sleeping 0x4000: add_particle_mask position: vec3f data: zigzag32 @@ -1243,7 +1244,7 @@ packet_event: 9: agent_created 10: banner_pattern_removed 11: commaned_executed - 12: fish_bucketed + 12: fish_bucketed 13: mob_born 14: pet_died 15: cauldron_block_used @@ -1256,6 +1257,7 @@ packet_event: 22: honey_harvested 23: target_block_hit 24: piglin_barter + 25: waxed_or_unwaxed_copper use_player_id: u8 event_data: restBuffer # Unknown data, TODO: add @@ -3015,4 +3017,26 @@ packet_debug_renderer: # Alpha is the alpha value from the RGBA colour rendered on the debug. alpha: lf32 # Duration is how long the debug will last in the world for. It is measured in milliseconds. - duration: li64 \ No newline at end of file + duration: li64 + +# Sent by the server to synchronize/update entity properties as NBT, an alternative to Set Entity Data. +packet_sync_entity_property: + !id: 0xa5 + !bound: client + nbt: nbt + +# AddVolumeEntity sends a volume entity's definition and components from server to client. +packet_add_volume_entity: + !id: 0xa6 + !bound: client + # The Runtime Entity ID + entity_id: varint64 + nbt: nbt + +# RemoveVolumeEntity indicates a volume entity to be removed from server to client. +packet_remove_volume_entity: + !id: 0xa7 + !bound: client + # The Runtime Entity ID + entity_id: varint64 + diff --git a/data/latest/types.yaml b/data/latest/types.yaml index f047936..b18a577 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -45,6 +45,7 @@ GameMode: zigzag32 => GameRule: name: string + editable: bool type: varint => 1: bool 2: int @@ -283,12 +284,11 @@ MetadataDictionary: []varint 117: nearby_cured_discount_timestamp 118: hitbox 119: is_buoyant - 120: freezing_effect_strength - 121: buoyancy_data - 122: goat_horn_count - 123: base_runtime_id - 124: define_properties - 125: update_properties + 120: base_runtime_id + 121: freezing_effect_strength + 122: buoyancy_data + 123: goat_horn_count + 124: update_properties type: varint => 0: byte 1: short @@ -418,7 +418,10 @@ MetadataFlags2: [ "bitflags", { "emoting", "celebrating", "admiring", - "celebrating_special" + "celebrating_special", + "unknown95", # 95 + "ram_attack", + "playing_dead" ] }] @@ -1042,10 +1045,24 @@ StructureBlockSettings: last_editing_player_unique_id: zigzag64 # Rotation is the rotation that the structure block should obtain. See the constants above for available # options. - rotation: u8 + rotation: u8 => + 0: none + 1: 90_deg + 2: 180_deg + 3: 270_deg # Mirror specifies the way the structure should be mirrored. It is either no mirror at all, mirror on the # x/z axis or both. - mirror: u8 + mirror: u8 => + 0: none + 1: x_axis + 2: z_axis + 3: both_axes + animation_mode: u8 => + 0: none + 1: layers + 2: blocks + # How long the duration for this animation is + animation_duration: lf32 # Integrity is usually 1, but may be set to a number between 0 and 1 to omit blocks randomly, using # the Seed that follows. integrity: lf32 @@ -1553,6 +1570,31 @@ SoundType: varint => - CaveVinesPickBerries - BigDripleafTiltDown - BigDripleafTiltUp + - unknown335 + - unknown336 + - unknown337 + - unknown338 + - copper_wax_on + - copper_wax_off + - scrape + - player_hurt_drown + - player_hurt_on_fire + - player_hurt_freeze + - use_spyglass + - stop_using_spyglass + - amethyst_block_chime + - ambient_screamer + - hurt_screamer + - death_screamer + - milk_screamer + - jump_to_block + - pre_ram + - pre_ram_screamer + - ram_impact + - ram_impact_screamer + - squid_ink_squirt + - glow_squid_ink_squirt + - convert_to_stray - Undefined # TODO: remove? diff --git a/index.d.ts b/index.d.ts index e47c35c..34fee07 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } @@ -157,4 +157,4 @@ declare module "bedrock-protocol" { export function createServer(options: ServerOptions): Server export function ping({ host, port }: { host: string, port: number }): Promise -} \ No newline at end of file +} diff --git a/src/options.js b/src/options.js index 8750697..4530548 100644 --- a/src/options.js +++ b/src/options.js @@ -1,9 +1,10 @@ // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson -const CURRENT_VERSION = '1.16.220' +const CURRENT_VERSION = '1.17.0' const Versions = { + '1.17.0': 440, '1.16.220': 431, '1.16.210': 428, '1.16.201': 422 diff --git a/test/internal.js b/test/internal.js index ff8cedf..ddfd025 100644 --- a/test/internal.js +++ b/test/internal.js @@ -2,6 +2,7 @@ const { Server, Client } = require('../') const { dumpPackets } = require('../tools/genPacketDumps') const DataProvider = require('../data/provider') const { ping } = require('../src/createClient') +const { CURRENT_VERSION } = require('../src/options') // First we need to dump some packets that a vanilla server would send a vanilla // client. Then we can replay those back in our custom server. @@ -9,7 +10,7 @@ function prepare (version) { return dumpPackets(version) } -async function startTest (version = '1.16.220', ok) { +async function startTest (version = CURRENT_VERSION, ok) { await prepare(version) const Item = require('../types/Item')(version) const port = 19130 diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index 39a1fce..a0a676f 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -23,7 +23,7 @@ async function dump (version, force = true) { const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port }) - console.log('Started dump server') + console.log('Started dump server', version) const client = new Client({ host: '127.0.0.1', port, diff --git a/types/Item.js b/types/Item.js index 123ceb4..5de23d2 100644 --- a/types/Item.js +++ b/types/Item.js @@ -1,3 +1,5 @@ +const { Versions } = require('../src/options') + module.exports = (version) => class Item { nbt @@ -11,7 +13,7 @@ module.exports = (version) => } static fromBedrock (obj) { - if (version === '1.16.220') { + if (Versions[version] >= Versions['1.16.220']) { return new Item({ networkId: obj.network_id, stackId: obj.stack_id, @@ -32,7 +34,7 @@ module.exports = (version) => } toBedrock () { - if (version === '1.16.220') { + if (Versions[version] >= Versions['1.16.220']) { return { network_id: this.networkId, count: this.count, From 6a03c9813c0e6dc856d2de5e03cfadd60d8d79a0 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 9 Jun 2021 17:38:58 -0400 Subject: [PATCH 201/458] Release 3.4.0 --- HISTORY.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index d731a86..71c0f33 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,8 @@ +## 3.4.0 +* Initial 1.17 support [#99](https://github.com/PrismarineJS/bedrock-protocol/pull/99) +* update connect version based on ping response & fix typings (u9g) [#101](https://github.com/PrismarineJS/bedrock-protocol/pull/101) +* fix: ping types. (JammSpread) [#100](https://github.com/PrismarineJS/bedrock-protocol/pull/100) + ## 3.3.0 * Protocol updates for 1.16, with some minor breaking changes to protocol fields [#95](https://github.com/PrismarineJS/bedrock-protocol/pull/95) * Fix npm install issues diff --git a/package.json b/package.json index ec3ffd9..f01299f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.3.0", + "version": "3.4.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 90d12fa6969390ec47b27e0d719b317dcc04fa22 Mon Sep 17 00:00:00 2001 From: JammSpread <61063879+JammSpread@users.noreply.github.com> Date: Fri, 11 Jun 2021 18:45:54 -0400 Subject: [PATCH 202/458] fix: type definition errors found related to ServerAdvertisements. (#103) * fix: online/max player count type definition. Fixes the type definition of the online/max players to be an immediate child of the ServerAdvertisement class so that it can be accessed properly on TypeScript. Signed-off-by: JK * feat: implement advertisementFn type definition. Adds the type definition for the 'advertisementFn' server option. Signed-off-by: JK * fix: minor advertisementFn typo in API docs. Fixes a minor typo found in the API docs that misspells 'advertisementFn' as 'advertismentFn'. Signed-off-by: JK * feat: add skipPing to the API docs. Adds the 'skipPing' client option to the API docs. Signed-off-by: JK * feat: add connectTimeout type definition. Adds the 'connectTimeout' client option to the package type definitions. Signed-off-by: JK --- docs/API.md | 5 +++-- index.d.ts | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/API.md b/docs/API.md index a38da60..051ea09 100644 --- a/docs/API.md +++ b/docs/API.md @@ -17,7 +17,8 @@ Returns a `Client` instance and connects to the server. | connectTimeout | *optional* | default to **9000ms**. How long to wait in milliseconds while trying to connect to server. | | onMsaCode | *optional* | Callback called when signing in with a microsoft account with device code auth, `data` is an object documented [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code#device-authorization-response) | | profilesFolder | *optional* | Where to store cached authentication tokens. Defaults to .minecraft, or the node_modules folder if not found. | -| autoInitPlayer | optional | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | +| autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | +| skipPing | *optional* | Whether pinging the server to check its version should be skipped. | ## be.createServer(options) : Server @@ -36,7 +37,7 @@ authenticated unless offline is set to true. | maxPlayers | *optional* | default to **3**. Set this to change the maximum number of players connected. | | kickTimeout | *[Future][1]* | How long to wait before kicking a unresponsive client. | | motd | *optional* | The "message of the day" for the server, the message shown to players in the server list. See usage below. | -| advertismentFn | *optional* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | +| advertisementFn | *optional* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | ## be.ping({ host, port }) : ServerAdvertisement diff --git a/index.d.ts b/index.d.ts index 34fee07..d59c8fd 100644 --- a/index.d.ts +++ b/index.d.ts @@ -23,6 +23,8 @@ declare module "bedrock-protocol" { viewDistance?: number, // Specifies which game edition to sign in as. Optional, but some servers verify this. authTitle?: title | string, + // How long to wait in milliseconds while trying to connect to the server. + connectTimeout?: number // whether to skip initial ping and immediately connect skipPing?: boolean } @@ -36,6 +38,7 @@ declare module "bedrock-protocol" { // The sub-header for the MOTD shown in the server list. levelName: string } + advertisementFn: () => ServerAdvertisement } enum ClientStatus { @@ -145,10 +148,8 @@ declare module "bedrock-protocol" { name: string protocol: number version: string - players: { - online: number, - max: number - } + playersOnline: number + playersMax: number gamemode: string serverId: string } From 565ae4583dc671e0387a796d7c0aa71e536bc48e Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 18 Jun 2021 14:47:55 -0400 Subject: [PATCH 203/458] Protocol updates to sync with minecraft-data --- data/1.16.201/protocol.json | 10 ++++++++-- data/1.16.210/protocol.json | 10 ++++++++-- data/1.16.220/protocol.json | 10 ++++++++-- data/1.17.0/protocol.json | 19 ++++++++++++------- data/latest/proto.yml | 19 ++++++++++++------- data/latest/types.yaml | 6 +++--- 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/data/1.16.201/protocol.json b/data/1.16.201/protocol.json index a62a5ed..d82e626 100644 --- a/data/1.16.201/protocol.json +++ b/data/1.16.201/protocol.json @@ -1,13 +1,19 @@ { "types": { "varint32": "varint", - "bool": "native", + "varint64": "native", "zigzag32": "native", "zigzag64": "native", "uuid": "native", "byterot": "native", - "MapInfo": "native", + "bitflags": "native", + "restBuffer": "native", + "encapsulated": "native", "nbt": "native", + "lnbt": "native", + "nbtLoop": "native", + "enum_size_based_on_values_len": "native", + "MapInfo": "native", "BehaviourPackInfos": [ "array", { diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json index 1010531..96a88ca 100644 --- a/data/1.16.210/protocol.json +++ b/data/1.16.210/protocol.json @@ -1,13 +1,19 @@ { "types": { "varint32": "varint", - "bool": "native", + "varint64": "native", "zigzag32": "native", "zigzag64": "native", "uuid": "native", "byterot": "native", - "MapInfo": "native", + "bitflags": "native", + "restBuffer": "native", + "encapsulated": "native", "nbt": "native", + "lnbt": "native", + "nbtLoop": "native", + "enum_size_based_on_values_len": "native", + "MapInfo": "native", "BehaviourPackInfos": [ "array", { diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json index b49072a..eaebb08 100644 --- a/data/1.16.220/protocol.json +++ b/data/1.16.220/protocol.json @@ -1,13 +1,19 @@ { "types": { "varint32": "varint", - "bool": "native", + "varint64": "native", "zigzag32": "native", "zigzag64": "native", "uuid": "native", "byterot": "native", - "MapInfo": "native", + "bitflags": "native", + "restBuffer": "native", + "encapsulated": "native", "nbt": "native", + "lnbt": "native", + "nbtLoop": "native", + "enum_size_based_on_values_len": "native", + "MapInfo": "native", "BehaviourPackInfos": [ "array", { diff --git a/data/1.17.0/protocol.json b/data/1.17.0/protocol.json index 941c0e5..68efe51 100644 --- a/data/1.17.0/protocol.json +++ b/data/1.17.0/protocol.json @@ -1,13 +1,18 @@ { "types": { - "varint32": "varint", - "bool": "native", + "varint64": "native", "zigzag32": "native", "zigzag64": "native", "uuid": "native", "byterot": "native", - "MapInfo": "native", + "bitflags": "native", + "restBuffer": "native", + "encapsulated": "native", "nbt": "native", + "lnbt": "native", + "nbtLoop": "native", + "enum_size_based_on_values_len": "native", + "MapInfo": "native", "BehaviourPackInfos": [ "array", { @@ -2259,7 +2264,7 @@ [ { "name": "item_id", - "type": "varint32" + "type": "varint" } ] ], @@ -2340,7 +2345,7 @@ }, { "name": "request_id", - "type": "varint32" + "type": "varint" }, { "anon": true, @@ -2388,7 +2393,7 @@ }, { "name": "item_stack_id", - "type": "varint32" + "type": "varint" }, { "name": "custom_name", @@ -5433,7 +5438,7 @@ "type": [ "mapper", { - "type": "varint32", + "type": "varint", "mappings": { "0": "normal", "1": "operator", diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 585c33c..bb2237d 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -4,21 +4,26 @@ !version: 1.17.0 # Some ProtoDef aliases -string: ["pstring",{"countType":"varint"}] +string: ["pstring",{"countType":"varint"}] # String / array types ByteArray: ["buffer",{"countType":"varint"}] SignedByteArray: ["buffer",{"countType":"zigzag32"}] LittleString: ["pstring",{"countType":"li32"}] ShortArray: ["buffer",{"countType":"li16"}] -varint32: varint -bool: native +varint64: native # Some primitives zigzag32: native zigzag64: native -uuid: native +uuid: native # Data types & special handling byterot: native +bitflags: native +restBuffer: native +encapsulated: native +nbt: native # NBT +lnbt: native +nbtLoop: native +enum_size_based_on_values_len: native # Packet-specific custom logic MapInfo: native -nbt: native -# load the packet map file +# load the packet map file (auto-generated) !import: packet_map.yml !StartDocs: Packets @@ -1088,7 +1093,7 @@ packet_adventure_settings: flags: AdventureFlags # CommandPermissionLevel is a permission level that specifies the kind of commands that the player is # allowed to use. - command_permission: varint32 => + command_permission: varint => 0: normal 1: operator 2: host diff --git a/data/latest/types.yaml b/data/latest/types.yaml index b18a577..b474e56 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -892,7 +892,7 @@ ItemStackRequest: if craft_creative: # The stack ID of the creative item that is being created. This is one of the # creative item stack IDs sent in the CreativeContent packet. - item_id: varint32 + item_id: varint if optional: # For the cartography table, if a certain MULTI recipe is being called, this points to the network ID that was assigned. recipe_network_id: varint @@ -918,7 +918,7 @@ ItemStackResponses: []varint 1: error # RequestID is the unique ID of the request that this response is in reaction to. If rejected, the client # will undo the actions from the request with this ID. - request_id: varint32 + request_id: varint _: status ? if ok: # ContainerInfo holds information on the containers that had their contents changed as a result of the @@ -939,7 +939,7 @@ ItemStackResponses: []varint # sent to the client. count: u8 # StackNetworkID is the network ID of the new stack at a specific slot. - item_stack_id: varint32 + item_stack_id: varint # CustomName is the custom name of the item stack. It is used in relation to text filtering. custom_name: string # DurabilityCorrection is the current durability of the item stack. This durability will be shown From 3f5c4ad12ebba6ef46f274b4a4aece47350cef63 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 18 Jun 2021 14:49:06 -0400 Subject: [PATCH 204/458] Relay proxy fixes, handle disconnect --- README.md | 4 +++- src/relay.js | 36 +++++++++++++----------------------- src/server.js | 2 +- src/serverPlayer.js | 4 +++- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 1218f51..89fab28 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,15 @@ Want to contribute on something important for PrismarineJS ? go to https://githu ### Client example +Example to connect to a server in offline mode, and relay chat messages back: + ```js const bedrock = require('bedrock-protocol') const client = bedrock.createClient({ host: 'localhost', // optional port: 19132, // optional, default 19132 username: 'Notch', // the username you want to join as, optional if online mode - offline: true // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. + offline: true, // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. // Optional for some servers which verify the title ID: // authTitle: bedrock.title.MinecraftNintendoSwitch }) diff --git a/src/relay.js b/src/relay.js index 0a382b4..de09353 100644 --- a/src/relay.js +++ b/src/relay.js @@ -37,13 +37,15 @@ class RelayPlayer extends Player { // Called when we get a packet from backend server (Backend -> PROXY -> Client) readUpstream (packet) { if (!this.startRelaying) { + this.upInLog('Client not ready, queueing packet until join') this.downQ.push(packet) return } - this.upInLog('->', packet) const des = this.server.deserializer.parsePacketBuffer(packet) const name = des.data.name const params = des.data.params + this.upInLog('->', name, params) + if (name === 'play_status' && params.status === 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect if (debugging) { // some packet encode/decode testing stuff @@ -51,31 +53,12 @@ class RelayPlayer extends Player { } this.emit('clientbound', des.data) - - // If we're sending a chunk, but player isn't yet initialized, wait until it is. - // This is wrong and should not be an issue to send chunks before the client - // is in the world; need to investigate further, but for now it's fine. - if (this.status !== 3) { - if (name === 'level_chunk') { - this.chunkSendCache.push([name, params]) - return - } - if (name === 'respawn') this.respawnPacket.push([name, params]) - } else if (this.status === 3 && this.chunkSendCache.length) { - for (const chunk of this.chunkSendCache) { - this.queue(...chunk) - } - for (const rp of this.respawnPacket) { - this.queue(...rp) - } - this.chunkSendCache = [] - this.respawnPacket = [] - } this.queue(name, params) } // Send queued packets to the connected client flushDownQueue () { + this.downOutLog('Flushing downstream queue') for (const packet of this.downQ) { const des = this.server.deserializer.parsePacketBuffer(packet) this.write(des.data.name, des.data.params) @@ -85,10 +68,11 @@ class RelayPlayer extends Player { // Send queued packets to the backend upstream server from the client flushUpQueue () { + this.upOutLog('Flushing upstream queue') for (const e of this.upQ) { // Send the queue const des = this.server.deserializer.parsePacketBuffer(e) if (des.data.name === 'client_cache_status') { // Currently broken, force off the chunk cache - this.upstream.write('client_cache_status', { enabled: false }) + // this.upstream.write('client_cache_status', { enabled: false }) } else { this.upstream.write(des.data.name, des.data.params) } @@ -127,7 +111,7 @@ class RelayPlayer extends Player { break case 'set_local_player_as_initialized': this.status = 3 - break + // falls through default: // Emit the packet as-is back to the upstream server this.downInLog('Relaying', des.data) @@ -137,6 +121,11 @@ class RelayPlayer extends Player { super.readPacket(packet) } } + + close (reason) { + this.upstream.close(reason) + super.close(reason) + } } class Relay extends Server { @@ -196,6 +185,7 @@ class Relay extends Server { this.conLog('dropping connection as single client relay', conn) conn.close() } else { + this.clientCount++ const player = new this.RelayPlayer(this, conn) this.conLog('New connection from', conn.address) this.clients[conn.address] = player diff --git a/src/server.js b/src/server.js index b10abd8..f8d3c87 100644 --- a/src/server.js +++ b/src/server.js @@ -46,7 +46,7 @@ class Server extends EventEmitter { onCloseConnection = (inetAddr, reason) => { this.conLog('close connection', inetAddr?.address, reason) delete this.clients[inetAddr]?.connection // Prevent close loop - this.clients[inetAddr]?.close() + this.clients[inetAddr?.address ?? inetAddr]?.close() delete this.clients[inetAddr] this.clientCount-- } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 7e638fe..c4d1ada 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -2,6 +2,7 @@ const { ClientStatus, Connection } = require('./connection') const fs = require('fs') const Options = require('./options') const debug = require('debug')('minecraft-protocol') +// const { serialize } = require('./datatypes/util') const { KeyExchange } = require('./handshake/keyExchange') const Login = require('./handshake/login') @@ -110,7 +111,7 @@ class Player extends Connection { close (reason) { if (this.status !== ClientStatus.Disconnected) { this.emit('close') // Emit close once - if (!reason) console.trace('Client closed connection', this.connection?.address) + if (!reason) this.inLog('Client closed connection', this.connection?.address) } this.q = [] this.q2 = [] @@ -130,6 +131,7 @@ class Player extends Connection { return } + // this.inLog(des.data.name, serialize(des.data.params).slice(0, 200)) switch (des.data.name) { case 'login': this.onLogin(des) From b546cda89975f0455885d22be614109ac8e66dff Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 18 Jun 2021 15:23:12 -0400 Subject: [PATCH 205/458] Logging improvements --- src/client.js | 6 ++++-- src/client/authFlow.js | 1 - src/connection.js | 10 ++++------ src/handshake/keyExchange.js | 1 - src/relay.js | 18 ++++++++++++++---- src/server.js | 3 --- src/serverPlayer.js | 31 +++++++++++++++---------------- 7 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/client.js b/src/client.js index 26d8662..3bf263e 100644 --- a/src/client.js +++ b/src/client.js @@ -35,8 +35,10 @@ class Client extends Connection { this.startGameData = {} this.clientRuntimeId = null - this.inLog = (...args) => debug('C ->', ...args) - this.outLog = (...args) => debug('C <-', ...args) + if (process.env.DEBUG.includes('minecraft-protocol')) { + this.inLog = (...args) => debug('C ->', ...args) + this.outLog = (...args) => debug('C <-', ...args) + } } connect () { diff --git a/src/client/authFlow.js b/src/client/authFlow.js index 1f67aa2..16c6c68 100644 --- a/src/client/authFlow.js +++ b/src/client/authFlow.js @@ -145,7 +145,6 @@ class MsAuthFlow { const token = await this.mca.getAccessToken(publicKey, xsts) // If we want to auth with a title ID, make sure there's a TitleID in the response const body = JSON.parse(Buffer.from(token.chain[1].split('.')[1], 'base64').toString()) - console.log(this.options.authTitle) if (!body.extraData.titleId && this.options.authTitle) { throw Error('missing titleId in response') } diff --git a/src/connection.js b/src/connection.js index bf08245..ce15507 100644 --- a/src/connection.js +++ b/src/connection.js @@ -22,6 +22,7 @@ class Connection extends EventEmitter { set status (val) { debug('* new status', val) + this.emit('status', val) this.#status = val } @@ -35,7 +36,7 @@ class Connection extends EventEmitter { startEncryption (iv) { this.encryptionEnabled = true - this.inLog('Started encryption', this.sharedSecret, iv) + this.inLog?.('Started encryption', this.sharedSecret, iv) this.decrypt = cipher.createDecryptor(this, iv) this.encrypt = cipher.createEncryptor(this, iv) } @@ -57,7 +58,7 @@ class Connection extends EventEmitter { } write (name, params) { - this.outLog('sending', name, params) + this.outLog?.(name, params) if (name === 'start_game') this.updateItemPalette(params.itemstates) const batch = new Framer() const packet = this.serializer.createPacketBuffer({ name, params }) @@ -71,7 +72,7 @@ class Connection extends EventEmitter { } queue (name, params) { - this.outLog('Q <- ', name, params) + this.outLog?.('Q <- ', name, params) if (name === 'start_game') this.updateItemPalette(params.itemstates) const packet = this.serializer.createPacketBuffer({ name, params }) if (name === 'level_chunk') { @@ -88,7 +89,6 @@ class Connection extends EventEmitter { this.loop = setInterval(() => { if (this.sendQ.length) { const batch = new Framer() - this.outLog('<- Batch', this.sendIds) batch.addEncodedPackets(this.sendQ) this.sendQ = [] this.sendIds = [] @@ -140,7 +140,6 @@ class Connection extends EventEmitter { // These are callbacks called from encryption.js onEncryptedPacket = (buf) => { - this.outLog('Enc buf', buf) const packet = Buffer.concat([Buffer.from([0xfe]), buf]) // add header this.sendMCPE(packet) @@ -160,7 +159,6 @@ class Connection extends EventEmitter { this.decrypt(buffer.slice(1)) } else { Framer.decode(buffer, packets => { - this.inLog('Reading ', packets.length, 'packets') for (const packet of packets) { this.readPacket(packet) } diff --git a/src/handshake/keyExchange.js b/src/handshake/keyExchange.js index e4dfe54..a732dc8 100644 --- a/src/handshake/keyExchange.js +++ b/src/handshake/keyExchange.js @@ -13,7 +13,6 @@ function KeyExchange (client, server, options) { client.ecdhKeyPair = crypto.generateKeyPairSync('ec', { namedCurve: curve }) client.publicKeyDER = client.ecdhKeyPair.publicKey.export(der) client.privateKeyPEM = client.ecdhKeyPair.privateKey.export(pem) - console.log(client.publicKeyPEM) client.clientX509 = client.publicKeyDER.toString('base64') function startClientboundEncryption (publicKey) { diff --git a/src/relay.js b/src/relay.js index de09353..b78662f 100644 --- a/src/relay.js +++ b/src/relay.js @@ -46,7 +46,7 @@ class RelayPlayer extends Player { const params = des.data.params this.upInLog('->', name, params) - if (name === 'play_status' && params.status === 'login_success') return // We already sent this, this needs to be sent ASAP or client will disconnect + if (name === 'play_status' && params.status === 'login_success') return // Already sent this, this needs to be sent ASAP or client will disconnect if (debugging) { // some packet encode/decode testing stuff this.server.deserializer.verify(des, this.server.serializer) @@ -71,8 +71,8 @@ class RelayPlayer extends Player { this.upOutLog('Flushing upstream queue') for (const e of this.upQ) { // Send the queue const des = this.server.deserializer.parsePacketBuffer(e) - if (des.data.name === 'client_cache_status') { // Currently broken, force off the chunk cache - // this.upstream.write('client_cache_status', { enabled: false }) + if (des.data.name === 'client_cache_status') { + // Currently not working, force off the chunk cache } else { this.upstream.write(des.data.name, des.data.params) } @@ -141,6 +141,12 @@ class Relay extends Server { this.conLog = debug } + // Called after a new player joins our proxy. We first create a new Client to connect to + // the remote server. Then we listen to soem events and proxy them over. The queue and + // flushing logic is more of an accessory to make sure the server or client recieves + // a packet, no matter what state it's in. For example, if the client wants to send a + // packet to the server but it's not connected, it will add to the queue and send as soon + // as a connection with the server is established. openUpstreamConnection (ds, clientAddr) { const client = new Client({ authTitle: this.options.authTitle, @@ -157,7 +163,7 @@ class Relay extends Server { this.conLog('Connecting to', this.options.destination.host, this.options.destination.port) client.outLog = ds.upOutLog client.inLog = ds.upInLog - client.once('join', () => { // Intercept once handshaking done + client.once('join', () => { // Tell the server to disable chunk cache for this connection as a client. // Wait a bit for the server to ack and process, the continue with proxying // otherwise the player can get stuck in an empty world. @@ -172,6 +178,7 @@ class Relay extends Server { this.upstreams.set(clientAddr.hash, client) } + // Close a connection to a remote backend server. closeUpstreamConnection (clientAddr) { const up = this.upstreams.get(clientAddr.hash) if (!up) throw Error(`unable to close non-open connection ${clientAddr.hash}`) @@ -180,6 +187,8 @@ class Relay extends Server { this.conLog('closed upstream connection', clientAddr) } + // Called when a new player connects to our proxy server. Once the player has authenticted, + // we can open an upstream connection to the backend server. onOpenConnection = (conn) => { if (this.forceSingle && this.clientCount > 0) { this.conLog('dropping connection as single client relay', conn) @@ -196,6 +205,7 @@ class Relay extends Server { } } + // When our server is closed, make sure to kick all of the connected clients and run emitters. close (...a) { for (const [, v] of this.upstreams) { v.close(...a) diff --git a/src/server.js b/src/server.js index f8d3c87..eb40a4e 100644 --- a/src/server.js +++ b/src/server.js @@ -19,8 +19,6 @@ class Server extends EventEmitter { /** @type {Object} */ this.clients = {} this.clientCount = 0 - this.inLog = (...args) => debug('S ->', ...args) - this.outLog = (...args) => debug('S <-', ...args) this.conLog = debug } @@ -52,7 +50,6 @@ class Server extends EventEmitter { } onEncapsulated = (buffer, address) => { - // this.inLog('encapsulated', address, buffer) const client = this.clients[address] if (!client) { throw new Error(`packet from unknown inet addr: ${address}`) diff --git a/src/serverPlayer.js b/src/serverPlayer.js index c4d1ada..954e86f 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -1,12 +1,11 @@ const { ClientStatus, Connection } = require('./connection') -const fs = require('fs') const Options = require('./options') -const debug = require('debug')('minecraft-protocol') -// const { serialize } = require('./datatypes/util') - +const { serialize } = require('./datatypes/util') const { KeyExchange } = require('./handshake/keyExchange') const Login = require('./handshake/login') const LoginVerify = require('./handshake/loginVerify') +const fs = require('fs') +const debug = require('debug')('minecraft-protocol') class Player extends Connection { constructor (server, connection) { @@ -23,8 +22,11 @@ class Player extends Connection { this.startQueue() this.status = ClientStatus.Authenticating - this.inLog = (...args) => debug('S ->', ...args) - this.outLog = (...args) => debug('S <-', ...args) + + if (process.env.DEBUG.includes('minecraft-protocol')) { + this.inLog = (...args) => debug('S ->', ...args) + this.outLog = (...args) => debug('S <-', ...args) + } } getUserData () { @@ -33,7 +35,6 @@ class Player extends Connection { onLogin (packet) { const body = packet.data - // debug('Login body', body) this.emit('loggingIn', body) const clientVer = body.protocol_version @@ -60,7 +61,6 @@ class Player extends Connection { this.disconnect('Server authentication error') return } - debug('Verified user pub key', key, userData) this.emit('server.client_handshake', { key }) // internal so we start encryption @@ -101,7 +101,6 @@ class Player extends Connection { // After sending Server to Client Handshake, this handles the client's // Client to Server handshake response. This indicates successful encryption onHandshake () { - // this.outLog('Sending login success!', this.status) // https://wiki.vg/Bedrock_Protocol#Play_Status this.write('play_status', { status: 'login_success' }) this.status = ClientStatus.Initializing @@ -111,7 +110,7 @@ class Player extends Connection { close (reason) { if (this.status !== ClientStatus.Disconnected) { this.emit('close') // Emit close once - if (!reason) this.inLog('Client closed connection', this.connection?.address) + if (!reason) this.inLog?.('Client closed connection', this.connection?.address) } this.q = [] this.q2 = [] @@ -126,12 +125,12 @@ class Player extends Connection { var des = this.server.deserializer.parsePacketBuffer(packet) // eslint-disable-line } catch (e) { this.disconnect('Server error') - console.warn('Packet parsing failed! Writing dump to ./packetdump.bin') - fs.writeFile('packetdump.bin', packet) + fs.writeFile(`packetdump_${this.connection.address}_${Date.now()}.bin`, packet) return } - // this.inLog(des.data.name, serialize(des.data.params).slice(0, 200)) + this.inLog?.(des.data.name, serialize(des.data.params).slice(0, 200)) + switch (des.data.name) { case 'login': this.onLogin(des) @@ -142,13 +141,13 @@ class Player extends Connection { break case 'set_local_player_as_initialized': this.status = ClientStatus.Initialized - this.inLog('Server client spawned') + this.inLog?.('Server client spawned') // Emit the 'spawn' event this.emit('spawn') break default: if (this.status === ClientStatus.Disconnected || this.status === ClientStatus.Authenticating) { - this.inLog('ignoring', des.data.name) + this.inLog?.('ignoring', des.data.name) return } } @@ -156,4 +155,4 @@ class Player extends Connection { } } -module.exports = { Player, ClientStatus } +module.exports = { Player } From 1cdb0e4c554d45c152f362858f79e07d27c672ed Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 20 Jun 2021 17:12:22 -0400 Subject: [PATCH 206/458] Update protodef version --- package.json | 2 +- src/client.js | 11 ++++++----- src/datatypes/util.js | 4 +++- src/serverPlayer.js | 4 ++-- src/transforms/framer.js | 2 +- src/transforms/serializer.js | 6 +++--- tools/compileProtocol.js | 2 +- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index f01299f..50e85f4 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", - "protodef-compiler-fix": "latest", + "protodef": "^1.14.0", "smart-buffer": "^4.1.0", "uuid-1345": "^1.0.2" }, diff --git a/src/client.js b/src/client.js index 3bf263e..068dce5 100644 --- a/src/client.js +++ b/src/client.js @@ -1,7 +1,7 @@ const { ClientStatus, Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { RakClient } = require('./rak') -const { serialize } = require('./datatypes/util') +const { serialize, isDebug } = require('./datatypes/util') const debug = require('debug')('minecraft-protocol') const Options = require('./options') const auth = require('./client/auth') @@ -35,7 +35,7 @@ class Client extends Connection { this.startGameData = {} this.clientRuntimeId = null - if (process.env.DEBUG.includes('minecraft-protocol')) { + if (isDebug) { this.inLog = (...args) => debug('C ->', ...args) this.outLog = (...args) => debug('C <-', ...args) } @@ -156,7 +156,7 @@ class Client extends Connection { readPacket (packet) { const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } - this.inLog('-> C', pakData.name, this.options.loggging ? serialize(pakData.params) : '') + this.inLog?.('-> C', pakData.name, this.options.loggging ? serialize(pakData.params) : '') this.emit('packet', des) if (debugging) { @@ -186,7 +186,7 @@ class Client extends Connection { break case 'play_status': if (this.status === ClientStatus.Authenticating) { - this.inLog('Server wants to skip encryption') + this.inLog?.('Server wants to skip encryption') this.emit('join') this.status = ClientStatus.Initializing } @@ -194,7 +194,8 @@ class Client extends Connection { break default: if (this.status !== ClientStatus.Initializing && this.status !== ClientStatus.Initialized) { - this.inLog(`Can't accept ${des.data.name}, client not yet authenticated : ${this.status}`) + // TODO: standardjs bug happens here with ?.(`something ${des.data.name}`) + if (this.inLog) this.inLog(`Can't accept ${des.data.name}, client not yet authenticated : ${this.status}`) return } } diff --git a/src/datatypes/util.js b/src/datatypes/util.js index b080577..4b29d57 100644 --- a/src/datatypes/util.js +++ b/src/datatypes/util.js @@ -43,4 +43,6 @@ function nextUUID () { return uuidFrom(Date.now().toString()) } -module.exports = { getFiles, sleep, waitFor, serialize, uuidFrom, nextUUID } +const isDebug = process.env.DEBUG?.includes('minecraft-protocol') + +module.exports = { getFiles, sleep, waitFor, serialize, uuidFrom, nextUUID, isDebug } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 954e86f..52693b8 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -1,6 +1,6 @@ const { ClientStatus, Connection } = require('./connection') const Options = require('./options') -const { serialize } = require('./datatypes/util') +const { serialize, isDebug } = require('./datatypes/util') const { KeyExchange } = require('./handshake/keyExchange') const Login = require('./handshake/login') const LoginVerify = require('./handshake/loginVerify') @@ -23,7 +23,7 @@ class Player extends Connection { this.startQueue() this.status = ClientStatus.Authenticating - if (process.env.DEBUG.includes('minecraft-protocol')) { + if (isDebug) { this.inLog = (...args) => debug('S ->', ...args) this.outLog = (...args) => debug('S <-', ...args) } diff --git a/src/transforms/framer.js b/src/transforms/framer.js index aa1b496..77f41e9 100644 --- a/src/transforms/framer.js +++ b/src/transforms/framer.js @@ -1,4 +1,4 @@ -const [readVarInt, writeVarInt, sizeOfVarInt] = require('protodef-compiler-fix').types.varint +const [readVarInt, writeVarInt, sizeOfVarInt] = require('protodef').types.varint const zlib = require('zlib') // Concatenates packets into one batch packet, and adds length prefixs. diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 2900cf3..4a6102f 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -1,5 +1,5 @@ -const { ProtoDefCompiler, CompiledProtodef } = require('protodef-compiler-fix').Compiler -const { FullPacketParser, Serializer } = require('protodef-compiler-fix') +const { ProtoDefCompiler, CompiledProtodef } = require('protodef').Compiler +const { FullPacketParser, Serializer } = require('protodef') const { join } = require('path') class Parser extends FullPacketParser { @@ -43,7 +43,7 @@ function getProtocol (version) { compiler.addTypes(require(join(__dirname, '../datatypes/compiler-minecraft'))) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) - global.PartialReadError = require('protodef-compiler-fix/src/utils').PartialReadError + global.PartialReadError = require('protodef/src/utils').PartialReadError const compile = (compiler, file) => require(file)(compiler.native) return new CompiledProtodef( diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index c89cb28..bed7b2c 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -6,7 +6,7 @@ * */ const fs = require('fs') -const { ProtoDefCompiler } = require('protodef-compiler-fix').Compiler +const { ProtoDefCompiler } = require('protodef').Compiler const { Versions } = require('../src/options') const { join } = require('path') From 987bf43987b021dcee216f31e3ee5709f4800b09 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 14 Jul 2021 17:30:10 -0400 Subject: [PATCH 207/458] 1.17.10 protocol support (#109) * 1.17.10 support * add protocol.json * add extra particle IDs --- README.md | 4 +- data/1.17.10/protocol.json | 9081 +++++++++++++++++++++++++++++++ data/latest/proto.yml | 134 +- data/latest/types.yaml | 2 + examples/serverReadmeExample.js | 2 +- src/options.js | 3 +- 6 files changed, 9217 insertions(+), 9 deletions(-) create mode 100644 data/1.17.10/protocol.json diff --git a/README.md b/README.md index 89fab28..765491a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This is a work in progress. You can track the progress in https://github.com/Pri ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md) @@ -69,7 +69,7 @@ const bedrock = require('bedrock-protocol') const server = new bedrock.createServer({ host: '0.0.0.0', // optional. host to bind as. port: 19132, // optional - version: '1.16.220', // optional. The server version, latest if not specified. + version: '1.17.10', // optional. The server version, latest if not specified. }) server.on('connect', client => { diff --git a/data/1.17.10/protocol.json b/data/1.17.10/protocol.json new file mode 100644 index 0000000..1fcbc86 --- /dev/null +++ b/data/1.17.10/protocol.json @@ -0,0 +1,9081 @@ +{ + "types": { + "varint64": "native", + "zigzag32": "native", + "zigzag64": "native", + "uuid": "native", + "byterot": "native", + "bitflags": "native", + "restBuffer": "native", + "encapsulated": "native", + "nbt": "native", + "lnbt": "native", + "nbtLoop": "native", + "enum_size_based_on_values_len": "native", + "MapInfo": "native", + "BehaviourPackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + } + ] + ] + } + ], + "TexturePackInfos": [ + "array", + { + "countType": "li16", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "content_key", + "type": "string" + }, + { + "name": "sub_pack_name", + "type": "string" + }, + { + "name": "content_identity", + "type": "string" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "rtx_enabled", + "type": "bool" + } + ] + ] + } + ], + "ResourcePackIdVersions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "uuid", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "ResourcePackIds": [ + "array", + { + "countType": "li16", + "type": "string" + } + ], + "Experiment": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "enabled", + "type": "bool" + } + ] + ], + "Experiments": [ + "array", + { + "countType": "li32", + "type": "Experiment" + } + ], + "GameMode": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "survival", + "1": "creative", + "2": "adventure", + "3": "survival_spectator", + "4": "creative_spectator", + "5": "fallback" + } + } + ], + "GameRule": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "editable", + "type": "bool" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "bool", + "2": "int", + "3": "float" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "bool": "bool", + "int": "zigzag32", + "float": "lf32" + }, + "default": "void" + } + ] + } + ] + ], + "GameRules": [ + "array", + { + "countType": "varint", + "type": "GameRule" + } + ], + "Blob": [ + "container", + [ + { + "name": "hash", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "BlockProperties": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "state", + "type": "nbt" + } + ] + ] + } + ], + "Itemstates": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "runtime_id", + "type": "li16" + }, + { + "name": "component_based", + "type": "bool" + } + ] + ] + } + ], + "ItemExtraDataWithBlockingTick": [ + "container", + [ + { + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "false", + "65535": "true" + } + } + ] + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "true": [ + "container", + [ + { + "name": "version", + "type": "u8" + }, + { + "name": "nbt", + "type": "lnbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "blocking_tick", + "type": "li64" + } + ] + ], + "ItemExtraDataWithoutBlockingTick": [ + "container", + [ + { + "name": "has_nbt", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "0": "false", + "65535": "true" + } + } + ] + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "has_nbt", + "fields": { + "true": [ + "container", + [ + { + "name": "version", + "type": "u8" + }, + { + "name": "nbt", + "type": "lnbt" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "can_place_on", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + }, + { + "name": "can_destroy", + "type": [ + "array", + { + "countType": "li32", + "type": "ShortArray" + } + ] + } + ] + ], + "ItemLegacy": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "count", + "type": "lu16" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "block_runtime_id", + "type": "zigzag32" + }, + { + "name": "extra", + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "/ShieldItemID": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithBlockingTick" + } + ] + }, + "default": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithoutBlockingTick" + } + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "Item": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "count", + "type": "lu16" + }, + { + "name": "metadata", + "type": "varint" + }, + { + "name": "has_stack_id", + "type": "u8" + }, + { + "name": "stack_id", + "type": [ + "switch", + { + "compareTo": "has_stack_id", + "fields": { + "0": "void" + }, + "default": "zigzag32" + } + ] + }, + { + "name": "block_runtime_id", + "type": "zigzag32" + }, + { + "name": "extra", + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "/ShieldItemID": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithBlockingTick" + } + ] + }, + "default": [ + "encapsulated", + { + "lengthType": "varint", + "type": "ItemExtraDataWithoutBlockingTick" + } + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "vec3i": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "vec3u": [ + "container", + [ + { + "name": "x", + "type": "varint" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "varint" + } + ] + ], + "vec3f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "y", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "vec2f": [ + "container", + [ + { + "name": "x", + "type": "lf32" + }, + { + "name": "z", + "type": "lf32" + } + ] + ], + "MetadataDictionary": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "key", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "flags", + "1": "health", + "2": "variant", + "3": "color", + "4": "nametag", + "5": "owner_eid", + "6": "target_eid", + "7": "air", + "8": "potion_color", + "9": "potion_ambient", + "10": "jump_duration", + "11": "hurt_time", + "12": "hurt_direction", + "13": "paddle_time_left", + "14": "paddle_time_right", + "15": "experience_value", + "16": "minecart_display_block", + "17": "minecart_display_offset", + "18": "minecart_has_display", + "20": "old_swell", + "21": "swell_dir", + "22": "charge_amount", + "23": "enderman_held_runtime_id", + "24": "entity_age", + "26": "player_flags", + "27": "player_index", + "28": "player_bed_position", + "29": "fireball_power_x", + "30": "fireball_power_y", + "31": "fireball_power_z", + "32": "aux_power", + "33": "fish_x", + "34": "fish_z", + "35": "fish_angle", + "36": "potion_aux_value", + "37": "lead_holder_eid", + "38": "scale", + "39": "interactive_tag", + "40": "npc_skin_id", + "41": "url_tag", + "42": "max_airdata_max_air", + "43": "mark_variant", + "44": "container_type", + "45": "container_base_size", + "46": "container_extra_slots_per_strength", + "47": "block_target", + "48": "wither_invulnerable_ticks", + "49": "wither_target_1", + "50": "wither_target_2", + "51": "wither_target_3", + "52": "aerial_attack", + "53": "boundingbox_width", + "54": "boundingbox_height", + "55": "fuse_length", + "56": "rider_seat_position", + "57": "rider_rotation_locked", + "58": "rider_max_rotation", + "59": "rider_min_rotation", + "60": "rider_rotation_offset", + "61": "area_effect_cloud_radius", + "62": "area_effect_cloud_waiting", + "63": "area_effect_cloud_particle_id", + "64": "shulker_peek_id", + "65": "shulker_attach_face", + "66": "shulker_attached", + "67": "shulker_attach_pos", + "68": "trading_player_eid", + "69": "trading_career", + "70": "has_command_block", + "71": "command_block_command", + "72": "command_block_last_output", + "73": "command_block_track_output", + "74": "controlling_rider_seat_number", + "75": "strength", + "76": "max_strength", + "77": "spell_casting_color", + "78": "limited_life", + "79": "armor_stand_pose_index", + "80": "ender_crystal_time_offset", + "81": "always_show_nametag", + "82": "color_2", + "83": "name_author", + "84": "score_tag", + "85": "balloon_attached_entity", + "86": "pufferfish_size", + "87": "bubble_time", + "88": "agent", + "89": "sitting_amount", + "90": "sitting_amount_previous", + "91": "eating_counter", + "92": "flags_extended", + "93": "laying_amount", + "94": "laying_amount_previous", + "95": "duration", + "96": "spawn_time", + "97": "change_rate", + "98": "change_on_pickup", + "99": "pickup_count", + "100": "interact_text", + "101": "trade_tier", + "102": "max_trade_tier", + "103": "trade_experience", + "104": "skin_id", + "105": "spawning_frames", + "106": "command_block_tick_delay", + "107": "command_block_execute_on_first_tick", + "108": "ambient_sound_interval", + "109": "ambient_sound_interval_range", + "110": "ambient_sound_event_name", + "111": "fall_damage_multiplier", + "112": "name_raw_text", + "113": "can_ride_target", + "114": "low_tier_cured_discount", + "115": "high_tier_cured_discount", + "116": "nearby_cured_discount", + "117": "nearby_cured_discount_timestamp", + "118": "hitbox", + "119": "is_buoyant", + "120": "base_runtime_id", + "121": "freezing_effect_strength", + "122": "buoyancy_data", + "123": "goat_horn_count", + "124": "update_properties" + } + } + ] + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "byte", + "1": "short", + "2": "int", + "3": "float", + "4": "string", + "5": "compound", + "6": "vec3i", + "7": "long", + "8": "vec3f" + } + } + ] + }, + { + "name": "value", + "type": [ + "switch", + { + "compareTo": "key", + "fields": { + "flags": "MetadataFlags1", + "flags_extended": "MetadataFlags2" + }, + "default": [ + "switch", + { + "compareTo": "type", + "fields": { + "byte": "i8", + "short": "li16", + "int": "zigzag32", + "float": "lf32", + "string": "string", + "compound": "nbt", + "vec3i": "vec3i", + "long": "zigzag64", + "vec3f": "vec3f" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ], + "Link": [ + "container", + [ + { + "name": "ridden_entity_id", + "type": "zigzag64" + }, + { + "name": "rider_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "immediate", + "type": "bool" + }, + { + "name": "rider_initiated", + "type": "bool" + } + ] + ], + "Links": [ + "array", + { + "countType": "varint", + "type": "Link" + } + ], + "EntityAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "min", + "type": "lf32" + }, + { + "name": "value", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + } + ] + ] + } + ], + "Rotation": [ + "container", + [ + { + "name": "yaw", + "type": "byterot" + }, + { + "name": "pitch", + "type": "byterot" + }, + { + "name": "head_yaw", + "type": "byterot" + } + ] + ], + "BlockCoordinates": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "varint" + }, + { + "name": "z", + "type": "zigzag32" + } + ] + ], + "PlayerAttributes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "min", + "type": "lf32" + }, + { + "name": "max", + "type": "lf32" + }, + { + "name": "current", + "type": "lf32" + }, + { + "name": "default", + "type": "lf32" + }, + { + "name": "name", + "type": "string" + } + ] + ] + } + ], + "TransactionUseItem": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "click_block", + "1": "click_air", + "2": "break_block" + } + } + ] + }, + { + "name": "block_position", + "type": "vec3i" + }, + { + "name": "face", + "type": "varint" + }, + { + "name": "hotbar_slot", + "type": "varint" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + }, + { + "name": "block_runtime_id", + "type": "varint" + } + ] + ], + "TransactionActions": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "source_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "container", + "1": "global", + "2": "world_interaction", + "3": "creative", + "100": "craft_slot", + "99999": "craft" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "source_type", + "fields": { + "container": [ + "container", + [ + { + "name": "inventory_id", + "type": "WindowIDVarint" + } + ] + ], + "craft": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ], + "world_interaction": [ + "container", + [ + { + "name": "flags", + "type": "varint" + } + ] + ], + "craft_slot": [ + "container", + [ + { + "name": "action", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "old_item", + "type": "Item" + }, + { + "name": "new_item", + "type": "Item" + } + ] + ] + } + ], + "TransactionLegacy": [ + "container", + [ + { + "name": "legacy_request_id", + "type": "zigzag32" + }, + { + "name": "legacy_transactions", + "type": [ + "switch", + { + "compareTo": "legacy_request_id", + "fields": { + "0": "void" + }, + "default": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "container_id", + "type": "u8" + }, + { + "name": "changed_slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_id", + "type": "u8" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + } + ] + ], + "Transaction": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "transaction_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "inventory_mismatch", + "2": "item_use", + "3": "item_use_on_entity", + "4": "item_release" + } + } + ] + }, + { + "name": "actions", + "type": "TransactionActions" + }, + { + "name": "transaction_data", + "type": [ + "switch", + { + "compareTo": "transaction_type", + "fields": { + "normal": "void", + "inventory_mismatch": "void", + "item_use": "TransactionUseItem", + "item_use_on_entity": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "interact", + "1": "attack" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "player_pos", + "type": "vec3f" + }, + { + "name": "click_pos", + "type": "vec3f" + } + ] + ], + "item_release": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "release", + "1": "consume" + } + } + ] + }, + { + "name": "hotbar_slot", + "type": "zigzag32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "head_pos", + "type": "vec3f" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "ItemStacks": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ], + "RecipeIngredient": [ + "container", + [ + { + "name": "network_id", + "type": "zigzag32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "network_id", + "fields": { + "0": "void" + }, + "default": [ + "container", + [ + { + "name": "network_data", + "type": "zigzag32" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ], + "PotionTypeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "input_item_meta", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "ingredient_meta", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + }, + { + "name": "output_item_meta", + "type": "zigzag32" + } + ] + ] + } + ], + "PotionContainerChangeRecipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "input_item_id", + "type": "zigzag32" + }, + { + "name": "ingredient_id", + "type": "zigzag32" + }, + { + "name": "output_item_id", + "type": "zigzag32" + } + ] + ] + } + ], + "Recipes": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "shapeless", + "1": "shaped", + "2": "furnace", + "3": "furnace_with_metadata", + "4": "multi", + "5": "shulker_box", + "6": "shapeless_chemistry", + "7": "shaped_chemistry" + } + } + ] + }, + { + "name": "recipe", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "shapeless": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shulker_box": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shapeless_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "RecipeIngredient" + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shaped": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "shaped_chemistry": [ + "container", + [ + { + "name": "recipe_id", + "type": "string" + }, + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "input", + "type": [ + "array", + { + "count": "width", + "type": [ + "array", + { + "count": "height", + "type": "RecipeIngredient" + } + ] + } + ] + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "block", + "type": "string" + }, + { + "name": "priority", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ], + "furnace": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "output", + "type": "ItemLegacy" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "furnace_with_metadata": [ + "container", + [ + { + "name": "input_id", + "type": "zigzag32" + }, + { + "name": "input_meta", + "type": "zigzag32" + }, + { + "name": "output", + "type": "ItemLegacy" + }, + { + "name": "block", + "type": "string" + } + ] + ], + "multi": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "network_id", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ], + "SkinImage": [ + "container", + [ + { + "name": "width", + "type": "li32" + }, + { + "name": "height", + "type": "li32" + }, + { + "name": "data", + "type": "ByteArray" + } + ] + ], + "Skin": [ + "container", + [ + { + "name": "skin_id", + "type": "string" + }, + { + "name": "play_fab_id", + "type": "string" + }, + { + "name": "skin_resource_pack", + "type": "string" + }, + { + "name": "skin_data", + "type": "SkinImage" + }, + { + "name": "animations", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "skin_image", + "type": "SkinImage" + }, + { + "name": "animation_type", + "type": "li32" + }, + { + "name": "animation_frames", + "type": "lf32" + }, + { + "name": "expression_type", + "type": "lf32" + } + ] + ] + } + ] + }, + { + "name": "cape_data", + "type": "SkinImage" + }, + { + "name": "geometry_data", + "type": "string" + }, + { + "name": "animation_data", + "type": "string" + }, + { + "name": "premium", + "type": "bool" + }, + { + "name": "persona", + "type": "bool" + }, + { + "name": "cape_on_classic", + "type": "bool" + }, + { + "name": "cape_id", + "type": "string" + }, + { + "name": "full_skin_id", + "type": "string" + }, + { + "name": "arm_size", + "type": "string" + }, + { + "name": "skin_color", + "type": "string" + }, + { + "name": "personal_pieces", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_id", + "type": "string" + }, + { + "name": "piece_type", + "type": "string" + }, + { + "name": "pack_id", + "type": "string" + }, + { + "name": "is_default_piece", + "type": "bool" + }, + { + "name": "product_id", + "type": "string" + } + ] + ] + } + ] + }, + { + "name": "piece_tint_colors", + "type": [ + "array", + { + "countType": "li32", + "type": [ + "container", + [ + { + "name": "piece_type", + "type": "string" + }, + { + "name": "colors", + "type": [ + "array", + { + "countType": "li32", + "type": "string" + } + ] + } + ] + ] + } + ] + } + ] + ], + "PlayerRecords": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "remove" + } + } + ] + }, + { + "name": "records_count", + "type": "varint" + }, + { + "name": "records", + "type": [ + "array", + { + "count": "records_count", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "xbox_user_id", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "build_platform", + "type": "li32" + }, + { + "name": "skin_data", + "type": "Skin" + }, + { + "name": "is_teacher", + "type": "bool" + }, + { + "name": "is_host", + "type": "bool" + } + ] + ], + "remove": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + }, + { + "name": "verified", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "add": [ + "array", + { + "count": "records_count", + "type": "bool" + } + ] + }, + "default": "void" + } + ] + } + ] + ], + "Enchant": [ + "container", + [ + { + "name": "id", + "type": "u8" + }, + { + "name": "level", + "type": "u8" + } + ] + ], + "EnchantOption": [ + "container", + [ + { + "name": "cost", + "type": "varint" + }, + { + "name": "slot_flags", + "type": "li32" + }, + { + "name": "equip_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "held_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "self_enchants", + "type": [ + "array", + { + "countType": "varint", + "type": "Enchant" + } + ] + }, + { + "name": "name", + "type": "string" + }, + { + "name": "option_id", + "type": "zigzag32" + } + ] + ], + "Action": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "start_break", + "1": "abort_break", + "2": "stop_break", + "3": "get_updated_block", + "4": "drop_item", + "5": "start_sleeping", + "6": "stop_sleeping", + "7": "respawn", + "8": "jump", + "9": "start_sprint", + "10": "stop_sprint", + "11": "start_sneak", + "12": "stop_sneak", + "13": "creative_player_destroy_block", + "14": "dimension_change_ack", + "15": "start_glide", + "16": "stop_glide", + "17": "build_denied", + "18": "crack_break", + "19": "change_skin", + "20": "set_enchatnment_seed", + "21": "swimming", + "22": "stop_swimming", + "23": "start_spin_attack", + "24": "stop_spin_attack", + "25": "interact_block", + "26": "predict_break", + "27": "continue_break" + } + } + ], + "StackRequestSlotInfo": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "stack_id", + "type": "zigzag32" + } + ] + ], + "ItemStackRequest": [ + "container", + [ + { + "name": "request_id", + "type": "varint" + }, + { + "name": "actions", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "type_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "take", + "1": "place", + "2": "swap", + "3": "drop", + "4": "destroy", + "5": "consume", + "6": "create", + "7": "lab_table_combine", + "8": "beacon_payment", + "9": "mine_block", + "10": "craft_recipe", + "11": "craft_recipe_auto", + "12": "craft_creative", + "13": "optional", + "14": "non_implemented", + "15": "results_deprecated" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type_id", + "fields": { + "take": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "place": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "swap": [ + "container", + [ + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "destination", + "type": "StackRequestSlotInfo" + } + ] + ], + "drop": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + }, + { + "name": "randomly", + "type": "bool" + } + ] + ], + "destroy": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "consume": [ + "container", + [ + { + "name": "count", + "type": "u8" + }, + { + "name": "source", + "type": "StackRequestSlotInfo" + } + ] + ], + "create": [ + "container", + [ + { + "name": "result_slot_id", + "type": "u8" + } + ] + ], + "beacon_payment": [ + "container", + [ + { + "name": "primary_effect", + "type": "zigzag32" + }, + { + "name": "secondary_effect", + "type": "zigzag32" + } + ] + ], + "mine_block": [ + "container", + [ + { + "name": "unknown1", + "type": "zigzag32" + }, + { + "name": "predicted_durability", + "type": "zigzag32" + }, + { + "name": "network_id", + "type": "zigzag32" + } + ] + ], + "craft_recipe": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_recipe_auto": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + } + ] + ], + "craft_creative": [ + "container", + [ + { + "name": "item_id", + "type": "varint" + } + ] + ], + "optional": [ + "container", + [ + { + "name": "recipe_network_id", + "type": "varint" + }, + { + "name": "filtered_string_index", + "type": "li32" + } + ] + ], + "non_implemented": "void", + "results_deprecated": [ + "container", + [ + { + "name": "result_items", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemLegacy" + } + ] + }, + { + "name": "times_crafted", + "type": "u8" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + { + "name": "custom_names", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "ItemStackResponses": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "ok", + "1": "error" + } + } + ] + }, + { + "name": "request_id", + "type": "varint" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "status", + "fields": { + "ok": [ + "container", + [ + { + "name": "containers", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot_type", + "type": "ContainerSlotType" + }, + { + "name": "slots", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "slot", + "type": "u8" + }, + { + "name": "hotbar_slot", + "type": "u8" + }, + { + "name": "count", + "type": "u8" + }, + { + "name": "item_stack_id", + "type": "varint" + }, + { + "name": "custom_name", + "type": "string" + }, + { + "name": "durability_correction", + "type": "zigzag32" + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ], + "ItemComponentList": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ] + } + ], + "CommandOrigin": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "player", + "1": "block", + "2": "minecart_block", + "3": "dev_console", + "4": "test", + "5": "automation_player", + "6": "client_automation", + "7": "dedicated_server", + "8": "entity", + "9": "virtual", + "10": "game_argument", + "11": "entity_server", + "12": "precompiled", + "13": "game_director_entity_server", + "14": "script" + } + } + ] + }, + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "request_id", + "type": "string" + }, + { + "name": "player_entity_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "dev_console": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ], + "test": [ + "container", + [ + { + "name": "player_entity_id", + "type": "zigzag64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "TrackedObject": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "entity", + "1": "block" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "block_position", + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "block": "BlockCoordinates" + }, + "default": "void" + } + ] + } + ] + ], + "MapDecoration": [ + "container", + [ + { + "name": "type", + "type": "u8" + }, + { + "name": "rotation", + "type": "u8" + }, + { + "name": "x", + "type": "u8" + }, + { + "name": "y", + "type": "u8" + }, + { + "name": "label", + "type": "string" + }, + { + "name": "color_abgr", + "type": "varint" + } + ] + ], + "StructureBlockSettings": [ + "container", + [ + { + "name": "palette_name", + "type": "string" + }, + { + "name": "ignore_entities", + "type": "bool" + }, + { + "name": "ignore_blocks", + "type": "bool" + }, + { + "name": "size", + "type": "BlockCoordinates" + }, + { + "name": "structure_offset", + "type": "BlockCoordinates" + }, + { + "name": "last_editing_player_unique_id", + "type": "zigzag64" + }, + { + "name": "rotation", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "90_deg", + "2": "180_deg", + "3": "270_deg" + } + } + ] + }, + { + "name": "mirror", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "x_axis", + "2": "z_axis", + "3": "both_axes" + } + } + ] + }, + { + "name": "animation_mode", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "layers", + "2": "blocks" + } + } + ] + }, + { + "name": "animation_duration", + "type": "lf32" + }, + { + "name": "integrity", + "type": "lf32" + }, + { + "name": "seed", + "type": "lu32" + }, + { + "name": "pivot", + "type": "vec3f" + } + ] + ], + "WindowID": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], + "WindowIDVarint": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "inventory", + "1": "first", + "100": "last", + "119": "offhand", + "120": "armor", + "121": "creative", + "122": "hotbar", + "123": "fixed_inventory", + "124": "ui", + "-100": "drop_contents", + "-24": "beacon", + "-23": "trading_output", + "-22": "trading_use_inputs", + "-21": "trading_input_2", + "-20": "trading_input_1", + "-17": "enchant_output", + "-16": "enchant_material", + "-15": "enchant_input", + "-13": "anvil_output", + "-12": "anvil_result", + "-11": "anvil_material", + "-10": "container_input", + "-5": "crafting_use_ingredient", + "-4": "crafting_result", + "-3": "crafting_remove_ingredient", + "-2": "crafting_add_ingredient", + "-1": "none" + } + } + ], + "WindowType": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "container", + "1": "workbench", + "2": "furnace", + "3": "enchantment", + "4": "brewing_stand", + "5": "anvil", + "6": "dispenser", + "7": "dropper", + "8": "hopper", + "9": "cauldron", + "10": "minecart_chest", + "11": "minecart_hopper", + "12": "horse", + "13": "beacon", + "14": "structure_editor", + "15": "trading", + "16": "command_block", + "17": "jukebox", + "18": "armor", + "19": "hand", + "20": "compound_creator", + "21": "element_constructor", + "22": "material_reducer", + "23": "lab_table", + "24": "loom", + "25": "lectern", + "26": "grindstone", + "27": "blast_furnace", + "28": "smoker", + "29": "stonecutter", + "30": "cartography", + "31": "hud", + "32": "jigsaw_editor", + "33": "smithing_table", + "-9": "none", + "-1": "inventory" + } + } + ], + "ContainerSlotType": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "anvil_input", + "1": "anvil_material", + "2": "anvil_result", + "3": "smithing_table_input", + "4": "smithing_table_material", + "5": "smithing_table_result", + "6": "armor", + "7": "container", + "8": "beacon_payment", + "9": "brewing_input", + "10": "brewing_result", + "11": "brewing_fuel", + "12": "hotbar_and_inventory", + "13": "crafting_input", + "14": "crafting_output", + "15": "recipe_construction", + "16": "recipe_nature", + "17": "recipe_items", + "18": "recipe_search", + "19": "recipe_search_bar", + "20": "recipe_equipment", + "21": "enchanting_input", + "22": "enchanting_lapis", + "23": "furnace_fuel", + "24": "furnace_ingredient", + "25": "furnace_output", + "26": "horse_equip", + "27": "hotbar", + "28": "inventory", + "29": "shulker", + "30": "trade_ingredient1", + "31": "trade_ingredient2", + "32": "trade_result", + "33": "offhand", + "34": "compcreate_input", + "35": "compcreate_output", + "36": "elemconstruct_output", + "37": "matreduce_input", + "38": "matreduce_output", + "39": "labtable_input", + "40": "loom_input", + "41": "loom_dye", + "42": "loom_material", + "43": "loom_result", + "44": "blast_furnace_ingredient", + "45": "smoker_ingredient", + "46": "trade2_ingredient1", + "47": "trade2_ingredient2", + "48": "trade2_result", + "49": "grindstone_input", + "50": "grindstone_additional", + "51": "grindstone_result", + "52": "stonecutter_input", + "53": "stonecutter_result", + "54": "cartography_input", + "55": "cartography_additional", + "56": "cartography_result", + "57": "barrel", + "58": "cursor", + "59": "creative_output" + } + } + ], + "SoundType": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "ItemUseOn", + "1": "Hit", + "2": "Step", + "3": "Fly", + "4": "Jump", + "5": "Break", + "6": "Place", + "7": "HeavyStep", + "8": "Gallop", + "9": "Fall", + "10": "Ambient", + "11": "AmbientBaby", + "12": "AmbientInWater", + "13": "Breathe", + "14": "Death", + "15": "DeathInWater", + "16": "DeathToZombie", + "17": "Hurt", + "18": "HurtInWater", + "19": "Mad", + "20": "Boost", + "21": "Bow", + "22": "SquishBig", + "23": "SquishSmall", + "24": "FallBig", + "25": "FallSmall", + "26": "Splash", + "27": "Fizz", + "28": "Flap", + "29": "Swim", + "30": "Drink", + "31": "Eat", + "32": "Takeoff", + "33": "Shake", + "34": "Plop", + "35": "Land", + "36": "Saddle", + "37": "Armor", + "38": "MobArmorStandPlace", + "39": "AddChest", + "40": "Throw", + "41": "Attack", + "42": "AttackNoDamage", + "43": "AttackStrong", + "44": "Warn", + "45": "Shear", + "46": "Milk", + "47": "Thunder", + "48": "Explode", + "49": "Fire", + "50": "Ignite", + "51": "Fuse", + "52": "Stare", + "53": "Spawn", + "54": "Shoot", + "55": "BreakBlock", + "56": "Launch", + "57": "Blast", + "58": "LargeBlast", + "59": "Twinkle", + "60": "Remedy", + "61": "Infect", + "62": "LevelUp", + "63": "BowHit", + "64": "BulletHit", + "65": "ExtinguishFire", + "66": "ItemFizz", + "67": "ChestOpen", + "68": "ChestClosed", + "69": "ShulkerBoxOpen", + "70": "ShulkerBoxClosed", + "71": "EnderChestOpen", + "72": "EnderChestClosed", + "73": "PowerOn", + "74": "PowerOff", + "75": "Attach", + "76": "Detach", + "77": "Deny", + "78": "Tripod", + "79": "Pop", + "80": "DropSlot", + "81": "Note", + "82": "Thorns", + "83": "PistonIn", + "84": "PistonOut", + "85": "Portal", + "86": "Water", + "87": "LavaPop", + "88": "Lava", + "89": "Burp", + "90": "BucketFillWater", + "91": "BucketFillLava", + "92": "BucketEmptyWater", + "93": "BucketEmptyLava", + "94": "ArmorEquipChain", + "95": "ArmorEquipDiamond", + "96": "ArmorEquipGeneric", + "97": "ArmorEquipGold", + "98": "ArmorEquipIron", + "99": "ArmorEquipLeather", + "100": "ArmorEquipElytra", + "101": "Record13", + "102": "RecordCat", + "103": "RecordBlocks", + "104": "RecordChirp", + "105": "RecordFar", + "106": "RecordMall", + "107": "RecordMellohi", + "108": "RecordStal", + "109": "RecordStrad", + "110": "RecordWard", + "111": "Record11", + "112": "RecordWait", + "113": "unknown1", + "114": "Flop", + "115": "ElderGuardianCurse", + "116": "MobWarning", + "117": "MobWarningBaby", + "118": "Teleport", + "119": "ShulkerOpen", + "120": "ShulkerClose", + "121": "Haggle", + "122": "HaggleYes", + "123": "HaggleNo", + "124": "HaggleIdle", + "125": "ChorusGrow", + "126": "ChorusDeath", + "127": "Glass", + "128": "PotionBrewed", + "129": "CastSpell", + "130": "PrepareAttack", + "131": "PrepareSummon", + "132": "PrepareWololo", + "133": "Fang", + "134": "Charge", + "135": "CameraTakePicture", + "136": "LeashKnotPlace", + "137": "LeashKnotBreak", + "138": "Growl", + "139": "Whine", + "140": "Pant", + "141": "Purr", + "142": "Purreow", + "143": "DeathMinVolume", + "144": "DeathMidVolume", + "145": "unknown2", + "146": "ImitateCaveSpider", + "147": "ImitateCreeper", + "148": "ImitateElderGuardian", + "149": "ImitateEnderDragon", + "150": "ImitateEnderman", + "151": "unknown3", + "152": "ImitateEvocationIllager", + "153": "ImitateGhast", + "154": "ImitateHusk", + "155": "ImitateIllusionIllager", + "156": "ImitateMagmaCube", + "157": "ImitatePolarBear", + "158": "ImitateShulker", + "159": "ImitateSilverfish", + "160": "ImitateSkeleton", + "161": "ImitateSlime", + "162": "ImitateSpider", + "163": "ImitateStray", + "164": "ImitateVex", + "165": "ImitateVindicationIllager", + "166": "ImitateWitch", + "167": "ImitateWither", + "168": "ImitateWitherSkeleton", + "169": "ImitateWolf", + "170": "ImitateZombie", + "171": "ImitateZombiePigman", + "172": "ImitateZombieVillager", + "173": "BlockEndPortalFrameFill", + "174": "BlockEndPortalSpawn", + "175": "RandomAnvilUse", + "176": "BottleDragonBreath", + "177": "PortalTravel", + "178": "ItemTridentHit", + "179": "ItemTridentReturn", + "180": "ItemTridentRiptide1", + "181": "ItemTridentRiptide2", + "182": "ItemTridentRiptide3", + "183": "ItemTridentThrow", + "184": "ItemTridentThunder", + "185": "ItemTridentHitGround", + "186": "Default", + "187": "BlockFletchingTableUse", + "188": "ElemConstructOpen", + "189": "IceBombHit", + "190": "BalloonPop", + "191": "LtReactionIceBomb", + "192": "LtReactionBleach", + "193": "LtReactionEPaste", + "194": "LtReactionEPaste2", + "195": "LtReactionFertilizer", + "196": "LtReactionFireball", + "197": "LtReactionMgsalt", + "198": "LtReactionMiscfire", + "199": "LtReactionFire", + "200": "LtReactionMiscexplosion", + "201": "LtReactionMiscmystical", + "202": "LtReactionMiscmystical2", + "203": "LtReactionProduct", + "204": "SparklerUse", + "205": "GlowstickUse", + "206": "SparklerActive", + "207": "ConvertToDrowned", + "208": "BucketFillFish", + "209": "BucketEmptyFish", + "210": "BubbleUp", + "211": "BubbleDown", + "212": "BubblePop", + "213": "BubbleUpInside", + "214": "BubbleDownInside", + "215": "HurtBaby", + "216": "DeathBaby", + "217": "StepBaby", + "218": "BabySpawn", + "219": "Born", + "220": "BlockTurtleEggBreak", + "221": "BlockTurtleEggCrack", + "222": "BlockTurtleEggHatch", + "223": "TurtleLayEgg", + "224": "BlockTurtleEggAttack", + "225": "BeaconActivate", + "226": "BeaconAmbient", + "227": "BeaconDeactivate", + "228": "BeaconPower", + "229": "ConduitActivate", + "230": "ConduitAmbient", + "231": "ConduitAttack", + "232": "ConduitDeactivate", + "233": "ConduitShort", + "234": "Swoop", + "235": "BlockBambooSaplingPlace", + "236": "PreSneeze", + "237": "Sneeze", + "238": "AmbientTame", + "239": "Scared", + "240": "BlockScaffoldingClimb", + "241": "CrossbowLoadingStart", + "242": "CrossbowLoadingMiddle", + "243": "CrossbowLoadingEnd", + "244": "CrossbowShoot", + "245": "CrossbowQuickChargeStart", + "246": "CrossbowQuickChargeMiddle", + "247": "CrossbowQuickChargeEnd", + "248": "AmbientAggressive", + "249": "AmbientWorried", + "250": "CantBreed", + "251": "ItemShieldBlock", + "252": "ItemBookPut", + "253": "BlockGrindstoneUse", + "254": "BlockBellHit", + "255": "BlockCampfireCrackle", + "256": "Roar", + "257": "Stun", + "258": "BlockSweetBerryBushHurt", + "259": "BlockSweetBerryBushPick", + "260": "UICartographyTableTakeResult", + "261": "UIStoneCutterTakeResult", + "262": "BlockComposterEmpty", + "263": "BlockComposterFill", + "264": "BlockComposterFillSuccess", + "265": "BlockComposterReady", + "266": "BlockBarrelOpen", + "267": "BlockBarrelClose", + "268": "RaidHorn", + "269": "BlockLoomUse", + "270": "AmbientRaid", + "271": "UICartographyTableUse", + "272": "UIStoneCutterUse", + "273": "UILoomUse", + "274": "SmokerUse", + "275": "BlastFurnaceUse", + "276": "SmithingTableUse", + "277": "Screech", + "278": "Sleep", + "279": "FurnaceUse", + "280": "MooshroomConvert", + "281": "MilkSuspiciously", + "282": "Celebrate", + "283": "JumpPrevent", + "284": "AmbientPollinate", + "285": "BeeHiveDrip", + "286": "BeeHiveEnter", + "287": "BeeHiveExit", + "288": "BeeHiveWork", + "289": "BeeHiveShear", + "290": "HoneyBottleDrink", + "291": "AmbientCave", + "292": "Retreat", + "293": "ConvertToZombified", + "294": "Admire", + "295": "StepLava", + "296": "Tempt", + "297": "Panic", + "298": "Angry", + "299": "AmbientWarpedForest", + "300": "AmbientSoulsandValley", + "301": "AmbientNetherWastes", + "302": "AmbientBasaltDeltas", + "303": "AmbientCrimsonForest", + "304": "RespawnAnchorCharge", + "305": "RespawnAnchorDeplete", + "306": "RespawnAnchorSetSpawn", + "307": "RespawnAnchorAmbient", + "308": "SoulEscapeQuiet", + "309": "SoulEscapeLoud", + "310": "RecordPigstep", + "311": "LinkCompassToLodestone", + "312": "BlockSmithingTableUse", + "313": "EquipNetherite", + "314": "AmbientLoopWarpedForest", + "315": "AmbientLoopSoulsandValley", + "316": "AmbientLoopNetherWastes", + "317": "AmbientLoopBasaltDeltas", + "318": "AmbientLoopCrimsonForest", + "319": "AmbientAdditionWarpedForest", + "320": "AmbientAdditionSoulsandValley", + "321": "AmbientAdditionNetherWastes", + "322": "AmbientAdditionBasaltDeltas", + "323": "AmbientAdditionCrimsonForest", + "324": "SculkSensorPowerOn", + "325": "SculkSensorPowerOff", + "326": "BucketFillPowderSnow", + "327": "BucketEmptyPowderSnow", + "328": "PointedDripstoneCauldronDripWater", + "329": "PointedDripstoneCauldronDripLava", + "330": "PointedDripstoneDripWater", + "331": "PointedDripstoneDripLava", + "332": "CaveVinesPickBerries", + "333": "BigDripleafTiltDown", + "334": "BigDripleafTiltUp", + "335": "unknown335", + "336": "unknown336", + "337": "unknown337", + "338": "unknown338", + "339": "copper_wax_on", + "340": "copper_wax_off", + "341": "scrape", + "342": "player_hurt_drown", + "343": "player_hurt_on_fire", + "344": "player_hurt_freeze", + "345": "use_spyglass", + "346": "stop_using_spyglass", + "347": "amethyst_block_chime", + "348": "ambient_screamer", + "349": "hurt_screamer", + "350": "death_screamer", + "351": "milk_screamer", + "352": "jump_to_block", + "353": "pre_ram", + "354": "pre_ram_screamer", + "355": "ram_impact", + "356": "ram_impact_screamer", + "357": "squid_ink_squirt", + "358": "glow_squid_ink_squirt", + "359": "convert_to_stray", + "360": "extinguish_candle", + "361": "ambient_candle", + "362": "Undefined" + } + } + ], + "LegacyEntityType": [ + "mapper", + { + "type": "li32", + "mappings": { + "10": "chicken", + "11": "cow", + "12": "pig", + "13": "sheep", + "14": "wolf", + "15": "villager", + "16": "mooshroom", + "17": "squid", + "18": "rabbit", + "19": "bat", + "20": "iron_golem", + "21": "snow_golem", + "22": "ocelot", + "23": "horse", + "24": "donkey", + "25": "mule", + "26": "skeleton_horse", + "27": "zombie_horse", + "28": "polar_bear", + "29": "llama", + "30": "parrot", + "31": "dolphin", + "32": "zombie", + "33": "creeper", + "34": "skeleton", + "35": "spider", + "36": "zombie_pigman", + "37": "slime", + "38": "enderman", + "39": "silverfish", + "40": "cave_spider", + "41": "ghast", + "42": "magma_cube", + "43": "blaze", + "44": "zombie_villager", + "45": "witch", + "46": "stray", + "47": "husk", + "48": "wither_skeleton", + "49": "guardian", + "50": "elder_guardian", + "51": "npc", + "52": "wither", + "53": "ender_dragon", + "54": "shulker", + "55": "endermite", + "56": "agent", + "57": "vindicator", + "58": "phantom", + "61": "armor_stand", + "62": "tripod_camera", + "63": "player", + "64": "item", + "65": "tnt", + "66": "falling_block", + "67": "moving_block", + "68": "xp_bottle", + "69": "xp_orb", + "70": "eye_of_ender_signal", + "71": "ender_crystal", + "72": "fireworks_rocket", + "73": "thrown_trident", + "74": "turtle", + "75": "cat", + "76": "shulker_bullet", + "77": "fishing_hook", + "78": "chalkboard", + "79": "dragon_fireball", + "80": "arrow", + "81": "snowball", + "82": "egg", + "83": "painting", + "84": "minecart", + "85": "fireball", + "86": "splash_potion", + "87": "ender_pearl", + "88": "leash_knot", + "89": "wither_skull", + "90": "boat", + "91": "wither_skull_dangerous", + "93": "lightning_bolt", + "94": "small_fireball", + "95": "area_effect_cloud", + "96": "hopper_minecart", + "97": "tnt_minecart", + "98": "chest_minecart", + "100": "command_block_minecart", + "101": "lingering_potion", + "102": "llama_spit", + "103": "evocation_fang", + "104": "evocation_illager", + "105": "vex", + "106": "ice_bomb", + "107": "balloon", + "108": "pufferfish", + "109": "salmon", + "110": "drowned", + "111": "tropicalfish", + "112": "cod", + "113": "panda" + } + } + ], + "mcpe_packet": [ + "container", + [ + { + "name": "name", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "1": "login", + "2": "play_status", + "3": "server_to_client_handshake", + "4": "client_to_server_handshake", + "5": "disconnect", + "6": "resource_packs_info", + "7": "resource_pack_stack", + "8": "resource_pack_client_response", + "9": "text", + "10": "set_time", + "11": "start_game", + "12": "add_player", + "13": "add_entity", + "14": "remove_entity", + "15": "add_item_entity", + "17": "take_item_entity", + "18": "move_entity", + "19": "move_player", + "20": "rider_jump", + "21": "update_block", + "22": "add_painting", + "23": "tick_sync", + "24": "level_sound_event_old", + "25": "level_event", + "26": "block_event", + "27": "entity_event", + "28": "mob_effect", + "29": "update_attributes", + "30": "inventory_transaction", + "31": "mob_equipment", + "32": "mob_armor_equipment", + "33": "interact", + "34": "block_pick_request", + "35": "entity_pick_request", + "36": "player_action", + "38": "hurt_armor", + "39": "set_entity_data", + "40": "set_entity_motion", + "41": "set_entity_link", + "42": "set_health", + "43": "set_spawn_position", + "44": "animate", + "45": "respawn", + "46": "container_open", + "47": "container_close", + "48": "player_hotbar", + "49": "inventory_content", + "50": "inventory_slot", + "51": "container_set_data", + "52": "crafting_data", + "53": "crafting_event", + "54": "gui_data_pick_item", + "55": "adventure_settings", + "56": "block_entity_data", + "57": "player_input", + "58": "level_chunk", + "59": "set_commands_enabled", + "60": "set_difficulty", + "61": "change_dimension", + "62": "set_player_game_type", + "63": "player_list", + "64": "simple_event", + "65": "event", + "66": "spawn_experience_orb", + "67": "clientbound_map_item_data", + "68": "map_info_request", + "69": "request_chunk_radius", + "70": "chunk_radius_update", + "71": "item_frame_drop_item", + "72": "game_rules_changed", + "73": "camera", + "74": "boss_event", + "75": "show_credits", + "76": "available_commands", + "77": "command_request", + "78": "command_block_update", + "79": "command_output", + "80": "update_trade", + "81": "update_equipment", + "82": "resource_pack_data_info", + "83": "resource_pack_chunk_data", + "84": "resource_pack_chunk_request", + "85": "transfer", + "86": "play_sound", + "87": "stop_sound", + "88": "set_title", + "89": "add_behavior_tree", + "90": "structure_block_update", + "91": "show_store_offer", + "92": "purchase_receipt", + "93": "player_skin", + "94": "sub_client_login", + "95": "initiate_web_socket_connection", + "96": "set_last_hurt_by", + "97": "book_edit", + "98": "npc_request", + "99": "photo_transfer", + "100": "modal_form_request", + "101": "modal_form_response", + "102": "server_settings_request", + "103": "server_settings_response", + "104": "show_profile", + "105": "set_default_game_type", + "106": "remove_objective", + "107": "set_display_objective", + "108": "set_score", + "109": "lab_table", + "110": "update_block_synced", + "111": "move_entity_delta", + "112": "set_scoreboard_identity", + "113": "set_local_player_as_initialized", + "114": "update_soft_enum", + "115": "network_stack_latency", + "117": "script_custom_event", + "118": "spawn_particle_effect", + "119": "available_entity_identifiers", + "120": "level_sound_event_v2", + "121": "network_chunk_publisher_update", + "122": "biome_definition_list", + "123": "level_sound_event", + "124": "level_event_generic", + "125": "lectern_update", + "126": "video_stream_connect", + "127": "add_ecs_entity", + "128": "remove_ecs_entity", + "129": "client_cache_status", + "130": "on_screen_texture_animation", + "131": "map_create_locked_copy", + "132": "structure_template_data_export_request", + "133": "structure_template_data_export_response", + "134": "update_block_properties", + "135": "client_cache_blob_status", + "136": "client_cache_miss_response", + "137": "education_settings", + "139": "multiplayer_settings", + "140": "settings_command", + "141": "anvil_damage", + "142": "completed_using_item", + "143": "network_settings", + "144": "player_auth_input", + "145": "creative_content", + "146": "player_enchant_options", + "147": "item_stack_request", + "148": "item_stack_response", + "149": "player_armor_damage", + "151": "update_player_game_type", + "153": "position_tracking_db_broadcast", + "154": "position_tracking_db_request", + "156": "packet_violation_warning", + "157": "motion_prediction_hints", + "158": "animate_entity", + "159": "camera_shake", + "160": "player_fog", + "161": "correct_player_move_prediction", + "162": "item_component", + "163": "filter_text_packet", + "164": "debug_renderer", + "165": "sync_entity_property", + "166": "add_volume_entity", + "167": "remove_volume_entity", + "168": "simulation_type", + "169": "npc_dialogue" + } + } + ] + }, + { + "name": "params", + "type": [ + "switch", + { + "compareTo": "name", + "fields": { + "login": "packet_login", + "play_status": "packet_play_status", + "server_to_client_handshake": "packet_server_to_client_handshake", + "client_to_server_handshake": "packet_client_to_server_handshake", + "disconnect": "packet_disconnect", + "resource_packs_info": "packet_resource_packs_info", + "resource_pack_stack": "packet_resource_pack_stack", + "resource_pack_client_response": "packet_resource_pack_client_response", + "text": "packet_text", + "set_time": "packet_set_time", + "start_game": "packet_start_game", + "add_player": "packet_add_player", + "add_entity": "packet_add_entity", + "remove_entity": "packet_remove_entity", + "add_item_entity": "packet_add_item_entity", + "take_item_entity": "packet_take_item_entity", + "move_entity": "packet_move_entity", + "move_player": "packet_move_player", + "rider_jump": "packet_rider_jump", + "update_block": "packet_update_block", + "add_painting": "packet_add_painting", + "tick_sync": "packet_tick_sync", + "level_sound_event_old": "packet_level_sound_event_old", + "level_event": "packet_level_event", + "block_event": "packet_block_event", + "entity_event": "packet_entity_event", + "mob_effect": "packet_mob_effect", + "update_attributes": "packet_update_attributes", + "inventory_transaction": "packet_inventory_transaction", + "mob_equipment": "packet_mob_equipment", + "mob_armor_equipment": "packet_mob_armor_equipment", + "interact": "packet_interact", + "block_pick_request": "packet_block_pick_request", + "entity_pick_request": "packet_entity_pick_request", + "player_action": "packet_player_action", + "hurt_armor": "packet_hurt_armor", + "set_entity_data": "packet_set_entity_data", + "set_entity_motion": "packet_set_entity_motion", + "set_entity_link": "packet_set_entity_link", + "set_health": "packet_set_health", + "set_spawn_position": "packet_set_spawn_position", + "animate": "packet_animate", + "respawn": "packet_respawn", + "container_open": "packet_container_open", + "container_close": "packet_container_close", + "player_hotbar": "packet_player_hotbar", + "inventory_content": "packet_inventory_content", + "inventory_slot": "packet_inventory_slot", + "container_set_data": "packet_container_set_data", + "crafting_data": "packet_crafting_data", + "crafting_event": "packet_crafting_event", + "gui_data_pick_item": "packet_gui_data_pick_item", + "adventure_settings": "packet_adventure_settings", + "block_entity_data": "packet_block_entity_data", + "player_input": "packet_player_input", + "level_chunk": "packet_level_chunk", + "set_commands_enabled": "packet_set_commands_enabled", + "set_difficulty": "packet_set_difficulty", + "change_dimension": "packet_change_dimension", + "set_player_game_type": "packet_set_player_game_type", + "player_list": "packet_player_list", + "simple_event": "packet_simple_event", + "event": "packet_event", + "spawn_experience_orb": "packet_spawn_experience_orb", + "clientbound_map_item_data": "packet_clientbound_map_item_data", + "map_info_request": "packet_map_info_request", + "request_chunk_radius": "packet_request_chunk_radius", + "chunk_radius_update": "packet_chunk_radius_update", + "item_frame_drop_item": "packet_item_frame_drop_item", + "game_rules_changed": "packet_game_rules_changed", + "camera": "packet_camera", + "boss_event": "packet_boss_event", + "show_credits": "packet_show_credits", + "available_commands": "packet_available_commands", + "command_request": "packet_command_request", + "command_block_update": "packet_command_block_update", + "command_output": "packet_command_output", + "update_trade": "packet_update_trade", + "update_equipment": "packet_update_equipment", + "resource_pack_data_info": "packet_resource_pack_data_info", + "resource_pack_chunk_data": "packet_resource_pack_chunk_data", + "resource_pack_chunk_request": "packet_resource_pack_chunk_request", + "transfer": "packet_transfer", + "play_sound": "packet_play_sound", + "stop_sound": "packet_stop_sound", + "set_title": "packet_set_title", + "add_behavior_tree": "packet_add_behavior_tree", + "structure_block_update": "packet_structure_block_update", + "show_store_offer": "packet_show_store_offer", + "purchase_receipt": "packet_purchase_receipt", + "player_skin": "packet_player_skin", + "sub_client_login": "packet_sub_client_login", + "initiate_web_socket_connection": "packet_initiate_web_socket_connection", + "set_last_hurt_by": "packet_set_last_hurt_by", + "book_edit": "packet_book_edit", + "npc_request": "packet_npc_request", + "photo_transfer": "packet_photo_transfer", + "modal_form_request": "packet_modal_form_request", + "modal_form_response": "packet_modal_form_response", + "server_settings_request": "packet_server_settings_request", + "server_settings_response": "packet_server_settings_response", + "show_profile": "packet_show_profile", + "set_default_game_type": "packet_set_default_game_type", + "remove_objective": "packet_remove_objective", + "set_display_objective": "packet_set_display_objective", + "set_score": "packet_set_score", + "lab_table": "packet_lab_table", + "update_block_synced": "packet_update_block_synced", + "move_entity_delta": "packet_move_entity_delta", + "set_scoreboard_identity": "packet_set_scoreboard_identity", + "set_local_player_as_initialized": "packet_set_local_player_as_initialized", + "update_soft_enum": "packet_update_soft_enum", + "network_stack_latency": "packet_network_stack_latency", + "script_custom_event": "packet_script_custom_event", + "spawn_particle_effect": "packet_spawn_particle_effect", + "available_entity_identifiers": "packet_available_entity_identifiers", + "level_sound_event_v2": "packet_level_sound_event_v2", + "network_chunk_publisher_update": "packet_network_chunk_publisher_update", + "biome_definition_list": "packet_biome_definition_list", + "level_sound_event": "packet_level_sound_event", + "level_event_generic": "packet_level_event_generic", + "lectern_update": "packet_lectern_update", + "video_stream_connect": "packet_video_stream_connect", + "add_ecs_entity": "packet_add_ecs_entity", + "remove_ecs_entity": "packet_remove_ecs_entity", + "client_cache_status": "packet_client_cache_status", + "on_screen_texture_animation": "packet_on_screen_texture_animation", + "map_create_locked_copy": "packet_map_create_locked_copy", + "structure_template_data_export_request": "packet_structure_template_data_export_request", + "structure_template_data_export_response": "packet_structure_template_data_export_response", + "update_block_properties": "packet_update_block_properties", + "client_cache_blob_status": "packet_client_cache_blob_status", + "client_cache_miss_response": "packet_client_cache_miss_response", + "education_settings": "packet_education_settings", + "multiplayer_settings": "packet_multiplayer_settings", + "settings_command": "packet_settings_command", + "anvil_damage": "packet_anvil_damage", + "completed_using_item": "packet_completed_using_item", + "network_settings": "packet_network_settings", + "player_auth_input": "packet_player_auth_input", + "creative_content": "packet_creative_content", + "player_enchant_options": "packet_player_enchant_options", + "item_stack_request": "packet_item_stack_request", + "item_stack_response": "packet_item_stack_response", + "player_armor_damage": "packet_player_armor_damage", + "update_player_game_type": "packet_update_player_game_type", + "position_tracking_db_request": "packet_position_tracking_db_request", + "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", + "packet_violation_warning": "packet_packet_violation_warning", + "motion_prediction_hints": "packet_motion_prediction_hints", + "animate_entity": "packet_animate_entity", + "camera_shake": "packet_camera_shake", + "player_fog": "packet_player_fog", + "correct_player_move_prediction": "packet_correct_player_move_prediction", + "item_component": "packet_item_component", + "filter_text_packet": "packet_filter_text_packet", + "debug_renderer": "packet_debug_renderer", + "sync_entity_property": "packet_sync_entity_property", + "add_volume_entity": "packet_add_volume_entity", + "remove_volume_entity": "packet_remove_volume_entity", + "simulation_type": "packet_simulation_type", + "npc_dialogue": "packet_npc_dialogue" + }, + "default": "void" + } + ] + } + ] + ], + "packet_login": [ + "container", + [ + { + "name": "protocol_version", + "type": "i32" + }, + { + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] + ], + "LoginTokens": [ + "container", + [ + { + "name": "identity", + "type": "LittleString" + }, + { + "name": "client", + "type": "LittleString" + } + ] + ], + "packet_play_status": [ + "container", + [ + { + "name": "status", + "type": [ + "mapper", + { + "type": "i32", + "mappings": { + "0": "login_success", + "1": "failed_client", + "2": "failed_spawn", + "3": "player_spawn", + "4": "failed_invalid_tenant", + "5": "failed_vanilla_edu", + "6": "failed_edu_vanilla", + "7": "failed_server_full" + } + } + ] + } + ] + ], + "packet_server_to_client_handshake": [ + "container", + [ + { + "name": "token", + "type": "string" + } + ] + ], + "packet_client_to_server_handshake": [ + "container", + [] + ], + "packet_disconnect": [ + "container", + [ + { + "name": "hide_disconnect_reason", + "type": "bool" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "packet_resource_packs_info": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "has_scripts", + "type": "bool" + }, + { + "name": "behaviour_packs", + "type": "BehaviourPackInfos" + }, + { + "name": "texture_packs", + "type": "TexturePackInfos" + }, + { + "name": "force_server_packs", + "type": "bool" + } + ] + ], + "packet_resource_pack_stack": [ + "container", + [ + { + "name": "must_accept", + "type": "bool" + }, + { + "name": "behavior_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "resource_packs", + "type": "ResourcePackIdVersions" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + } + ] + ], + "packet_resource_pack_client_response": [ + "container", + [ + { + "name": "response_status", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "none", + "1": "refused", + "2": "send_packs", + "3": "have_all_packs", + "4": "completed" + } + } + ] + }, + { + "name": "resourcepackids", + "type": "ResourcePackIds" + } + ] + ], + "packet_text": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "raw", + "1": "chat", + "2": "translation", + "3": "popup", + "4": "jukebox_popup", + "5": "tip", + "6": "system", + "7": "whisper", + "8": "announcement", + "9": "json_whisper", + "10": "json" + } + } + ] + }, + { + "name": "needs_translation", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "chat": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "whisper": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "announcement": [ + "container", + [ + { + "name": "source_name", + "type": "string" + }, + { + "name": "message", + "type": "string" + } + ] + ], + "raw": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "tip": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "system": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json_whisper": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "json": [ + "container", + [ + { + "name": "message", + "type": "string" + } + ] + ], + "translation": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "jukebox_popup": [ + "container", + [ + { + "name": "message", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "xuid", + "type": "string" + }, + { + "name": "platform_chat_id", + "type": "string" + } + ] + ], + "packet_set_time": [ + "container", + [ + { + "name": "time", + "type": "zigzag32" + } + ] + ], + "packet_start_game": [ + "container", + [ + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "player_gamemode", + "type": "GameMode" + }, + { + "name": "player_position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "vec2f" + }, + { + "name": "seed", + "type": "zigzag32" + }, + { + "name": "biome_type", + "type": "li16" + }, + { + "name": "biome_name", + "type": "string" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "generator", + "type": "zigzag32" + }, + { + "name": "world_gamemode", + "type": "GameMode" + }, + { + "name": "difficulty", + "type": "zigzag32" + }, + { + "name": "spawn_position", + "type": "BlockCoordinates" + }, + { + "name": "achievements_disabled", + "type": "bool" + }, + { + "name": "day_cycle_stop_time", + "type": "zigzag32" + }, + { + "name": "edu_offer", + "type": "zigzag32" + }, + { + "name": "edu_features_enabled", + "type": "bool" + }, + { + "name": "edu_product_uuid", + "type": "string" + }, + { + "name": "rain_level", + "type": "lf32" + }, + { + "name": "lightning_level", + "type": "lf32" + }, + { + "name": "has_confirmed_platform_locked_content", + "type": "bool" + }, + { + "name": "is_multiplayer", + "type": "bool" + }, + { + "name": "broadcast_to_lan", + "type": "bool" + }, + { + "name": "xbox_live_broadcast_mode", + "type": "varint" + }, + { + "name": "platform_broadcast_mode", + "type": "varint" + }, + { + "name": "enable_commands", + "type": "bool" + }, + { + "name": "is_texturepacks_required", + "type": "bool" + }, + { + "name": "gamerules", + "type": "GameRules" + }, + { + "name": "experiments", + "type": "Experiments" + }, + { + "name": "experiments_previously_used", + "type": "bool" + }, + { + "name": "bonus_chest", + "type": "bool" + }, + { + "name": "map_enabled", + "type": "bool" + }, + { + "name": "permission_level", + "type": "zigzag32" + }, + { + "name": "server_chunk_tick_range", + "type": "li32" + }, + { + "name": "has_locked_behavior_pack", + "type": "bool" + }, + { + "name": "has_locked_resource_pack", + "type": "bool" + }, + { + "name": "is_from_locked_world_template", + "type": "bool" + }, + { + "name": "msa_gamertags_only", + "type": "bool" + }, + { + "name": "is_from_world_template", + "type": "bool" + }, + { + "name": "is_world_template_option_locked", + "type": "bool" + }, + { + "name": "only_spawn_v1_villagers", + "type": "bool" + }, + { + "name": "game_version", + "type": "string" + }, + { + "name": "limited_world_width", + "type": "li32" + }, + { + "name": "limited_world_length", + "type": "li32" + }, + { + "name": "is_new_nether", + "type": "bool" + }, + { + "name": "experimental_gameplay_override", + "type": "bool" + }, + { + "name": "level_id", + "type": "string" + }, + { + "name": "world_name", + "type": "string" + }, + { + "name": "premium_world_template_id", + "type": "string" + }, + { + "name": "is_trial", + "type": "bool" + }, + { + "name": "movement_authority", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "client", + "1": "server", + "2": "server_with_rewind" + } + } + ] + }, + { + "name": "rewind_history_size", + "type": "zigzag32" + }, + { + "name": "server_authoritative_block_breaking", + "type": "bool" + }, + { + "name": "current_tick", + "type": "li64" + }, + { + "name": "enchantment_seed", + "type": "zigzag32" + }, + { + "name": "block_properties", + "type": "BlockProperties" + }, + { + "name": "itemstates", + "type": "Itemstates" + }, + { + "name": "multiplayer_correlation_id", + "type": "string" + }, + { + "name": "server_authoritative_inventory", + "type": "bool" + }, + { + "name": "engine", + "type": "string" + } + ] + ], + "packet_add_player": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "username", + "type": "string" + }, + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "platform_chat_id", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "held_item", + "type": "Item" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "flags", + "type": "varint" + }, + { + "name": "command_permission", + "type": "varint" + }, + { + "name": "action_permissions", + "type": "varint" + }, + { + "name": "permission_level", + "type": "varint" + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + }, + { + "name": "links", + "type": "Links" + }, + { + "name": "device_id", + "type": "string" + }, + { + "name": "device_os", + "type": "li32" + } + ] + ], + "packet_add_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "attributes", + "type": "EntityAttributes" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "links", + "type": "Links" + } + ] + ], + "packet_remove_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + } + ] + ], + "packet_add_item_entity": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "is_from_fishing", + "type": "bool" + } + ] + ], + "packet_take_item_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "target", + "type": "varint" + } + ] + ], + "packet_move_entity": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "flags", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "rotation", + "type": "Rotation" + } + ] + ], + "packet_move_player": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "mode", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "normal", + "1": "reset", + "2": "teleport", + "3": "rotation" + } + } + ] + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "ridden_runtime_id", + "type": "varint" + }, + { + "name": "teleport", + "type": [ + "switch", + { + "compareTo": "mode", + "fields": { + "teleport": [ + "container", + [ + { + "name": "cause", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "unknown", + "1": "projectile", + "2": "chorus_fruit", + "3": "command", + "4": "behavior" + } + } + ] + }, + { + "name": "source_entity_type", + "type": "LegacyEntityType" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_rider_jump": [ + "container", + [ + { + "name": "jump_strength", + "type": "zigzag32" + } + ] + ], + "packet_update_block": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + } + ] + ], + "packet_add_painting": [ + "container", + [ + { + "name": "entity_id_self", + "type": "zigzag64" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "coordinates", + "type": "vec3f" + }, + { + "name": "direction", + "type": "zigzag32" + }, + { + "name": "title", + "type": "string" + } + ] + ], + "packet_tick_sync": [ + "container", + [ + { + "name": "request_time", + "type": "li64" + }, + { + "name": "response_time", + "type": "li64" + } + ] + ], + "packet_level_sound_event_old": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "zigzag32" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event": [ + "container", + [ + { + "name": "event", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "1000": "sound_click", + "1001": "sound_click_fail", + "1002": "sound_shoot", + "1003": "sound_door", + "1004": "sound_fizz", + "1005": "sound_ignite", + "1007": "sound_ghast", + "1008": "sound_ghast_shoot", + "1009": "sound_blaze_shoot", + "1010": "sound_door_bump", + "1012": "sound_door_crash", + "1018": "sound_enderman_teleport", + "1020": "sound_anvil_break", + "1021": "sound_anvil_use", + "1022": "sound_anvil_fall", + "1030": "sound_pop", + "1032": "sound_portal", + "1040": "sound_itemframe_add_item", + "1041": "sound_itemframe_remove", + "1042": "sound_itemframe_place", + "1043": "sound_itemframe_remove_item", + "1044": "sound_itemframe_rotate_item", + "1050": "sound_camera", + "1051": "sound_orb", + "1052": "sound_totem", + "1060": "sound_armor_stand_break", + "1061": "sound_armor_stand_hit", + "1062": "sound_armor_stand_fall", + "1063": "sound_armor_stand_place", + "1064": "pointed_dripstone_land", + "1065": "dye_used", + "1066": "ink_sack_used", + "2000": "particle_shoot", + "2001": "particle_destroy", + "2002": "particle_splash", + "2003": "particle_eye_despawn", + "2004": "particle_spawn", + "2005": "particle_crop_growth", + "2006": "particle_guardian_curse", + "2007": "particle_death_smoke", + "2008": "particle_block_force_field", + "2009": "particle_projectile_hit", + "2010": "particle_dragon_egg_teleport", + "2011": "particle_crop_eaten", + "2012": "particle_critical", + "2013": "particle_enderman_teleport", + "2014": "particle_punch_block", + "2015": "particle_bubble", + "2016": "particle_evaporate", + "2017": "particle_destroy_armor_stand", + "2018": "particle_breaking_egg", + "2019": "particle_destroy_egg", + "2020": "particle_evaporate_water", + "2021": "particle_destroy_block_no_sound", + "2022": "particle_knockback_roar", + "2023": "particle_teleport_trail", + "2024": "particle_point_cloud", + "2025": "particle_explosion", + "2026": "particle_block_explosion", + "2027": "particle_vibration_signal", + "2028": "particle_dripstone_drip", + "2029": "particle_fizz_effect", + "2030": "particle_wax_on", + "2031": "particle_wax_off", + "2032": "particle_scrape", + "2033": "particle_electric_spark", + "3001": "start_rain", + "3002": "start_thunder", + "3003": "stop_rain", + "3004": "stop_thunder", + "3005": "pause_game", + "3006": "pause_game_no_screen", + "3007": "set_game_speed", + "3500": "redstone_trigger", + "3501": "cauldron_explode", + "3502": "cauldron_dye_armor", + "3503": "cauldron_clean_armor", + "3504": "cauldron_fill_potion", + "3505": "cauldron_take_potion", + "3506": "cauldron_fill_water", + "3507": "cauldron_take_water", + "3508": "cauldron_add_dye", + "3509": "cauldron_clean_banner", + "3600": "block_start_break", + "3601": "block_stop_break", + "4000": "set_data", + "9800": "players_sleeping", + "16384": "add_particle_mask", + "16385": "particle_bubble", + "16386": "particle_bubble_manual", + "16387": "particle_critical", + "16388": "particle_block_force_field", + "16389": "particle_smoke", + "16390": "particle_explode", + "16391": "particle_evaporation", + "16392": "particle_flame", + "16393": "particle_candle_flame", + "16394": "particle_lava", + "16395": "particle_large_smoke", + "16396": "particle_redstone", + "16397": "particle_rising_red_dust", + "16398": "particle_item_break", + "16399": "particle_snowball_poof", + "16400": "particle_huge_explode", + "16401": "particle_huge_explode_seed", + "16402": "particle_mob_flame", + "16403": "particle_heart", + "16404": "particle_terrain", + "16405": "particle_town_aura", + "16406": "particle_portal", + "16408": "particle_water_splash", + "16409": "particle_water_splash_manual", + "16410": "particle_water_wake", + "16411": "particle_drip_water", + "16412": "particle_drip_lava", + "16413": "particle_drip_honey", + "16414": "particle_stalactite_drip_water", + "16415": "particle_stalactite_drip_lava", + "16416": "particle_falling_dust", + "16417": "particle_mob_spell", + "16418": "particle_mob_spell_ambient", + "16419": "particle_mob_spell_instantaneous", + "16420": "particle_ink", + "16421": "particle_slime", + "16422": "particle_rain_splash", + "16423": "particle_villager_angry", + "16424": "particle_villager_happy", + "16425": "particle_enchantment_table", + "16426": "particle_tracking_emitter", + "16427": "particle_note", + "16428": "particle_witch_spell", + "16429": "particle_carrot", + "16430": "particle_mob_appearance", + "16431": "particle_end_rod", + "16432": "particle_dragons_breath", + "16433": "particle_spit", + "16434": "particle_totem", + "16435": "particle_food", + "16436": "particle_fireworks_starter", + "16437": "particle_fireworks_spark", + "16438": "particle_fireworks_overlay", + "16439": "particle_balloon_gas", + "16440": "particle_colored_flame", + "16441": "particle_sparkler", + "16442": "particle_conduit", + "16443": "particle_bubble_column_up", + "16444": "particle_bubble_column_down", + "16445": "particle_sneeze", + "16446": "particle_shulker_bullet", + "16447": "particle_bleach", + "16448": "particle_dragon_destroy_block", + "16449": "particle_mycelium_dust", + "16450": "particle_falling_red_dust", + "16451": "particle_campfire_smoke", + "16452": "particle_tall_campfire_smoke", + "16453": "particle_dragon_breath_fire", + "16454": "particle_dragon_breath_trail", + "16455": "particle_blue_flame", + "16456": "particle_soul", + "16457": "particle_obsidian_tear", + "16458": "particle_portal_reverse", + "16459": "particle_snowflake", + "16460": "particle_vibration_signal", + "16461": "particle_sculk_sensor_redstone", + "16462": "particle_spore_blossom_shower", + "16463": "particle_spore_blossom_ambient", + "16464": "particle_wax", + "16465": "particle_electric_spark" + } + } + ] + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_block_event": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "sound", + "1": "change_state" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_entity_event": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "event_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "jump", + "2": "hurt_animation", + "3": "death_animation", + "4": "arm_swing", + "5": "stop_attack", + "6": "tame_fail", + "7": "tame_success", + "8": "shake_wet", + "9": "use_item", + "10": "eat_grass_animation", + "11": "fish_hook_bubble", + "12": "fish_hook_position", + "13": "fish_hook_hook", + "14": "fish_hook_tease", + "15": "squid_ink_cloud", + "16": "zombie_villager_cure", + "18": "respawn", + "19": "iron_golem_offer_flower", + "20": "iron_golem_withdraw_flower", + "21": "love_particles", + "22": "villager_angry", + "23": "villager_happy", + "24": "witch_spell_particles", + "25": "firework_particles", + "26": "in_love_particles", + "27": "silverfish_spawn_animation", + "28": "guardian_attack", + "29": "witch_drink_potion", + "30": "witch_throw_potion", + "31": "minecart_tnt_prime_fuse", + "32": "creeper_prime_fuse", + "33": "air_supply_expired", + "34": "player_add_xp_levels", + "35": "elder_guardian_curse", + "36": "agent_arm_swing", + "37": "ender_dragon_death", + "38": "dust_particles", + "39": "arrow_shake", + "57": "eating_item", + "60": "baby_animal_feed", + "61": "death_smoke_cloud", + "62": "complete_trade", + "63": "remove_leash", + "65": "consume_totem", + "66": "player_check_treasure_hunter_achievement", + "67": "entity_spawn", + "68": "dragon_puke", + "69": "item_entity_merge", + "70": "start_swim", + "71": "balloon_pop", + "72": "treasure_hunt", + "73": "agent_summon", + "74": "charged_crossbow", + "75": "fall" + } + } + ] + }, + { + "name": "data", + "type": "zigzag32" + } + ] + ], + "packet_mob_effect": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "event_id", + "type": "u8" + }, + { + "name": "effect_id", + "type": "zigzag32" + }, + { + "name": "amplifier", + "type": "zigzag32" + }, + { + "name": "particles", + "type": "bool" + }, + { + "name": "duration", + "type": "zigzag32" + } + ] + ], + "packet_update_attributes": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "attributes", + "type": "PlayerAttributes" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_inventory_transaction": [ + "container", + [ + { + "name": "transaction", + "type": "Transaction" + } + ] + ], + "packet_mob_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "item", + "type": "Item" + }, + { + "name": "slot", + "type": "u8" + }, + { + "name": "selected_slot", + "type": "u8" + }, + { + "name": "window_id", + "type": "WindowID" + } + ] + ], + "packet_mob_armor_equipment": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "helmet", + "type": "Item" + }, + { + "name": "chestplate", + "type": "Item" + }, + { + "name": "leggings", + "type": "Item" + }, + { + "name": "boots", + "type": "Item" + } + ] + ], + "packet_interact": [ + "container", + [ + { + "name": "action_id", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "3": "leave_vehicle", + "4": "mouse_over_entity", + "6": "open_inventory" + } + } + ] + }, + { + "name": "target_entity_id", + "type": "varint64" + }, + { + "name": "position", + "type": [ + "switch", + { + "compareTo": "action_id", + "fields": { + "mouse_over_entity": "vec3f", + "leave_vehicle": "vec3f" + }, + "default": "void" + } + ] + } + ] + ], + "packet_block_pick_request": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "y", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "add_user_data", + "type": "bool" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_entity_pick_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "lu64" + }, + { + "name": "selected_slot", + "type": "u8" + } + ] + ], + "packet_player_action": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "action", + "type": "Action" + }, + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "packet_hurt_armor": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_entity_data": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "metadata", + "type": "MetadataDictionary" + }, + { + "name": "tick", + "type": "varint" + } + ] + ], + "packet_set_entity_motion": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + } + ] + ], + "packet_set_entity_link": [ + "container", + [ + { + "name": "link", + "type": "Link" + } + ] + ], + "packet_set_health": [ + "container", + [ + { + "name": "health", + "type": "zigzag32" + } + ] + ], + "packet_set_spawn_position": [ + "container", + [ + { + "name": "spawn_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "player", + "1": "world" + } + } + ] + }, + { + "name": "player_position", + "type": "BlockCoordinates" + }, + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "world_position", + "type": "BlockCoordinates" + } + ] + ], + "packet_animate": [ + "container", + [ + { + "name": "action_id", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "none", + "1": "swing_arm", + "2": "unknown", + "3": "wake_up", + "4": "critical_hit", + "5": "magic_critical_hit", + "6": "row_right", + "7": "row_left" + } + } + ] + }, + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_respawn": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "state", + "type": "u8" + }, + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_container_open": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "runtime_entity_id", + "type": "zigzag64" + } + ] + ], + "packet_container_close": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "server", + "type": "bool" + } + ] + ], + "packet_player_hotbar": [ + "container", + [ + { + "name": "selected_slot", + "type": "varint" + }, + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "select_slot", + "type": "bool" + } + ] + ], + "packet_inventory_content": [ + "container", + [ + { + "name": "window_id", + "type": "WindowIDVarint" + }, + { + "name": "input", + "type": "ItemStacks" + } + ] + ], + "packet_inventory_slot": [ + "container", + [ + { + "name": "window_id", + "type": "WindowIDVarint" + }, + { + "name": "slot", + "type": "varint" + }, + { + "name": "item", + "type": "Item" + } + ] + ], + "packet_container_set_data": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "property", + "type": "zigzag32" + }, + { + "name": "value", + "type": "zigzag32" + } + ] + ], + "packet_crafting_data": [ + "container", + [ + { + "name": "recipes", + "type": "Recipes" + }, + { + "name": "potion_type_recipes", + "type": "PotionTypeRecipes" + }, + { + "name": "potion_container_recipes", + "type": "PotionContainerChangeRecipes" + }, + { + "name": "is_clean", + "type": "bool" + } + ] + ], + "packet_crafting_event": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "recipe_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "inventory", + "1": "crafting", + "2": "workbench" + } + } + ] + }, + { + "name": "recipe_id", + "type": "uuid" + }, + { + "name": "input", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + }, + { + "name": "result", + "type": [ + "array", + { + "countType": "varint", + "type": "Item" + } + ] + } + ] + ], + "packet_gui_data_pick_item": [ + "container", + [ + { + "name": "item_name", + "type": "string" + }, + { + "name": "item_effects", + "type": "string" + }, + { + "name": "hotbar_slot", + "type": "li32" + } + ] + ], + "packet_adventure_settings": [ + "container", + [ + { + "name": "flags", + "type": "AdventureFlags" + }, + { + "name": "command_permission", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "operator", + "2": "host", + "3": "automation", + "4": "admin" + } + } + ] + }, + { + "name": "action_permissions", + "type": "ActionPermissions" + }, + { + "name": "permission_level", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "visitor", + "1": "member", + "2": "operator", + "3": "custom" + } + } + ] + }, + { + "name": "custom_stored_permissions", + "type": "varint" + }, + { + "name": "user_id", + "type": "li64" + } + ] + ], + "packet_block_entity_data": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_player_input": [ + "container", + [ + { + "name": "motion_x", + "type": "lf32" + }, + { + "name": "motion_z", + "type": "lf32" + }, + { + "name": "jumping", + "type": "bool" + }, + { + "name": "sneaking", + "type": "bool" + } + ] + ], + "packet_level_chunk": [ + "container", + [ + { + "name": "x", + "type": "zigzag32" + }, + { + "name": "z", + "type": "zigzag32" + }, + { + "name": "sub_chunk_count", + "type": "varint" + }, + { + "name": "cache_enabled", + "type": "bool" + }, + { + "name": "blobs", + "type": [ + "switch", + { + "compareTo": "cache_enabled", + "fields": { + "true": [ + "container", + [ + { + "name": "hashes", + "type": [ + "array", + { + "countType": "varint", + "type": "lu64" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_set_commands_enabled": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_set_difficulty": [ + "container", + [ + { + "name": "difficulty", + "type": "varint" + } + ] + ], + "packet_change_dimension": [ + "container", + [ + { + "name": "dimension", + "type": "zigzag32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "respawn", + "type": "bool" + } + ] + ], + "packet_set_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_player_list": [ + "container", + [ + { + "name": "records", + "type": "PlayerRecords" + } + ] + ], + "packet_simple_event": [ + "container", + [ + { + "name": "event_type", + "type": "lu16" + } + ] + ], + "packet_event": [ + "container", + [ + { + "name": "runtime_id", + "type": "varint64" + }, + { + "name": "event_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "achievement_awarded", + "1": "entity_interact", + "2": "portal_built", + "3": "portal_used", + "4": "mob_killed", + "5": "cauldron_used", + "6": "player_death", + "7": "boss_killed", + "8": "agent_command", + "9": "agent_created", + "10": "banner_pattern_removed", + "11": "commaned_executed", + "12": "fish_bucketed", + "13": "mob_born", + "14": "pet_died", + "15": "cauldron_block_used", + "16": "composter_block_used", + "17": "bell_block_used", + "18": "actor_definition", + "19": "raid_update", + "20": "player_movement_anomaly", + "21": "player_moement_corrected", + "22": "honey_harvested", + "23": "target_block_hit", + "24": "piglin_barter", + "25": "waxed_or_unwaxed_copper" + } + } + ] + }, + { + "name": "use_player_id", + "type": "u8" + }, + { + "name": "event_data", + "type": "restBuffer" + } + ] + ], + "packet_spawn_experience_orb": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "count", + "type": "zigzag32" + } + ] + ], + "packet_clientbound_map_item_data": [ + "container", + [ + { + "name": "map_id", + "type": "zigzag64" + }, + { + "name": "update_flags", + "type": "UpdateMapFlags" + }, + { + "name": "dimension", + "type": "u8" + }, + { + "name": "locked", + "type": "bool" + }, + { + "name": "included_in", + "type": [ + "switch", + { + "compareTo": "update_flags.initialisation", + "fields": { + "true": [ + "array", + { + "countType": "varint", + "type": "zigzag64" + } + ] + }, + "default": "void" + } + ] + }, + { + "name": "scale", + "type": [ + "switch", + { + "compareTo": "update_flags.initialisation || update_flags.decoration || update_flags.texture", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "tracked", + "type": [ + "switch", + { + "compareTo": "update_flags.decoration", + "fields": { + "true": [ + "container", + [ + { + "name": "objects", + "type": [ + "array", + { + "countType": "varint", + "type": "TrackedObject" + } + ] + }, + { + "name": "decorations", + "type": [ + "array", + { + "countType": "varint", + "type": "MapDecoration" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "texture", + "type": [ + "switch", + { + "compareTo": "update_flags.texture", + "fields": { + "true": [ + "container", + [ + { + "name": "width", + "type": "zigzag32" + }, + { + "name": "height", + "type": "zigzag32" + }, + { + "name": "x_offset", + "type": "zigzag32" + }, + { + "name": "y_offset", + "type": "zigzag32" + }, + { + "name": "pixels", + "type": [ + "array", + { + "countType": "varint", + "type": "varint" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_map_info_request": [ + "container", + [ + { + "name": "map_id", + "type": "zigzag64" + } + ] + ], + "packet_request_chunk_radius": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_chunk_radius_update": [ + "container", + [ + { + "name": "chunk_radius", + "type": "zigzag32" + } + ] + ], + "packet_item_frame_drop_item": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + } + ] + ], + "packet_game_rules_changed": [ + "container", + [ + { + "name": "rules", + "type": "GameRules" + } + ] + ], + "packet_camera": [ + "container", + [ + { + "name": "camera_entity_unique_id", + "type": "zigzag64" + }, + { + "name": "target_player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_boss_event": [ + "container", + [ + { + "name": "boss_entity_id", + "type": "zigzag64" + }, + { + "name": "type", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "show_bar", + "1": "register_player", + "2": "hide_bar", + "3": "unregister_player", + "4": "set_bar_progress", + "5": "set_bar_title", + "6": "update_properties", + "7": "texture" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "show_bar": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "progress", + "type": "lf32" + }, + { + "name": "screen_darkening", + "type": "li16" + }, + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], + "register_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "unregister_player": [ + "container", + [ + { + "name": "player_id", + "type": "zigzag64" + } + ] + ], + "set_bar_progress": [ + "container", + [ + { + "name": "progress", + "type": "lf32" + } + ] + ], + "set_bar_title": [ + "container", + [ + { + "name": "title", + "type": "string" + } + ] + ], + "update_properties": [ + "container", + [ + { + "name": "screen_darkening", + "type": "li16" + }, + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ], + "texture": [ + "container", + [ + { + "name": "color", + "type": "varint" + }, + { + "name": "overlay", + "type": "varint" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_show_credits": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "status", + "type": "zigzag32" + } + ] + ], + "packet_available_commands": [ + "container", + [ + { + "name": "values_len", + "type": "varint" + }, + { + "name": "_enum_type", + "type": [ + "enum_size_based_on_values_len" + ] + }, + { + "name": "enum_values", + "type": [ + "array", + { + "count": "values_len", + "type": "string" + } + ] + }, + { + "name": "suffixes", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + }, + { + "name": "enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "switch", + { + "compareTo": "../_enum_type", + "fields": { + "byte": "u8", + "short": "lu16", + "int": "lu32" + }, + "default": "void" + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "command_data", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "description", + "type": "string" + }, + { + "name": "flags", + "type": "lu16" + }, + { + "name": "permission_level", + "type": "u8" + }, + { + "name": "alias", + "type": "li32" + }, + { + "name": "overloads", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "paramater_name", + "type": "string" + }, + { + "name": "value_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "1": "int", + "2": "float", + "3": "value", + "4": "wildcard_int", + "5": "operator", + "6": "target", + "16": "file_path", + "32": "string", + "40": "position", + "44": "message", + "46": "raw_text", + "50": "json", + "63": "command" + } + } + ] + }, + { + "name": "enum_type", + "type": [ + "mapper", + { + "type": "lu16", + "mappings": { + "16": "valid", + "32": "enum", + "256": "suffixed", + "1024": "soft_enum" + } + } + ] + }, + { + "name": "optional", + "type": "bool" + }, + { + "name": "options", + "type": "CommandFlags" + } + ] + ] + } + ] + } + ] + } + ] + ] + } + ] + }, + { + "name": "dynamic_enums", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "values", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "enum_constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "value_index", + "type": "li32" + }, + { + "name": "enum_index", + "type": "li32" + }, + { + "name": "constraints", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "constraint", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "cheats_enabled", + "1": "operator_permissions", + "2": "host_permissions" + } + } + ] + } + ] + ] + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_command_request": [ + "container", + [ + { + "name": "command", + "type": "string" + }, + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "interval", + "type": "bool" + } + ] + ], + "packet_command_block_update": [ + "container", + [ + { + "name": "is_block", + "type": "bool" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "is_block", + "fields": { + "true": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "impulse", + "1": "repeat", + "2": "chain" + } + } + ] + }, + { + "name": "needs_redstone", + "type": "bool" + }, + { + "name": "conditional", + "type": "bool" + } + ] + ] + }, + "default": [ + "container", + [ + { + "name": "minecart_entity_runtime_id", + "type": "varint64" + } + ] + ] + } + ] + }, + { + "name": "command", + "type": "string" + }, + { + "name": "last_output", + "type": "string" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "should_track_output", + "type": "bool" + }, + { + "name": "tick_delay", + "type": "li32" + }, + { + "name": "execute_on_first_tick", + "type": "bool" + } + ] + ], + "packet_command_output": [ + "container", + [ + { + "name": "origin", + "type": "CommandOrigin" + }, + { + "name": "output_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "last", + "2": "silent", + "3": "all", + "4": "data_set" + } + } + ] + }, + { + "name": "success_count", + "type": "varint" + }, + { + "name": "output", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "success", + "type": "bool" + }, + { + "name": "message_id", + "type": "string" + }, + { + "name": "paramaters", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ] + } + ] + }, + { + "name": "data_set", + "type": [ + "switch", + { + "compareTo": "output_type", + "fields": { + "data_set": "string" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_trade": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "varint" + }, + { + "name": "trade_tier", + "type": "varint" + }, + { + "name": "villager_unique_id", + "type": "varint64" + }, + { + "name": "entity_unique_id", + "type": "varint64" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "new_trading_ui", + "type": "bool" + }, + { + "name": "economic_trades", + "type": "bool" + }, + { + "name": "offers", + "type": "nbt" + } + ] + ], + "packet_update_equipment": [ + "container", + [ + { + "name": "window_id", + "type": "WindowID" + }, + { + "name": "window_type", + "type": "WindowType" + }, + { + "name": "size", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "inventory", + "type": "nbt" + } + ] + ], + "packet_resource_pack_data_info": [ + "container", + [ + { + "name": "pack_id", + "type": "string" + }, + { + "name": "max_chunk_size", + "type": "lu32" + }, + { + "name": "chunk_count", + "type": "lu32" + }, + { + "name": "size", + "type": "lu64" + }, + { + "name": "hash", + "type": "ByteArray" + }, + { + "name": "is_premium", + "type": "bool" + }, + { + "name": "pack_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "addon", + "2": "cached", + "3": "copy_protected", + "4": "behavior", + "5": "persona_piece", + "6": "resources", + "7": "skins", + "8": "world_template" + } + } + ] + } + ] + ], + "packet_resource_pack_chunk_data": [ + "container", + [ + { + "name": "pack_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + }, + { + "name": "progress", + "type": "lu64" + }, + { + "name": "payload", + "type": "ByteArray" + } + ] + ], + "packet_resource_pack_chunk_request": [ + "container", + [ + { + "name": "pack_id", + "type": "string" + }, + { + "name": "chunk_index", + "type": "lu32" + } + ] + ], + "packet_transfer": [ + "container", + [ + { + "name": "server_address", + "type": "string" + }, + { + "name": "port", + "type": "lu16" + } + ] + ], + "packet_play_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "volume", + "type": "lf32" + }, + { + "name": "pitch", + "type": "lf32" + } + ] + ], + "packet_stop_sound": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "stop_all", + "type": "bool" + } + ] + ], + "packet_set_title": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "clear", + "1": "reset", + "2": "set_title", + "3": "set_subtitle", + "4": "action_bar_message", + "5": "set_durations", + "6": "set_title_json", + "7": "set_subtitle_json", + "8": "action_bar_message_json" + } + } + ] + }, + { + "name": "text", + "type": "string" + }, + { + "name": "fade_in_time", + "type": "zigzag32" + }, + { + "name": "stay_time", + "type": "zigzag32" + }, + { + "name": "fade_out_time", + "type": "zigzag32" + }, + { + "name": "xuid", + "type": "string" + }, + { + "name": "platform_online_id", + "type": "string" + } + ] + ], + "packet_add_behavior_tree": [ + "container", + [ + { + "name": "behaviortree", + "type": "string" + } + ] + ], + "packet_structure_block_update": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "structure_name", + "type": "string" + }, + { + "name": "data_field", + "type": "string" + }, + { + "name": "include_players", + "type": "bool" + }, + { + "name": "show_bounding_box", + "type": "bool" + }, + { + "name": "structure_block_type", + "type": "zigzag32" + }, + { + "name": "settings", + "type": "StructureBlockSettings" + }, + { + "name": "redstone_save_mode", + "type": "zigzag32" + }, + { + "name": "should_trigger", + "type": "bool" + } + ] + ], + "packet_show_store_offer": [ + "container", + [ + { + "name": "offer_id", + "type": "string" + }, + { + "name": "show_all", + "type": "bool" + } + ] + ], + "packet_purchase_receipt": [ + "container", + [ + { + "name": "receipts", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "packet_player_skin": [ + "container", + [ + { + "name": "uuid", + "type": "uuid" + }, + { + "name": "skin", + "type": "Skin" + }, + { + "name": "skin_name", + "type": "string" + }, + { + "name": "old_skin_name", + "type": "string" + }, + { + "name": "is_verified", + "type": "bool" + } + ] + ], + "packet_sub_client_login": [ + "container", + [ + { + "name": "tokens", + "type": [ + "encapsulated", + { + "lengthType": "varint", + "type": "LoginTokens" + } + ] + } + ] + ], + "packet_initiate_web_socket_connection": [ + "container", + [ + { + "name": "server", + "type": "string" + } + ] + ], + "packet_set_last_hurt_by": [ + "container", + [ + { + "name": "entity_type", + "type": "varint" + } + ] + ], + "packet_book_edit": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "replace_page", + "1": "add_page", + "2": "delete_page", + "3": "swap_pages", + "4": "sign" + } + } + ] + }, + { + "name": "slot", + "type": "u8" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "replace_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "add_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + }, + { + "name": "text", + "type": "string" + }, + { + "name": "photo_name", + "type": "string" + } + ] + ], + "delete_page": [ + "container", + [ + { + "name": "page_number", + "type": "u8" + } + ] + ], + "swap_pages": [ + "container", + [ + { + "name": "page1", + "type": "u8" + }, + { + "name": "page2", + "type": "u8" + } + ] + ], + "sign": [ + "container", + [ + { + "name": "title", + "type": "string" + }, + { + "name": "author", + "type": "string" + }, + { + "name": "xuid", + "type": "string" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_npc_request": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "request_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "set_actions", + "1": "execute_action", + "2": "execute_closing_commands", + "3": "set_name", + "4": "set_skin", + "5": "set_interaction_text" + } + } + ] + }, + { + "name": "command", + "type": "string" + }, + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "set_actions", + "1": "execute_action", + "2": "execute_closing_commands", + "3": "set_name", + "4": "set_skin", + "5": "set_interact_text", + "6": "execute_openining_commands" + } + } + ] + }, + { + "name": "scene_name", + "type": "string" + } + ] + ], + "packet_photo_transfer": [ + "container", + [ + { + "name": "image_name", + "type": "string" + }, + { + "name": "image_data", + "type": "string" + }, + { + "name": "book_id", + "type": "string" + } + ] + ], + "packet_modal_form_request": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_modal_form_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_server_settings_request": [ + "container", + [] + ], + "packet_server_settings_response": [ + "container", + [ + { + "name": "form_id", + "type": "varint" + }, + { + "name": "data", + "type": "string" + } + ] + ], + "packet_show_profile": [ + "container", + [ + { + "name": "xuid", + "type": "string" + } + ] + ], + "packet_set_default_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + } + ] + ], + "packet_remove_objective": [ + "container", + [ + { + "name": "objective_name", + "type": "string" + } + ] + ], + "packet_set_display_objective": [ + "container", + [ + { + "name": "display_slot", + "type": "string" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "display_name", + "type": "string" + }, + { + "name": "criteria_name", + "type": "string" + }, + { + "name": "sort_order", + "type": "zigzag32" + } + ] + ], + "packet_set_score": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "change", + "1": "remove" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "objective_name", + "type": "string" + }, + { + "name": "score", + "type": "li32" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "../action", + "fields": { + "change": [ + "container", + [ + { + "name": "entry_type", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "1": "player", + "2": "entity", + "3": "fake_player" + } + } + ] + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "player": "zigzag64", + "entity": "zigzag64" + }, + "default": "void" + } + ] + }, + { + "name": "custom_name", + "type": [ + "switch", + { + "compareTo": "entry_type", + "fields": { + "fake_player": "string" + }, + "default": "void" + } + ] + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_lab_table": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "combine", + "1": "react" + } + } + ] + }, + { + "name": "position", + "type": "vec3u" + }, + { + "name": "reaction_type", + "type": "u8" + } + ] + ], + "packet_update_block_synced": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "block_runtime_id", + "type": "varint" + }, + { + "name": "flags", + "type": "UpdateBlockFlags" + }, + { + "name": "layer", + "type": "varint" + }, + { + "name": "entity_unique_id", + "type": "zigzag64" + }, + { + "name": "transition_type", + "type": [ + "mapper", + { + "type": "varint64", + "mappings": { + "0": "entity", + "1": "create", + "2": "destroy" + } + } + ] + } + ] + ], + "packet_move_entity_delta": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + }, + { + "name": "flags", + "type": "DeltaMoveFlags" + }, + { + "name": "x", + "type": [ + "switch", + { + "compareTo": "flags.has_x", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "y", + "type": [ + "switch", + { + "compareTo": "flags.has_y", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "z", + "type": [ + "switch", + { + "compareTo": "flags.has_z", + "fields": { + "true": "lf32" + }, + "default": "void" + } + ] + }, + { + "name": "rot_x", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_x", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_y", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_y", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + }, + { + "name": "rot_z", + "type": [ + "switch", + { + "compareTo": "flags.has_rot_z", + "fields": { + "true": "u8" + }, + "default": "void" + } + ] + } + ] + ], + "packet_set_scoreboard_identity": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "i8", + "mappings": { + "0": "register_identity", + "1": "clear_identity" + } + } + ] + }, + { + "name": "entries", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "scoreboard_id", + "type": "zigzag64" + }, + { + "name": "entity_unique_id", + "type": [ + "switch", + { + "compareTo": "../action", + "fields": { + "register_identity": "zigzag64" + }, + "default": "void" + } + ] + } + ] + ] + } + ] + } + ] + ], + "packet_set_local_player_as_initialized": [ + "container", + [ + { + "name": "runtime_entity_id", + "type": "varint64" + } + ] + ], + "packet_update_soft_enum": [ + "container", + [] + ], + "packet_network_stack_latency": [ + "container", + [ + { + "name": "timestamp", + "type": "lu64" + }, + { + "name": "needs_response", + "type": "u8" + } + ] + ], + "packet_script_custom_event": [ + "container", + [ + { + "name": "event_name", + "type": "string" + }, + { + "name": "event_data", + "type": "string" + } + ] + ], + "packet_spawn_particle_effect": [ + "container", + [ + { + "name": "dimension", + "type": "u8" + }, + { + "name": "entity_id", + "type": "zigzag64" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "particle_name", + "type": "string" + } + ] + ], + "packet_available_entity_identifiers": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event_v2": [ + "container", + [ + { + "name": "sound_id", + "type": "u8" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "block_id", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_network_chunk_publisher_update": [ + "container", + [ + { + "name": "coordinates", + "type": "BlockCoordinates" + }, + { + "name": "radius", + "type": "varint" + } + ] + ], + "packet_biome_definition_list": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_level_sound_event": [ + "container", + [ + { + "name": "sound_id", + "type": "SoundType" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "extra_data", + "type": "zigzag32" + }, + { + "name": "entity_type", + "type": "string" + }, + { + "name": "is_baby_mob", + "type": "bool" + }, + { + "name": "is_global", + "type": "bool" + } + ] + ], + "packet_level_event_generic": [ + "container", + [ + { + "name": "event_id", + "type": "varint" + }, + { + "name": "nbt", + "type": "nbtLoop" + } + ] + ], + "packet_lectern_update": [ + "container", + [ + { + "name": "page", + "type": "u8" + }, + { + "name": "page_count", + "type": "u8" + }, + { + "name": "position", + "type": "vec3i" + }, + { + "name": "drop_book", + "type": "bool" + } + ] + ], + "packet_video_stream_connect": [ + "container", + [ + { + "name": "server_uri", + "type": "string" + }, + { + "name": "frame_send_frequency", + "type": "lf32" + }, + { + "name": "action", + "type": "u8" + }, + { + "name": "resolution_x", + "type": "li32" + }, + { + "name": "resolution_y", + "type": "li32" + } + ] + ], + "packet_add_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_remove_ecs_entity": [ + "container", + [ + { + "name": "network_id", + "type": "varint64" + } + ] + ], + "packet_client_cache_status": [ + "container", + [ + { + "name": "enabled", + "type": "bool" + } + ] + ], + "packet_on_screen_texture_animation": [ + "container", + [ + { + "name": "animation_type", + "type": "lu32" + } + ] + ], + "packet_map_create_locked_copy": [ + "container", + [ + { + "name": "original_map_id", + "type": "zigzag64" + }, + { + "name": "new_map_id", + "type": "zigzag64" + } + ] + ], + "packet_structure_template_data_export_request": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "settings", + "type": "StructureBlockSettings" + }, + { + "name": "request_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "export_from_save", + "2": "export_from_load", + "3": "query_saved_structure" + } + } + ] + } + ] + ], + "packet_structure_template_data_export_response": [ + "container", + [ + { + "name": "name", + "type": "string" + }, + { + "name": "success", + "type": "bool" + }, + { + "name": "nbt", + "type": [ + "switch", + { + "compareTo": "success", + "fields": { + "true": "nbt" + }, + "default": "void" + } + ] + }, + { + "name": "response_type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "1": "export", + "2": "query" + } + } + ] + } + ] + ], + "packet_update_block_properties": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_client_cache_blob_status": [ + "container", + [ + { + "name": "misses", + "type": "varint" + }, + { + "name": "haves", + "type": "varint" + }, + { + "name": "missing", + "type": [ + "array", + { + "count": "misses", + "type": "lu64" + } + ] + }, + { + "name": "have", + "type": [ + "array", + { + "count": "haves", + "type": "lu64" + } + ] + } + ] + ], + "packet_client_cache_miss_response": [ + "container", + [ + { + "name": "blobs", + "type": [ + "array", + { + "countType": "varint", + "type": "Blob" + } + ] + } + ] + ], + "packet_education_settings": [ + "container", + [ + { + "name": "CodeBuilderDefaultURI", + "type": "string" + }, + { + "name": "CodeBuilderTitle", + "type": "string" + }, + { + "name": "CanResizeCodeBuilder", + "type": "bool" + }, + { + "name": "HasOverrideURI", + "type": "bool" + }, + { + "name": "OverrideURI", + "type": [ + "switch", + { + "compareTo": "HasOverrideURI", + "fields": { + "true": "string" + }, + "default": "void" + } + ] + }, + { + "name": "HasQuiz", + "type": "bool" + } + ] + ], + "packet_multiplayer_settings": [ + "container", + [ + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "enable_multiplayer", + "1": "disable_multiplayer", + "2": "refresh_join_code" + } + } + ] + } + ] + ], + "packet_settings_command": [ + "container", + [ + { + "name": "command_line", + "type": "string" + }, + { + "name": "suppress_output", + "type": "bool" + } + ] + ], + "packet_anvil_damage": [ + "container", + [ + { + "name": "damage", + "type": "u8" + }, + { + "name": "position", + "type": "BlockCoordinates" + } + ] + ], + "packet_completed_using_item": [ + "container", + [ + { + "name": "used_item_id", + "type": "li16" + }, + { + "name": "use_method", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "equip_armor", + "1": "eat", + "2": "attack", + "3": "consume", + "4": "throw", + "5": "shoot", + "6": "place", + "7": "fill_bottle", + "8": "fill_bucket", + "9": "pour_bucket", + "10": "use_tool", + "11": "interact", + "12": "retrieved", + "13": "dyed", + "14": "traded" + } + } + ] + } + ] + ], + "packet_network_settings": [ + "container", + [ + { + "name": "compression_threshold", + "type": "u16" + } + ] + ], + "packet_player_auth_input": [ + "container", + [ + { + "name": "pitch", + "type": "lf32" + }, + { + "name": "yaw", + "type": "lf32" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "move_vector", + "type": "vec2f" + }, + { + "name": "head_yaw", + "type": "lf32" + }, + { + "name": "input_data", + "type": "InputFlag" + }, + { + "name": "input_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "unknown", + "1": "mouse", + "2": "touch", + "3": "game_pad", + "4": "motion_controller" + } + } + ] + }, + { + "name": "play_mode", + "type": [ + "mapper", + { + "type": "varint", + "mappings": { + "0": "normal", + "1": "teaser", + "2": "screen", + "3": "viewer", + "4": "reality", + "5": "placement", + "6": "living_room", + "7": "exit_level", + "8": "exit_level_living_room", + "9": "num_modes" + } + } + ] + }, + { + "name": "gaze_direction", + "type": [ + "switch", + { + "compareTo": "play_mode", + "fields": { + "reality": "vec3f" + }, + "default": "void" + } + ] + }, + { + "name": "tick", + "type": "varint64" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "transaction", + "type": [ + "switch", + { + "compareTo": "input_data.item_interact", + "fields": { + "true": [ + "container", + [ + { + "name": "legacy", + "type": "TransactionLegacy" + }, + { + "name": "actions", + "type": "TransactionActions" + }, + { + "name": "data", + "type": "TransactionUseItem" + } + ] + ] + }, + "default": "void" + } + ] + }, + { + "name": "item_stack_request", + "type": [ + "switch", + { + "compareTo": "input_data.item_stack_request", + "fields": { + "true": "ItemStackRequest" + }, + "default": "void" + } + ] + }, + { + "name": "block_action", + "type": [ + "switch", + { + "compareTo": "input_data.block_action", + "fields": { + "true": [ + "array", + { + "countType": "zigzag32", + "type": [ + "container", + [ + { + "name": "action", + "type": "Action" + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "action", + "fields": { + "start_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "abort_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "crack_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "predict_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ], + "continue_break": [ + "container", + [ + { + "name": "position", + "type": "BlockCoordinates" + }, + { + "name": "face", + "type": "zigzag32" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ] + } + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_creative_content": [ + "container", + [ + { + "name": "items", + "type": [ + "array", + { + "countType": "varint", + "type": [ + "container", + [ + { + "name": "entry_id", + "type": "varint" + }, + { + "name": "item", + "type": "ItemLegacy" + } + ] + ] + } + ] + } + ] + ], + "packet_player_enchant_options": [ + "container", + [ + { + "name": "options", + "type": [ + "array", + { + "countType": "varint", + "type": "EnchantOption" + } + ] + } + ] + ], + "packet_item_stack_request": [ + "container", + [ + { + "name": "requests", + "type": [ + "array", + { + "countType": "varint", + "type": "ItemStackRequest" + } + ] + } + ] + ], + "packet_item_stack_response": [ + "container", + [ + { + "name": "responses", + "type": "ItemStackResponses" + } + ] + ], + "packet_player_armor_damage": [ + "container", + [ + { + "name": "type", + "type": "ArmorDamageType" + }, + { + "name": "helmet_damage", + "type": [ + "switch", + { + "compareTo": "type.head", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "chestplate_damage", + "type": [ + "switch", + { + "compareTo": "type.chest", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "leggings_damage", + "type": [ + "switch", + { + "compareTo": "type.legs", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + }, + { + "name": "boots_damage", + "type": [ + "switch", + { + "compareTo": "type.feet", + "fields": { + "true": "zigzag32" + }, + "default": "void" + } + ] + } + ] + ], + "packet_update_player_game_type": [ + "container", + [ + { + "name": "gamemode", + "type": "GameMode" + }, + { + "name": "player_unique_id", + "type": "zigzag64" + } + ] + ], + "packet_position_tracking_db_request": [ + "container", + [ + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "query" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + } + ] + ], + "packet_position_tracking_db_broadcast": [ + "container", + [ + { + "name": "broadcast_action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "update", + "1": "destory", + "2": "not_found" + } + } + ] + }, + { + "name": "tracking_id", + "type": "zigzag32" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_packet_violation_warning": [ + "container", + [ + { + "name": "violation_type", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "malformed" + } + } + ] + }, + { + "name": "severity", + "type": [ + "mapper", + { + "type": "zigzag32", + "mappings": { + "0": "warning", + "1": "final_warning", + "2": "terminating" + } + } + ] + }, + { + "name": "packet_id", + "type": "zigzag32" + }, + { + "name": "reason", + "type": "string" + } + ] + ], + "packet_motion_prediction_hints": [ + "container", + [ + { + "name": "entity_runtime_id", + "type": "varint64" + }, + { + "name": "velocity", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + } + ] + ], + "packet_animate_entity": [ + "container", + [ + { + "name": "animation", + "type": "string" + }, + { + "name": "next_state", + "type": "string" + }, + { + "name": "stop_condition", + "type": "string" + }, + { + "name": "controller", + "type": "string" + }, + { + "name": "blend_out_time", + "type": "lf32" + }, + { + "name": "runtime_entity_ids", + "type": [ + "array", + { + "countType": "varint", + "type": "varint64" + } + ] + } + ] + ], + "packet_camera_shake": [ + "container", + [ + { + "name": "intensity", + "type": "lf32" + }, + { + "name": "duration", + "type": "lf32" + }, + { + "name": "type", + "type": "u8" + }, + { + "name": "action", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "add", + "1": "stop" + } + } + ] + } + ] + ], + "packet_player_fog": [ + "container", + [ + { + "name": "stack", + "type": [ + "array", + { + "countType": "varint", + "type": "string" + } + ] + } + ] + ], + "packet_correct_player_move_prediction": [ + "container", + [ + { + "name": "position", + "type": "vec3f" + }, + { + "name": "delta", + "type": "vec3f" + }, + { + "name": "on_ground", + "type": "bool" + }, + { + "name": "tick", + "type": "varint64" + } + ] + ], + "packet_item_component": [ + "container", + [ + { + "name": "entries", + "type": "ItemComponentList" + } + ] + ], + "packet_filter_text_packet": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "from_server", + "type": "bool" + } + ] + ], + "packet_debug_renderer": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "1": "clear", + "2": "add_cube" + } + } + ] + }, + { + "anon": true, + "type": [ + "switch", + { + "compareTo": "type", + "fields": { + "clear": "void", + "add_cube": [ + "container", + [ + { + "name": "text", + "type": "string" + }, + { + "name": "position", + "type": "vec3f" + }, + { + "name": "red", + "type": "lf32" + }, + { + "name": "green", + "type": "lf32" + }, + { + "name": "blue", + "type": "lf32" + }, + { + "name": "alpha", + "type": "lf32" + }, + { + "name": "duration", + "type": "li64" + } + ] + ] + }, + "default": "void" + } + ] + } + ] + ], + "packet_sync_entity_property": [ + "container", + [ + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_add_volume_entity": [ + "container", + [ + { + "name": "entity_id", + "type": "varint64" + }, + { + "name": "nbt", + "type": "nbt" + } + ] + ], + "packet_remove_volume_entity": [ + "container", + [ + { + "name": "entity_id", + "type": "varint64" + } + ] + ], + "packet_simulation_type": [ + "container", + [ + { + "name": "type", + "type": [ + "mapper", + { + "type": "u8", + "mappings": { + "0": "game", + "1": "editor", + "2": "test", + "3": "invalid" + } + } + ] + } + ] + ], + "packet_npc_dialogue": [ + "container", + [ + { + "name": "entity_id", + "type": "lu64" + }, + { + "name": "action_type", + "type": [ + "mapper", + { + "type": "li32", + "mappings": { + "0": "open", + "1": "close" + } + } + ] + }, + { + "name": "dialogue", + "type": "string" + }, + { + "name": "screen_name", + "type": "string" + }, + { + "name": "npc_name", + "type": "string" + }, + { + "name": "action_json", + "type": "string" + } + ] + ], + "string": [ + "pstring", + { + "countType": "varint" + } + ], + "ByteArray": [ + "buffer", + { + "countType": "varint" + } + ], + "SignedByteArray": [ + "buffer", + { + "countType": "zigzag32" + } + ], + "LittleString": [ + "pstring", + { + "countType": "li32" + } + ], + "ShortArray": [ + "buffer", + { + "countType": "li16" + } + ], + "MetadataFlags1": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "flags": [ + "onfire", + "sneaking", + "riding", + "sprinting", + "action", + "invisible", + "tempted", + "inlove", + "saddled", + "powered", + "ignited", + "baby", + "converting", + "critical", + "can_show_nametag", + "always_show_nametag", + "no_ai", + "silent", + "wallclimbing", + "can_climb", + "swimmer", + "can_fly", + "walker", + "resting", + "sitting", + "angry", + "interested", + "charged", + "tamed", + "orphaned", + "leashed", + "sheared", + "gliding", + "elder", + "moving", + "breathing", + "chested", + "stackable", + "showbase", + "rearing", + "vibrating", + "idling", + "evoker_spell", + "charge_attack", + "wasd_controlled", + "can_power_jump", + "linger", + "has_collision", + "affected_by_gravity", + "fire_immune", + "dancing", + "enchanted", + "show_trident_rope", + "container_private", + "transforming", + "spin_attack", + "swimming", + "bribed", + "pregnant", + "laying_egg", + "rider_can_pick", + "transition_sitting", + "eating", + "laying_down" + ] + } + ], + "MetadataFlags2": [ + "bitflags", + { + "type": "zigzag64", + "big": true, + "flags": [ + "sneezing", + "trusting", + "rolling", + "scared", + "in_scaffolding", + "over_scaffolding", + "fall_through_scaffolding", + "blocking", + "transition_blocking", + "blocked_using_shield", + "blocked_using_damaged_shield", + "sleeping", + "wants_to_wake", + "trade_interest", + "door_breaker", + "breaking_obstruction", + "door_opener", + "illager_captain", + "stunned", + "roaring", + "delayed_attacking", + "avoiding_mobs", + "avoiding_block", + "facing_target_to_range_attack", + "hidden_when_invisible", + "is_in_ui", + "stalking", + "emoting", + "celebrating", + "admiring", + "celebrating_special", + "unknown95", + "ram_attack", + "playing_dead" + ] + } + ], + "UpdateBlockFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "neighbors": 1, + "network": 2, + "no_graphic": 4, + "unused": 8, + "priority": 16 + } + } + ], + "AdventureFlags": [ + "bitflags", + { + "type": "varint", + "flags": { + "world_immutable": 1, + "no_pvp": 2, + "auto_jump": 32, + "allow_flight": 64, + "no_clip": 128, + "world_builder": 256, + "flying": 512, + "muted": 1024 + } + } + ], + "ActionPermissions": [ + "bitflags", + { + "type": "varint", + "flags": { + "mine": 65537, + "doors_and_switches": 65538, + "open_containers": 65540, + "attack_players": 65544, + "attack_mobs": 65552, + "operator": 65568, + "teleport": 65664, + "build": 65792, + "default": 66048 + } + } + ], + "UpdateMapFlags": [ + "bitflags", + { + "type": "varint", + "flags": [ + "void", + "texture", + "decoration", + "initialisation" + ] + } + ], + "CommandFlags": [ + "bitfield", + [ + { + "name": "unused", + "size": 6, + "signed": false + }, + { + "name": "has_semantic_constraint", + "size": 1, + "signed": false + }, + { + "name": "collapse_enum", + "size": 1, + "signed": false + } + ] + ], + "DeltaMoveFlags": [ + "bitflags", + { + "type": "lu16", + "flags": { + "has_x": 1, + "has_y": 2, + "has_z": 4, + "has_rot_x": 8, + "has_rot_y": 16, + "has_rot_z": 32, + "on_ground": 64, + "teleport": 128, + "force_move": 256 + } + } + ], + "InputFlag": [ + "bitflags", + { + "type": "varint64", + "big": true, + "flags": [ + "ascend", + "descend", + "north_jump", + "jump_down", + "sprint_down", + "change_height", + "jumping", + "auto_jumping_in_water", + "sneaking", + "sneak_down", + "up", + "down", + "left", + "right", + "up_left", + "up_right", + "want_up", + "want_down", + "want_down_slow", + "want_up_slow", + "sprinting", + "ascend_block", + "descend_block", + "sneak_toggle_down", + "persist_sneak", + "start_sprinting", + "stop_sprinting", + "start_sneaking", + "stop_sneaking", + "start_swimming", + "stop_swimming", + "start_jumping", + "start_gliding", + "stop_gliding", + "item_interact", + "block_action", + "item_stack_request" + ] + } + ], + "ArmorDamageType": [ + "bitflags", + { + "type": "u8", + "flags": { + "head": 1, + "chest": 2, + "legs": 4, + "feet": 8 + } + } + ] + } +} \ No newline at end of file diff --git a/data/latest/proto.yml b/data/latest/proto.yml index bb2237d..43b79bf 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -1,7 +1,7 @@ # Created from MiNET and gophertunnel docs # The version below is the latest version this protocol schema was updated for. # The output protocol.json will be in the folder for the version -!version: 1.17.0 +!version: 1.17.10 # Some ProtoDef aliases string: ["pstring",{"countType":"varint"}] # String / array types @@ -126,6 +126,8 @@ packet_resource_packs_info: # A list of resource packs that the client needs to download before joining the server. # The order of these resource packs is not relevant in this packet. It is however important in the Resource Pack Stack packet. texture_packs: TexturePackInfos + # ForcingServerPacks is currently an unclear field. + force_server_packs: bool packet_resource_pack_stack: !id: 0x07 @@ -691,6 +693,87 @@ packet_level_event: 4000: set_data 9800: players_sleeping 0x4000: add_particle_mask + # 0x4000 | + particle ID + 16385: particle_bubble # 1 + 16386: particle_bubble_manual # 2 + 16387: particle_critical # 3 + 16388: particle_block_force_field # 4 + 16389: particle_smoke # 5 + 16390: particle_explode # 6 + 16391: particle_evaporation # 7 + 16392: particle_flame # 8 + 16393: particle_candle_flame # 9 + 16394: particle_lava # 10 + 16395: particle_large_smoke # 11 + 16396: particle_redstone # 12 + 16397: particle_rising_red_dust # 13 + 16398: particle_item_break # 14 + 16399: particle_snowball_poof # 15 + 16400: particle_huge_explode # 16 + 16401: particle_huge_explode_seed # 17 + 16402: particle_mob_flame # 18 + 16403: particle_heart # 19 + 16404: particle_terrain # 20 + 16405: particle_town_aura # 21 + 16406: particle_portal # 22 + 16408: particle_water_splash # 24 + 16409: particle_water_splash_manual # 25 + 16410: particle_water_wake # 26 + 16411: particle_drip_water # 27 + 16412: particle_drip_lava # 28 + 16413: particle_drip_honey # 29 + 16414: particle_stalactite_drip_water # 30 + 16415: particle_stalactite_drip_lava # 31 + 16416: particle_falling_dust # 32 + 16417: particle_mob_spell # 33 + 16418: particle_mob_spell_ambient # 34 + 16419: particle_mob_spell_instantaneous # 35 + 16420: particle_ink # 36 + 16421: particle_slime # 37 + 16422: particle_rain_splash # 38 + 16423: particle_villager_angry # 39 + 16424: particle_villager_happy # 40 + 16425: particle_enchantment_table # 41 + 16426: particle_tracking_emitter # 42 + 16427: particle_note # 43 + 16428: particle_witch_spell # 44 + 16429: particle_carrot # 45 + 16430: particle_mob_appearance # 46 + 16431: particle_end_rod # 47 + 16432: particle_dragons_breath # 48 + 16433: particle_spit # 49 + 16434: particle_totem # 50 + 16435: particle_food # 51 + 16436: particle_fireworks_starter # 52 + 16437: particle_fireworks_spark # 53 + 16438: particle_fireworks_overlay # 54 + 16439: particle_balloon_gas # 55 + 16440: particle_colored_flame # 56 + 16441: particle_sparkler # 57 + 16442: particle_conduit # 58 + 16443: particle_bubble_column_up # 59 + 16444: particle_bubble_column_down # 60 + 16445: particle_sneeze # 61 + 16446: particle_shulker_bullet # 62 + 16447: particle_bleach # 63 + 16448: particle_dragon_destroy_block # 64 + 16449: particle_mycelium_dust # 65 + 16450: particle_falling_red_dust # 66 + 16451: particle_campfire_smoke # 67 + 16452: particle_tall_campfire_smoke # 68 + 16453: particle_dragon_breath_fire # 69 + 16454: particle_dragon_breath_trail # 70 + 16455: particle_blue_flame # 71 + 16456: particle_soul # 72 + 16457: particle_obsidian_tear # 73 + 16458: particle_portal_reverse # 74 + 16459: particle_snowflake # 75 + 16460: particle_vibration_signal # 76 + 16461: particle_sculk_sensor_redstone # 77 + 16462: particle_spore_blossom_shower # 78 + 16463: particle_spore_blossom_ambient # 79 + 16464: particle_wax # 80 + 16465: particle_electric_spark # 81 position: vec3f data: zigzag32 @@ -1488,7 +1571,7 @@ packet_available_commands: command_data: []varint name: string description: string - flags: u8 + flags: lu16 permission_level: u8 alias: li32 # The list of overload paramaters for this command @@ -1825,6 +1908,11 @@ packet_set_title: # FadeOutDuration is the duration that the title takes to fade out of the screen of the player. It is # measured in 20ths of a second (AKA in ticks). fade_out_time: zigzag32 + # XUID is the XBOX Live user ID of the player, which will remain consistent as long as the player is + # logged in with the XBOX Live account. It is empty if the user is not logged into its XBL account. + xuid: string + # PlatformOnlineID is either a uint64 or an empty string. + platform_online_id: string packet_add_behavior_tree: !id: 0x59 @@ -1984,7 +2072,16 @@ packet_npc_request: # what the player set in it. command: string # ActionType is the type of the action to execute. - action_type: u8 + action_type: u8 => + 0: set_actions + 1: execute_action + 2: execute_closing_commands + 3: set_name + 4: set_skin + 5: set_interact_text + 6: execute_openining_commands + # SceneName is the name of the scene. + scene_name: string # PhotoTransfer is sent by the server to transfer a photo (image) file to the client. It is typically used # to transfer photos so that the client can display it in a portfolio in Education Edition. @@ -2725,8 +2822,8 @@ InputFlag: [ "bitflags", { "want_down_slow", "want_up_slow", "sprinting", - "ascend_scaffolding", - "descend_scaffolding", + "ascend_block", + "descend_block", "sneak_toggle_down", "persist_sneak", "start_sprinting", @@ -3045,3 +3142,30 @@ packet_remove_volume_entity: # The Runtime Entity ID entity_id: varint64 +# SimulationType is an in-progress packet. We currently do not know the use case. +packet_simulation_type: + !id: 0xa8 + # SimulationType is the simulation type selected + type: u8 => + 0: game + 1: editor + 2: test + 3: invalid + +# NPCDialogue is a packet that allows the client to display dialog boxes for interacting with NPCs. +packet_npc_dialogue: + !id: 0xa9 + # ActorUniqueID is the ID of the NPC being requested. + entity_id: lu64 + # ActionType is the type of action for the packet. + action_type: li32 => + 0: open + 1: close + # Dialogue is the text that the client should see. + dialogue: string + # SceneName is the scene the data was pulled from for the client. + screen_name: string + # NPCName is the name of the NPC to be displayed to the client. + npc_name: string + # ActionJSON is the JSON string of the buttons/actions the server can perform. + action_json: string \ No newline at end of file diff --git a/data/latest/types.yaml b/data/latest/types.yaml index b474e56..f88fba0 100644 --- a/data/latest/types.yaml +++ b/data/latest/types.yaml @@ -1595,6 +1595,8 @@ SoundType: varint => - squid_ink_squirt - glow_squid_ink_squirt - convert_to_stray + - extinguish_candle + - ambient_candle - Undefined # TODO: remove? diff --git a/examples/serverReadmeExample.js b/examples/serverReadmeExample.js index 870aed8..06ab2d9 100644 --- a/examples/serverReadmeExample.js +++ b/examples/serverReadmeExample.js @@ -3,7 +3,7 @@ const bedrock = require('bedrock-protocol') const server = new bedrock.createServer({ host: '0.0.0.0', // optional port: 19132, // optional - version: '1.16.220', // The server version + version: '1.17.10', // The server version motd: { // The message of the day motd: 'Funtime Server', levelName: 'Wonderland' diff --git a/src/options.js b/src/options.js index 4530548..2147252 100644 --- a/src/options.js +++ b/src/options.js @@ -1,9 +1,10 @@ // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson -const CURRENT_VERSION = '1.17.0' +const CURRENT_VERSION = '1.17.10' const Versions = { + '1.17.10': 448, '1.17.0': 440, '1.16.220': 431, '1.16.210': 428, From f530677245858c75d04c259d212e4ba82c753b35 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 17 Jul 2021 05:30:13 -0400 Subject: [PATCH 208/458] Option to use JS implementation of RakNet, fix 1.17.10 issue (#110) * Default to JS implementation of RakNet * update server also, adjust test timeout based on number of versions * 1.17.10: fix texture pack issue, keep raknet default at C++ * force_build --- .github/workflows/ci.yml | 3 +- HISTORY.md | 4 +++ data/1.17.10/protocol.json | 8 ++--- data/latest/proto.yml | 4 +-- docs/API.md | 2 +- index.d.ts | 9 ++++-- package.json | 2 +- src/client.js | 6 ++-- src/createClient.js | 2 +- src/options.js | 6 +++- src/rak.js | 59 ++++++++++++++++++++++++++----------- src/rakWorker.js | 5 ++++ src/server.js | 6 ++-- test/internal.js | 2 +- test/internal.test.js | 3 +- test/vanilla.test.js | 3 +- tools/startVanillaServer.js | 4 +++ 17 files changed, 91 insertions(+), 37 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7803afb..0a1ac07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,8 @@ jobs: strategy: matrix: node-version: [14.x] - + env: + FORCE_BUILD: true steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} diff --git a/HISTORY.md b/HISTORY.md index 71c0f33..1127ef5 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## 3.5.0 +* Add 1.17.10 support [#109](https://github.com/PrismarineJS/bedrock-protocol/pull/109) +* You can switch to the JS implementation of raknet by setting `useNativeRaknet: false` in options. + ## 3.4.0 * Initial 1.17 support [#99](https://github.com/PrismarineJS/bedrock-protocol/pull/99) * update connect version based on ping response & fix typings (u9g) [#101](https://github.com/PrismarineJS/bedrock-protocol/pull/101) diff --git a/data/1.17.10/protocol.json b/data/1.17.10/protocol.json index 1fcbc86..c994942 100644 --- a/data/1.17.10/protocol.json +++ b/data/1.17.10/protocol.json @@ -3780,6 +3780,10 @@ "name": "has_scripts", "type": "bool" }, + { + "name": "force_server_packs", + "type": "bool" + }, { "name": "behaviour_packs", "type": "BehaviourPackInfos" @@ -3787,10 +3791,6 @@ { "name": "texture_packs", "type": "TexturePackInfos" - }, - { - "name": "force_server_packs", - "type": "bool" } ] ], diff --git a/data/latest/proto.yml b/data/latest/proto.yml index 43b79bf..a214676 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -120,14 +120,14 @@ packet_resource_packs_info: must_accept: bool # If scripting is enabled. has_scripts: bool + # ForcingServerPacks is currently an unclear field. + force_server_packs: bool # A list of behaviour packs that the client needs to download before joining the server. # All of these behaviour packs will be applied together. behaviour_packs: BehaviourPackInfos # A list of resource packs that the client needs to download before joining the server. # The order of these resource packs is not relevant in this packet. It is however important in the Resource Pack Stack packet. texture_packs: TexturePackInfos - # ForcingServerPacks is currently an unclear field. - force_server_packs: bool packet_resource_pack_stack: !id: 0x07 diff --git a/docs/API.md b/docs/API.md index 051ea09..35db115 100644 --- a/docs/API.md +++ b/docs/API.md @@ -19,7 +19,7 @@ Returns a `Client` instance and connects to the server. | profilesFolder | *optional* | Where to store cached authentication tokens. Defaults to .minecraft, or the node_modules folder if not found. | | autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | | skipPing | *optional* | Whether pinging the server to check its version should be skipped. | - +| useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. | ## be.createServer(options) : Server diff --git a/index.d.ts b/index.d.ts index d59c8fd..3e9d801 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } @@ -15,7 +15,12 @@ declare module "bedrock-protocol" { port?: number // For the client, if we should login with Microsoft/Xbox Live. // For the server, if we should verify client's authentication with Xbox Live. - offline?: boolean + offline?: boolean, + + // Whether or not to use C++ version of RakNet + useNativeRaknet?: boolean, + // If using JS implementation of RakNet, should we use workers? (This only affects the client) + useRaknetWorker?: boolean } export interface ClientOptions extends Options { diff --git a/package.json b/package.json index 50e85f4..825cde1 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "debug": "^4.3.1", "jose-node-cjs-runtime": "^3.12.1", "jsonwebtoken": "^8.5.1", - "jsp-raknet": "^2.1.0", + "jsp-raknet": "^2.1.3", "minecraft-folder-path": "^1.1.0", "node-fetch": "^2.6.1", "prismarine-nbt": "^1.5.0", diff --git a/src/client.js b/src/client.js index 068dce5..2796546 100644 --- a/src/client.js +++ b/src/client.js @@ -1,6 +1,5 @@ const { ClientStatus, Connection } = require('./connection') const { createDeserializer, createSerializer } = require('./transforms/serializer') -const { RakClient } = require('./rak') const { serialize, isDebug } = require('./datatypes/util') const debug = require('debug')('minecraft-protocol') const Options = require('./options') @@ -21,6 +20,9 @@ class Client extends Connection { super() this.options = { ...Options.defaultOptions, ...options } this.validateOptions() + + const { RakClient } = require('./rak')(this.options.useNativeRaknet) + this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) @@ -30,7 +32,7 @@ class Client extends Connection { const host = this.options.host const port = this.options.port - this.connection = new RakClient({ useWorkers: true, host, port }) + this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port }) this.startGameData = {} this.clientRuntimeId = null diff --git a/src/createClient.js b/src/createClient.js index f8e205a..e79b9a7 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -1,5 +1,5 @@ const { Client } = require('./client') -const { RakClient } = require('./rak') +const { RakClient } = require('./rak')(true) const assert = require('assert') const advertisement = require('./server/advertisement') const { sleep } = require('./datatypes/util') diff --git a/src/options.js b/src/options.js index 2147252..32d7d93 100644 --- a/src/options.js +++ b/src/options.js @@ -21,7 +21,11 @@ const defaultOptions = { // If true, do not authenticate with Xbox Live offline: false, // Milliseconds to wait before aborting connection attempt - connectTimeout: 9000 + connectTimeout: 9000, + // Whether or not to use C++ version of RakNet + useNativeRaknet: true, + // If using JS implementation of RakNet, should we use workers? (This only affects the client) + useRaknetWorkers: true } module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } diff --git a/src/rak.js b/src/rak.js index d8e99ee..32a3b31 100644 --- a/src/rak.js +++ b/src/rak.js @@ -1,12 +1,23 @@ const { EventEmitter } = require('events') const ConnWorker = require('./rakWorker') const { waitFor } = require('./datatypes/util') -// TODO: better way to switch, via an option -try { - var { Client, Server, PacketPriority, PacketReliability } = require('raknet-native') // eslint-disable-line -} catch (e) { - var { Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet') // eslint-disable-line - console.debug('[raknet] native not found, using js', e) + +let Client, Server, PacketPriority, EncapsulatedPacket, PacketReliability, Reliability + +module.exports = nativeRaknet => { + if (nativeRaknet) { + try { + ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-native')) + return { RakServer: RakNativeServer, RakClient: RakNativeClient } + } catch (e) { + ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) + console.debug('[raknet] native not found, using js', e) + console.debug('You can suppress the error above by disabling `useNativeRaknet` in your options') + } + } else { + ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) + } + return { RakServer: RakJsServer, RakClient: RakJsClient } } class RakNativeClient extends EventEmitter { @@ -118,9 +129,10 @@ class RakJsClient extends EventEmitter { this.sendReliable = this.workerSendReliable } else { this.connect = this.plainConnect - this.close = this.plainClose + this.close = reason => this.raknet.close(reason) this.sendReliable = this.plainSendReliable } + this.pongCb = null } workerConnect (host = this.options.host, port = this.options.port) { @@ -137,6 +149,8 @@ class RakJsClient extends EventEmitter { this.onEncapsulated(ecapsulated, address.hash) break } + case 'pong': + this.pongCb?.(evt.args) } }) } @@ -165,12 +179,21 @@ class RakJsClient extends EventEmitter { if (immediate) this.connection.sendQueue() } - plainClose (reason) { - this.raknet.close(reason) - } - - ping () { - // TODO + async ping (timeout = 1000) { + if (this.worker) { + this.worker.postMessage({ type: 'ping' }) + return waitFor(res => { + this.pongCb = data => res(data) + }, timeout, () => { throw new Error('Ping timed out') }) + } else { + if (!this.raknet) this.raknet = new Client(this.options.host, this.options.port) + return waitFor(res => { + this.raknet.ping(data => { + this.raknet.close() + res(data) + }) + }, timeout, () => { throw new Error('Ping timed out') }) + } } } @@ -207,9 +230,11 @@ class RakJsServer extends EventEmitter { this.raknet.on('closeConnection', this.onCloseConnection) this.raknet.on('encapsulated', this.onEncapsulated) } -} -module.exports = { - RakClient: PacketPriority ? RakNativeClient : RakJsClient, - RakServer: PacketPriority ? RakNativeServer : RakJsServer + close () { + // Allow some time for the final packets to come in/out + setTimeout(() => { + this.raknet.close() + }, 40) + } } diff --git a/src/rakWorker.js b/src/rakWorker.js index f6e4046..06cd736 100644 --- a/src/rakWorker.js +++ b/src/rakWorker.js @@ -53,6 +53,11 @@ function main () { } } else if (evt.type === 'close') { raknet.close() + process.exit(0) + } else if (evt.type === 'ping') { + raknet.ping((args) => { + parentPort.postMessage({ type: 'pong', args }) + }) } }) } diff --git a/src/server.js b/src/server.js index eb40a4e..e13ca92 100644 --- a/src/server.js +++ b/src/server.js @@ -1,7 +1,6 @@ const { EventEmitter } = require('events') const { createDeserializer, createSerializer } = require('./transforms/serializer') const { Player } = require('./serverPlayer') -const { RakServer } = require('./rak') const { sleep } = require('./datatypes/util') const { ServerAdvertisement } = require('./server/advertisement') const Options = require('./options') @@ -12,6 +11,9 @@ class Server extends EventEmitter { super() this.options = { ...Options.defaultOptions, ...options } this.validateOptions() + + this.RakServer = require('./rak')(this.options.useNativeRaknet).RakServer + this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) this.advertisement = new ServerAdvertisement(this.options.motd) @@ -66,7 +68,7 @@ class Server extends EventEmitter { } async listen (host = this.options.host, port = this.options.port) { - this.raknet = new RakServer({ host, port }, this) + this.raknet = new this.RakServer({ host, port }, this) try { await this.raknet.listen() } catch (e) { diff --git a/test/internal.js b/test/internal.js index ddfd025..fd318c4 100644 --- a/test/internal.js +++ b/test/internal.js @@ -196,7 +196,7 @@ async function requestChunks (x, z, radius) { return chunks } -async function timedTest (version, timeout = 1000 * 120) { +async function timedTest (version, timeout = 1000 * 220) { await waitFor((res) => { startTest(version, res) }, timeout, () => { diff --git a/test/internal.test.js b/test/internal.test.js index b2a901b..32207e3 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -5,7 +5,8 @@ const { proxyTest } = require('./proxy') const { Versions } = require('../src/options') describe('internal client/server test', function () { - this.timeout(240 * 1000) + const vcount = Object.keys(Versions).length + this.timeout(vcount * 80 * 1000) for (const version in Versions) { it('connects ' + version, async () => { diff --git a/test/vanilla.test.js b/test/vanilla.test.js index 2670223..9cea359 100644 --- a/test/vanilla.test.js +++ b/test/vanilla.test.js @@ -4,7 +4,8 @@ const { clientTest } = require('./vanilla') const { Versions } = require('../src/options') describe('vanilla server test', function () { - this.timeout(220 * 1000) + const vcount = Object.keys(Versions).length + this.timeout(vcount * 80 * 1000) for (const version in Versions) { it('client spawns ' + version, async () => { diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 32d0e0a..8e34794 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -82,6 +82,10 @@ async function startServer (version, onStart, options = {}) { await download(os, version, options.path) configure(options) const handle = run(!onStart) + handle.on('error', (...a) => { + console.warn('*** THE MINECRAFT PROCESS CRASHED ***', a) + handle.kill('SIGKILL') + }) if (onStart) { let stdout = '' handle.stdout.on('data', data => { From 0ab783e1e6985645894abbdd19a64939486472f8 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 17 Jul 2021 15:30:17 -0400 Subject: [PATCH 209/458] Release 3.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 825cde1..eb5cd2d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.4.0", + "version": "3.5.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 3b96765f4534abbc516f4a4be0e4162b8ccdca52 Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Sun, 1 Aug 2021 05:21:34 -0400 Subject: [PATCH 210/458] Update link to proxy / mitm doc (#118) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 765491a..17b75a0 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This is a work in progress. You can track the progress in https://github.com/Pri - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - - [Proxy and mitm connections](docs/API.md) + - [Proxy and mitm connections](docs/API.md#proxy-docs) - Client - Authentication - Encryption From 0437e83fe9f5f51251dc7a89585dc7f7ed0c06be Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 2 Aug 2021 00:34:13 -0400 Subject: [PATCH 211/458] fix 1.17.10 npc packet serialization (#119) --- data/1.17.10/protocol.json | 2 +- data/latest/proto.yml | 2 +- src/client.js | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/data/1.17.10/protocol.json b/data/1.17.10/protocol.json index c994942..21d4fac 100644 --- a/data/1.17.10/protocol.json +++ b/data/1.17.10/protocol.json @@ -8752,7 +8752,7 @@ "type": [ "mapper", { - "type": "li32", + "type": "varint", "mappings": { "0": "open", "1": "close" diff --git a/data/latest/proto.yml b/data/latest/proto.yml index a214676..d2998d1 100644 --- a/data/latest/proto.yml +++ b/data/latest/proto.yml @@ -3158,7 +3158,7 @@ packet_npc_dialogue: # ActorUniqueID is the ID of the NPC being requested. entity_id: lu64 # ActionType is the type of action for the packet. - action_type: li32 => + action_type: varint => 0: open 1: close # Dialogue is the text that the client should see. diff --git a/src/client.js b/src/client.js index 2796546..bf6d167 100644 --- a/src/client.js +++ b/src/client.js @@ -156,7 +156,12 @@ class Client extends Connection { } readPacket (packet) { - const des = this.deserializer.parsePacketBuffer(packet) + try { + var des = this.deserializer.parsePacketBuffer(packet) // eslint-disable-line + } catch (e) { + this.emit('error', e) + return + } const pakData = { name: des.data.name, params: des.data.params } this.inLog?.('-> C', pakData.name, this.options.loggging ? serialize(pakData.params) : '') this.emit('packet', des) From a1fe4802e691b36d23ea94c41ef813a71d536447 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 2 Aug 2021 05:32:43 -0400 Subject: [PATCH 212/458] Release 3.5.1 --- HISTORY.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 1127ef5..ac57572 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,6 @@ +## 3.5.1 +* Fix 1.17.10 npc packet serialization (#119) + ## 3.5.0 * Add 1.17.10 support [#109](https://github.com/PrismarineJS/bedrock-protocol/pull/109) * You can switch to the JS implementation of raknet by setting `useNativeRaknet: false` in options. diff --git a/package.json b/package.json index eb5cd2d..ac23547 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.5.0", + "version": "3.5.1", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 254dbefcd46333b908aee36c02abffb30799b938 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 7 Aug 2021 17:41:01 -0400 Subject: [PATCH 213/458] Add update helper script (#117) * Squashed commit from 'helper' branch * CI: run "update-helper" script on cron * Update index.js * disable proxy test * lint * re-add proxy test with delay * lint * Fix cron time --- .github/helper-bot/github-helper.js | 59 ++++++++++++ .github/helper-bot/index.js | 137 ++++++++++++++++++++++++++++ .github/workflows/ci.yml | 2 - .github/workflows/update-helper.yml | 24 +++++ test/internal.test.js | 4 + test/vanilla.test.js | 2 + 6 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 .github/helper-bot/github-helper.js create mode 100644 .github/helper-bot/index.js create mode 100644 .github/workflows/update-helper.yml diff --git a/.github/helper-bot/github-helper.js b/.github/helper-bot/github-helper.js new file mode 100644 index 0000000..08759b2 --- /dev/null +++ b/.github/helper-bot/github-helper.js @@ -0,0 +1,59 @@ +if (!process.env.CI) { + // mock a bunch of things for testing locally -- https://github.com/actions/toolkit/issues/71 + process.env.GITHUB_REPOSITORY = 'PrismarineJS/bedrock-protocol' + process.env.GITHUB_EVENT_NAME = 'issue_comment' + process.env.GITHUB_SHA = 'cb2fd97b6eae9f2c7fee79d5a86eb9c3b4ac80d8' + process.env.GITHUB_REF = 'refs/heads/master' + process.env.GITHUB_WORKFLOW = 'Issue comments' + process.env.GITHUB_ACTION = 'run1' + process.env.GITHUB_ACTOR = 'test-user' + module.exports = { getIssueStatus: () => ({}), updateIssue: () => {}, createIssue: () => {} } + return +} + +// const { Octokit } = require('@octokit/rest') // https://github.com/octokit/rest.js +const github = require('@actions/github') + +const token = process.env.GITHUB_TOKEN +const octokit = github.getOctokit(token) +const context = github.context + +async function getIssueStatus (title) { + // https://docs.github.com/en/rest/reference/search#search-issues-and-pull-requests + const existingIssues = await octokit.rest.search.issuesAndPullRequests({ + q: `is:issue repo:${process.env.GITHUB_REPOSITORY} in:title ${title}` + }) + // console.log('Existing issues', existingIssues) + const existingIssue = existingIssues.data.items.find(issue => issue.title === title) + + if (!existingIssue) return {} + + return { open: existingIssue.state === 'open', closed: existingIssue.state === 'closed', id: existingIssue.number } +} + +async function updateIssue (id, payload) { + const issue = await octokit.rest.issues.update({ + ...context.repo, + issue_number: id, + body: payload.body + }) + console.log(`Updated issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}`) +} + +async function createIssue (payload) { + const issue = await octokit.rest.issues.create({ + ...context.repo, + ...payload + }) + console.log(`Created issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}`) +} + +async function close (id, reason) { + if (reason) await octokit.rest.issues.createComment({ ...context.repo, issue_number: id, body: reason }) + const issue = await octokit.rest.issues.update({ ...context.repo, issue_number: id, state: 'closed' }) + console.log(`Closed issue ${issue.data.title}#${issue.data.number}: ${issue.data.html_url}`) +} + +if (process.env.CI) { + module.exports = { getIssueStatus, updateIssue, createIssue, close } +} diff --git a/.github/helper-bot/index.js b/.github/helper-bot/index.js new file mode 100644 index 0000000..58d7856 --- /dev/null +++ b/.github/helper-bot/index.js @@ -0,0 +1,137 @@ +// Automatic version update checker for Minecraft bedrock edition. +const fs = require('fs') +const cp = require('child_process') +const helper = require('./github-helper') +const latestVesionEndpoint = 'https://itunes.apple.com/lookup?bundleId=com.mojang.minecraftpe' +const changelogURL = 'https://feedback.minecraft.net/hc/en-us/sections/360001186971-Release-Changelogs' + +// Relevant infomation for us is: +// "version": "1.17.10", +// "currentVersionReleaseDate": "2021-07-13T15:35:49Z", +// "releaseNotes": "What's new in 1.17.10:\nVarious bug fixes", + +function buildFirstIssue (title, result, externalPatches) { + let commitData = '' + let protocolVersion = '?' + const date = new Date(result.currentVersionReleaseDate).toUTCString() + + for (const name in externalPatches) { + commitData += '### ' + name + '\n' + const [patches, diff] = externalPatches[name] + for (const [name, url] of patches) { + commitData += `${name}\n` + } + commitData += `\n**[See the diff between *${result.currentVersionReleaseDate}* and now](${diff})**\n` + } + try { protocolVersion = getProtocolVersion() } catch (e) { console.log(e) } + + return { + title, + body: ` +A new Minecraft Bedrock version is available (as of ${date}), version **${result.version}** + +## Official Changelog +* ${result.releaseNotes} *(via App Store)* +* ${changelogURL} + +## 3rd party protocol patches +${commitData} + +## Protocol Details +(I will close this issue automatically if "${result.version}" is added to index.d.ts on "master" and there are no X's below) + + + + +
Name${result.version}
Protocol ID${protocolVersion}
+ +----- + +🤖 I am a bot, I check for updates every 2 hours without a trigger. You can close this PR to prevent any further updates. + ` + } +} + +function getCommitsInRepo (repo, containing, since) { + const endpoint = `https://api.github.com/repos/${repo}/commits` + console.log('Getting', endpoint) + cp.execSync(`curl -L ${endpoint} -o commits.json`, { stdio: 'inherit', shell: true }) + const commits = JSON.parse(fs.readFileSync('./commits.json', 'utf-8')) + const relevant = [] + for (const commit of commits) { + if (commit.commit.message.includes(containing)) { + console.log('commit url', commit.html_url) + relevant.push([commit.commit.message, commit.html_url]) + } + } + if (since) { + cp.execSync(`curl -L ${endpoint}?since=${since} -o commits.json`, { stdio: 'inherit', shell: true }) + const commits = JSON.parse(fs.readFileSync('./commits.json', 'utf-8')) + const head = commits[0].sha + const tail = commits[commits.length - 1].sha + return [relevant, `https://github.com/${repo}/compare/${tail}..${head}`] + } + return [relevant] +} + +function getProtocolVersion () { + if (!fs.existsSync('./ProtocolInfo.php')) cp.execSync('curl -LO https://raw.githubusercontent.com/pmmp/PocketMine-MP/stable/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php', { stdio: 'inherit', shell: true }) + const currentApi = fs.readFileSync('./ProtocolInfo.php', 'utf-8') + const [, latestProtocolVersion] = currentApi.match(/public const CURRENT_PROTOCOL = (\d+);/) + return latestProtocolVersion +} + +async function fetchLatest () { + if (!fs.existsSync('./results.json')) cp.execSync(`curl -L ${latestVesionEndpoint} -o results.json`, { stdio: 'inherit', shell: true }) + const json = require('./results.json') + const result = json.results[0] + // console.log(json) + + if (!fs.existsSync('./index.d.ts')) cp.execSync('curl -LO https://raw.githubusercontent.com/PrismarineJS/bedrock-protocol/master/index.d.ts', { stdio: 'inherit', shell: true }) + const currentApi = fs.readFileSync('./index.d.ts', 'utf-8') + const supportedVersions = currentApi.match(/type Version = ([^\n]+)/)[1].replace(/\||'/g, ' ').split(' ').map(k => k.trim()).filter(k => k.length) + console.log(supportedVersions) + + let { version, currentVersionReleaseDate, releaseNotes } = result + console.log(version, currentVersionReleaseDate, releaseNotes) + + const title = `Support Minecraft ${result.version}` + + const issueStatus = await helper.getIssueStatus(title) + + if (supportedVersions.includes(version)) { + if (issueStatus.open) { + helper.close(issueStatus.id, `Closing as ${version} is now supported`) + } + console.log('Latest version is supported.') + return + } + + + if (issueStatus.closed) { + // We already made an issue, but someone else already closed it, don't do anything else + console.log('I already made an issue, but it was closed') + return + } + + version = version.replace('.0', '') + const issuePayload = buildFirstIssue(title, result, { + PocketMine: getCommitsInRepo('pmmp/PocketMine-MP', version, currentVersionReleaseDate), + gophertunnel: getCommitsInRepo('Sandertv/gophertunnel', version, currentVersionReleaseDate), + CloudburstMC: getCommitsInRepo('CloudburstMC/Protocol', version, currentVersionReleaseDate) + }) + + if (issueStatus.open) { + helper.updateIssue(issueStatus.id, issuePayload) + } else { + helper.createIssue(issuePayload) + } + + fs.writeFileSync('./issue.md', issuePayload.body) + console.log('OK, wrote to ./issue.md', issuePayload) +} + +fetchLatest() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a1ac07..580260c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,8 +14,6 @@ jobs: strategy: matrix: node-version: [14.x] - env: - FORCE_BUILD: true steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} diff --git a/.github/workflows/update-helper.yml b/.github/workflows/update-helper.yml new file mode 100644 index 0000000..83503ac --- /dev/null +++ b/.github/workflows/update-helper.yml @@ -0,0 +1,24 @@ +name: Update Helper +on: + workflow_dispatch: + schedule: + - cron: "0 */2 * * *" + +jobs: + helper: + name: update-checker + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@master + - name: Set up Node.js + uses: actions/setup-node@master + with: + node-version: 16.0.0 + - name: Install Github Actions toolkit + run: npm i @actions/github + # The env vars contain the relevant trigger information, so we don't need to pass it + - name: Runs helper + run: cd .github/helper-bot && node index.js + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/test/internal.test.js b/test/internal.test.js index 32207e3..d6c11d8 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -3,6 +3,7 @@ const { timedTest } = require('./internal') const { proxyTest } = require('./proxy') const { Versions } = require('../src/options') +const { sleep } = require('../src/datatypes/util') describe('internal client/server test', function () { const vcount = Object.keys(Versions).length @@ -12,6 +13,7 @@ describe('internal client/server test', function () { it('connects ' + version, async () => { console.debug(version) await timedTest(version) + await sleep(100) }) } @@ -19,6 +21,8 @@ describe('internal client/server test', function () { it('proxies ' + version, async () => { console.debug(version) await proxyTest(version) + await sleep(5000) + console.debug('Done', version) }) } }) diff --git a/test/vanilla.test.js b/test/vanilla.test.js index 9cea359..3bae596 100644 --- a/test/vanilla.test.js +++ b/test/vanilla.test.js @@ -2,6 +2,7 @@ const { clientTest } = require('./vanilla') const { Versions } = require('../src/options') +const { sleep } = require('../src/datatypes/util') describe('vanilla server test', function () { const vcount = Object.keys(Versions).length @@ -10,6 +11,7 @@ describe('vanilla server test', function () { for (const version in Versions) { it('client spawns ' + version, async () => { await clientTest(version) + await sleep(100) }) } }) From 8845621e414e8c6c5a19dd8f5880f30419fd6b4d Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 9 Aug 2021 18:24:41 -0400 Subject: [PATCH 214/458] helper-bot: fix API call caching issue Fix issue with server caching the results --- .github/helper-bot/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/helper-bot/index.js b/.github/helper-bot/index.js index 58d7856..63e3988 100644 --- a/.github/helper-bot/index.js +++ b/.github/helper-bot/index.js @@ -2,7 +2,7 @@ const fs = require('fs') const cp = require('child_process') const helper = require('./github-helper') -const latestVesionEndpoint = 'https://itunes.apple.com/lookup?bundleId=com.mojang.minecraftpe' +const latestVesionEndpoint = 'https://itunes.apple.com/lookup?bundleId=com.mojang.minecraftpe&time=' + Date.now() const changelogURL = 'https://feedback.minecraft.net/hc/en-us/sections/360001186971-Release-Changelogs' // Relevant infomation for us is: From 37244db6dc0b44b74cc649d46c7781dd68eca81b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 9 Aug 2021 23:16:17 -0400 Subject: [PATCH 215/458] Run tests on windows, disable proxy test on ubuntu CI runner (#125) --- .github/workflows/ci.yml | 13 +++++++++---- test/internal.test.js | 19 ++++++++++++------- test/proxy.js | 10 ++++++---- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 580260c..79e0818 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,15 +5,20 @@ on: branches: [ '*', '!gh-pages' ] pull_request: branches: [ '*', '!gh-pages' ] + workflow_dispatch: + inputs: + via: + description: 'trigger origin' + required: true jobs: build: - runs-on: ubuntu-latest - timeout-minutes: 10 - strategy: matrix: - node-version: [14.x] + os: [ubuntu-latest, windows-latest] + node-version: [16.x] + runs-on: ${{ matrix.os }} + timeout-minutes: 10 steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} diff --git a/test/internal.test.js b/test/internal.test.js index d6c11d8..6e81c43 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -17,12 +17,17 @@ describe('internal client/server test', function () { }) } - for (const version in Versions) { - it('proxies ' + version, async () => { - console.debug(version) - await proxyTest(version) - await sleep(5000) - console.debug('Done', version) - }) + if (process.env.CI && process.platform === 'linux') { + // Don't run the test, see : + // https://github.com/PrismarineJS/bedrock-protocol/issues/124 + } else { + for (const version in Versions) { + it('proxies ' + version, async () => { + console.debug(version) + await proxyTest(version) + await sleep(5000) + console.debug('Done', version) + }) + } } }) diff --git a/test/proxy.js b/test/proxy.js index 2ea17b9..2d94e05 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -3,9 +3,11 @@ const { sleep, waitFor } = require('../src/datatypes/util') function proxyTest (version, timeout = 1000 * 40) { return waitFor(res => { + const SERVER_PORT = 19000 + ((Math.random() * 100) | 0) + const CLIENT_PORT = 19000 + ((Math.random() * 100) | 0) const server = createServer({ host: '0.0.0.0', // optional - port: 19131, // optional + port: SERVER_PORT, // optional offline: true, version // The server version }) @@ -27,11 +29,11 @@ function proxyTest (version, timeout = 1000 * 40) { offline: true, /* host and port for clients to listen to */ host: '0.0.0.0', - port: 19132, + port: CLIENT_PORT, /* Where to send upstream packets to */ destination: { host: '127.0.0.1', - port: 19131 + port: SERVER_PORT } }) relay.conLog = console.debug @@ -39,7 +41,7 @@ function proxyTest (version, timeout = 1000 * 40) { console.debug('Proxy started', server.options.version) - const client = createClient({ host: '127.0.0.1', version, username: 'Boat', offline: true }) + const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true }) console.debug('Client started') From b3edee0b4aeeee7ce3619b01db0bccdc758bab90 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 9 Aug 2021 23:19:08 -0400 Subject: [PATCH 216/458] helper-bot: fix url escaping --- .github/helper-bot/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/helper-bot/index.js b/.github/helper-bot/index.js index 63e3988..39fd32c 100644 --- a/.github/helper-bot/index.js +++ b/.github/helper-bot/index.js @@ -85,7 +85,7 @@ function getProtocolVersion () { } async function fetchLatest () { - if (!fs.existsSync('./results.json')) cp.execSync(`curl -L ${latestVesionEndpoint} -o results.json`, { stdio: 'inherit', shell: true }) + if (!fs.existsSync('./results.json')) cp.execSync(`curl -L "${latestVesionEndpoint}" -o results.json`, { stdio: 'inherit', shell: true }) const json = require('./results.json') const result = json.results[0] // console.log(json) From 72850b7f601ecd6764ebe75b40f3963ba3a41513 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 10 Aug 2021 01:17:39 -0400 Subject: [PATCH 217/458] helper-bot: handle condition where there are no 3rd party commits The helper-bot will still automatically update the PR if there are new commits while PR is still open --- .github/helper-bot/index.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/helper-bot/index.js b/.github/helper-bot/index.js index 39fd32c..95689f2 100644 --- a/.github/helper-bot/index.js +++ b/.github/helper-bot/index.js @@ -16,12 +16,13 @@ function buildFirstIssue (title, result, externalPatches) { const date = new Date(result.currentVersionReleaseDate).toUTCString() for (const name in externalPatches) { - commitData += '### ' + name + '\n' const [patches, diff] = externalPatches[name] + commitData += '### ' + name + '\n' for (const [name, url] of patches) { commitData += `${name}\n` } - commitData += `\n**[See the diff between *${result.currentVersionReleaseDate}* and now](${diff})**\n` + if (diff) commitData += `\n**[See the diff between *${result.currentVersionReleaseDate}* and now](${diff})**\n` + else commitData += '\n(No changes so far)\n' } try { protocolVersion = getProtocolVersion() } catch (e) { console.log(e) } @@ -70,9 +71,11 @@ function getCommitsInRepo (repo, containing, since) { if (since) { cp.execSync(`curl -L ${endpoint}?since=${since} -o commits.json`, { stdio: 'inherit', shell: true }) const commits = JSON.parse(fs.readFileSync('./commits.json', 'utf-8')) - const head = commits[0].sha - const tail = commits[commits.length - 1].sha - return [relevant, `https://github.com/${repo}/compare/${tail}..${head}`] + if (commits.length) { + const head = commits[0].sha + const tail = commits[commits.length - 1].sha + return [relevant, `https://github.com/${repo}/compare/${tail}..${head}`] + } } return [relevant] } From 2f941335f63fb1df5b5b67c4b609f150113dbc45 Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Tue, 10 Aug 2021 02:36:26 -0400 Subject: [PATCH 218/458] Fix small typo in helper-bot (#128) --- .github/helper-bot/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/helper-bot/index.js b/.github/helper-bot/index.js index 95689f2..e9d5893 100644 --- a/.github/helper-bot/index.js +++ b/.github/helper-bot/index.js @@ -51,7 +51,7 @@ ${commitData} ----- -🤖 I am a bot, I check for updates every 2 hours without a trigger. You can close this PR to prevent any further updates. +🤖 I am a bot, I check for updates every 2 hours without a trigger. You can close this issue to prevent any further updates. ` } } From 2d42caafb9a97701b14f8d4fe4c871f845a3623c Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Tue, 10 Aug 2021 21:17:41 -0400 Subject: [PATCH 219/458] Fix Typo in readme example (#129) * Fix Typo in readme example * ServerAdvertisement: Fix motd name doc/code inconsistency * Update advertisement.js * Update advertisement.js Co-authored-by: extremeheat --- README.md | 2 +- src/server/advertisement.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 17b75a0..04dc13f 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ client.on('text', (packet) => { // Listen for chat messages and echo them back. *Can't connect locally on Windows? See the [faq](docs/FAQ.md)* ```js const bedrock = require('bedrock-protocol') -const server = new bedrock.createServer({ +const server = bedrock.createServer({ host: '0.0.0.0', // optional. host to bind as. port: 19132, // optional version: '1.17.10', // optional. The server version, latest if not specified. diff --git a/src/server/advertisement.js b/src/server/advertisement.js index 3bca141..3a2fee8 100644 --- a/src/server/advertisement.js +++ b/src/server/advertisement.js @@ -12,6 +12,7 @@ class ServerAdvertisement { serverId = '0' constructor (obj, version) { + if (obj?.name) obj.motd = obj.name Object.assign(this, obj) } From 3267bbfca16fd3c154092edccb6468f5717141a0 Mon Sep 17 00:00:00 2001 From: u9g <43508353+u9g@users.noreply.github.com> Date: Thu, 12 Aug 2021 00:05:29 -0400 Subject: [PATCH 220/458] Fix typo in example (#130) --- examples/serverReadmeExample.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/serverReadmeExample.js b/examples/serverReadmeExample.js index 06ab2d9..92039f7 100644 --- a/examples/serverReadmeExample.js +++ b/examples/serverReadmeExample.js @@ -1,6 +1,6 @@ /* eslint-disable */ const bedrock = require('bedrock-protocol') -const server = new bedrock.createServer({ +const server = bedrock.createServer({ host: '0.0.0.0', // optional port: 19132, // optional version: '1.17.10', // The server version @@ -15,4 +15,4 @@ server.on('connect', client => { const d = new Date() // Once client is in the server, send a colorful kick message client.disconnect(`Good ${d.getHours() < 12 ? '§emorning§r' : '§3afternoon§r'} :)\n\nMy time is ${d.toLocaleString()} !`) }) -}) \ No newline at end of file +}) From c5858d5adda866af8ea19f6909ae6296b6c5831a Mon Sep 17 00:00:00 2001 From: Jordan Jones Date: Mon, 16 Aug 2021 04:06:19 -0700 Subject: [PATCH 221/458] Implement Prismarine Auth (#131) * add prismarine-auth and mfp * implement prismarine-auth * putting this on the record, i am stupid * Remove unneeded files * Use export from prismarine-auth * fix cache path * default the authTitle to MNS needs testings * Remove unnecessary comment --- index.js | 4 +- package.json | 11 +- src/client.js | 2 +- src/client/auth.js | 99 +++--- src/client/authConstants.js | 10 - src/client/authFlow.js | 161 ---------- src/client/titles.js | 4 - src/client/tokens.js | 592 ------------------------------------ 8 files changed, 52 insertions(+), 831 deletions(-) delete mode 100644 src/client/authConstants.js delete mode 100644 src/client/authFlow.js delete mode 100644 src/client/titles.js delete mode 100644 src/client/tokens.js diff --git a/index.js b/index.js index e3241a5..dcd3a80 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const { Server } = require('./src/server') const { Relay } = require('./src/relay') const { createClient, ping } = require('./src/createClient') const { createServer } = require('./src/createServer') -const Title = require('./src/client/titles') +const { Titles } = require('prismarine-auth') module.exports = { Client, @@ -18,5 +18,5 @@ module.exports = { createClient, ping, createServer, - title: Title + title: Titles } diff --git a/package.json b/package.json index ac23547..e521bae 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,9 @@ "jose-node-cjs-runtime": "^3.12.1", "jsonwebtoken": "^8.5.1", "jsp-raknet": "^2.1.3", - "minecraft-folder-path": "^1.1.0", + "minecraft-folder-path": "^1.2.0", "node-fetch": "^2.6.1", + "prismarine-auth": "^1.1.0", "prismarine-nbt": "^1.5.0", "protodef": "^1.14.0", "smart-buffer": "^4.1.0", @@ -39,13 +40,13 @@ }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", - "bedrock-provider": "^1.0.0", "babel-eslint": "^10.1.0", + "bedrock-protocol": "file:.", + "bedrock-provider": "^1.0.0", + "leveldb-zlib": "^1.0.1", "mocha": "^8.3.2", "protodef-yaml": "^1.1.0", - "standard": "^16.0.3", - "leveldb-zlib": "^1.0.1", - "bedrock-protocol": "file:." + "standard": "^16.0.3" }, "standard": { "parser": "babel-eslint" diff --git a/src/client.js b/src/client.js index bf6d167..3e4c9b6 100644 --- a/src/client.js +++ b/src/client.js @@ -50,7 +50,7 @@ class Client extends Connection { debug('offline mode, not authenticating', this.options) auth.createOfflineSession(this, this.options) } else { - auth.authenticateDeviceCode(this, this.options) + auth.authenticate(this, this.options) } this.startQueue() diff --git a/src/client/auth.js b/src/client/auth.js index d7ffc8d..bee00f3 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -1,31 +1,48 @@ -const { MsAuthFlow } = require('./authFlow.js') +const path = require('path') +const { Authflow: PrismarineAuth, Titles } = require('prismarine-auth') +const minecraftFolderPath = require('minecraft-folder-path') +const debug = require('debug')('minecraft-protocol') const { uuidFrom } = require('../datatypes/util') /** - * Obtains Minecaft profile data using a Minecraft access token and starts the join sequence + * Authenticates to Minecraft via device code based Microsoft auth, + * then connects to the specified server in Client Options + * + * @function * @param {object} client - The client passed to protocol * @param {object} options - Client Options - * @param {string} chains - Minecraft JWTs to send to server */ -async function postAuthenticate (client, options, chains) { - // First chain is Mojang stuff, second is Xbox profile data used by mc - const jwt = chains[1] - const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) // eslint-disable-line - const xboxProfile = JSON.parse(String(payload)) - - // This profile / session here could be simplified down to where it just passes the uuid of the player to encrypt.js - // That way you could remove some lines of code. It accesses client.session.selectedProfile.id so /shrug. - // - Kashalls - const profile = { - name: xboxProfile?.extraData?.displayName || 'Player', - uuid: xboxProfile?.extraData?.identity || 'adfcf5ca-206c-404a-aec4-f59fff264c9b', // random - xuid: xboxProfile?.extraData?.XUID || 0 +async function authenticate (client, options) { + if (!options.profilesFolder) { + options.profilesFolder = path.join(minecraftFolderPath, 'nmp-cache') } + if (!options.authTitle) { + options.authTitle = Titles.MinecraftNintendoSwitch + } + try { + const Authflow = new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode) + const chains = await Authflow.getMinecraftBedrockToken(client.clientX509) - client.profile = profile - client.username = profile.name - client.accessToken = chains - client.emit('session', profile) + debug('chains', chains) + + // First chain is Mojang stuff, second is Xbox profile data used by mc + const jwt = chains[1] + const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) // eslint-disable-line + const xboxProfile = JSON.parse(String(payload)) + + debug('got xbox profile', xboxProfile) + + const profile = { + name: xboxProfile?.extraData?.displayName || 'Player', + uuid: xboxProfile?.extraData?.identity || 'adfcf5ca-206c-404a-aec4-f59fff264c9b', // random + xuid: xboxProfile?.extraData?.XUID || 0 + } + + return postAuthenticate(client, profile, chains) + } catch (err) { + console.error(err) + client.emit('error', err) + } } /** @@ -38,49 +55,19 @@ function createOfflineSession (client, options) { uuid: uuidFrom(options.username), // random xuid: 0 } + return postAuthenticate(client, profile, []) // No extra JWTs, only send 1 client signed chain with all the data +} + +function postAuthenticate (client, profile, chains) { client.profile = profile client.username = profile.name - client.accessToken = [] // No extra JWTs, only send 1 client signed chain with all the data + client.accessToken = chains client.emit('session', profile) } -/** - * Authenticates with Mincrosoft through user credentials, then - * with Xbox Live, Minecraft, checks entitlements and returns profile - * - * @function - * @param {object} client - The client passed to protocol - * @param {object} options - Client Options - */ -async function authenticatePassword (client, options) { - throw Error('Not implemented') -} - -/** - * Authenticates to Minecraft via device code based Microsoft auth, - * then connects to the specified server in Client Options - * - * @function - * @param {object} client - The client passed to protocol - * @param {object} options - Client Options - */ -async function authenticateDeviceCode (client, options) { - try { - const flow = new MsAuthFlow(options.username, options.profilesFolder, options, options.onMsaCode) - - const chain = await flow.getMinecraftToken(client.clientX509) - // console.log('Chain', chain) - await postAuthenticate(client, options, chain) - } catch (err) { - console.error(err) - client.emit('error', err) - } -} - module.exports = { createOfflineSession, - authenticatePassword, - authenticateDeviceCode + authenticate } // async function msaTest () { diff --git a/src/client/authConstants.js b/src/client/authConstants.js deleted file mode 100644 index 1f5066f..0000000 --- a/src/client/authConstants.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - XSTSRelyingParty: 'https://multiplayer.minecraft.net/', - MinecraftAuth: 'https://multiplayer.minecraft.net/authentication', - XboxDeviceAuth: 'https://device.auth.xboxlive.com/device/authenticate', - XboxTitleAuth: 'https://title.auth.xboxlive.com/title/authenticate', - XstsAuthorize: 'https://xsts.auth.xboxlive.com/xsts/authorize', - - LiveDeviceCodeRequest: 'https://login.live.com/oauth20_connect.srf', - LiveTokenRequest: 'https://login.live.com/oauth20_token.srf' -} diff --git a/src/client/authFlow.js b/src/client/authFlow.js deleted file mode 100644 index 16c6c68..0000000 --- a/src/client/authFlow.js +++ /dev/null @@ -1,161 +0,0 @@ -const crypto = require('crypto') -const path = require('path') -const fs = require('fs') -const debug = require('debug')('minecraft-protocol') -const mcDefaultFolderPath = require('minecraft-folder-path') -const authConstants = require('./authConstants') -const { LiveTokenManager, MsaTokenManager, XboxTokenManager, MinecraftTokenManager } = require('./tokens') - -// Initialize msal -// Docs: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/request.md#public-apis-1 -const msalConfig = { - auth: { - // the minecraft client: - // clientId: "000000004C12AE6F", - clientId: '389b1b32-b5d5-43b2-bddc-84ce938d6737', // token from https://github.com/microsoft/Office365APIEditor - authority: 'https://login.microsoftonline.com/consumers' - } -} - -async function retry (methodFn, beforeRetry, times) { - while (times--) { - if (times !== 0) { - try { return await methodFn() } catch (e) { debug(e) } - await new Promise(resolve => setTimeout(resolve, 2000)) - await beforeRetry() - } else { - return await methodFn() - } - } -} - -class MsAuthFlow { - constructor (username, cacheDir, options = {}, codeCallback) { - this.options = options - this.initTokenCaches(username, cacheDir) - this.codeCallback = codeCallback - } - - initTokenCaches (username, cacheDir) { - const hash = sha1(username).substr(0, 6) - - let cachePath = cacheDir || mcDefaultFolderPath - try { - if (!fs.existsSync(cachePath + '/nmp-cache')) { - fs.mkdirSync(cachePath + '/nmp-cache') - } - cachePath += '/nmp-cache' - } catch (e) { - console.log('Failed to open cache dir', e) - cachePath = __dirname - } - - const cachePaths = { - live: path.join(cachePath, `./${hash}_live-cache.json`), - msa: path.join(cachePath, `./${hash}_msa-cache.json`), - xbl: path.join(cachePath, `./${hash}_xbl-cache.json`), - bed: path.join(cachePath, `./${hash}_bed-cache.json`) - } - - if (this.options.authTitle) { // Login with login.live.com - const scopes = ['service::user.auth.xboxlive.com::MBI_SSL'] - this.msa = new LiveTokenManager(this.options.authTitle, scopes, cachePaths.live) - } else { // Login with microsoftonline.com - const scopes = ['XboxLive.signin', 'offline_access'] - this.msa = new MsaTokenManager(msalConfig, scopes, cachePaths.msa) - } - - const keyPair = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }) - this.xbl = new XboxTokenManager(authConstants.XSTSRelyingParty, keyPair, cachePaths.xbl) - this.mca = new MinecraftTokenManager(cachePaths.bed) - } - - static resetTokenCaches (cacheDir) { - let cachePath = cacheDir || mcDefaultFolderPath - try { - if (fs.existsSync(cachePath + '/nmp-cache')) { - cachePath += '/nmp-cache' - fs.rmdirSync(cachePath, { recursive: true }) - return true - } - } catch (e) { - console.log('Failed to clear cache dir', e) - return false - } - } - - async getMsaToken () { - if (await this.msa.verifyTokens()) { - debug('[msa] Using existing tokens') - return this.msa.getAccessToken().token - } else { - debug('[msa] No valid cached tokens, need to sign in') - const ret = await this.msa.authDeviceCode((response) => { - console.info('[msa] First time signing in. Please authenticate now:') - console.info(response.message) - if (this.codeCallback) this.codeCallback(response) - }) - - if (ret.account) { - console.info(`[msa] Signed in as ${ret.account.username}`) - } else { // We don't get extra account data here per scope - console.info('[msa] Signed in with Microsoft') - } - - debug('[msa] got auth result', ret) - return ret.accessToken - } - } - - async getXboxToken () { - if (await this.xbl.verifyTokens()) { - debug('[xbl] Using existing XSTS token') - return this.xbl.getCachedXstsToken().data - } else { - debug('[xbl] Need to obtain tokens') - return await retry(async () => { - const msaToken = await this.getMsaToken() - const ut = await this.xbl.getUserToken(msaToken, !this.options.authTitle) - - if (this.options.authTitle) { - const deviceToken = await this.xbl.getDeviceToken({ DeviceType: 'Nintendo', Version: '0.0.0' }) - const titleToken = await this.xbl.getTitleToken(msaToken, deviceToken) - const xsts = await this.xbl.getXSTSToken(ut, deviceToken, titleToken) - return xsts - } else { - const xsts = await this.xbl.getXSTSToken(ut) - return xsts - } - }, () => { this.msa.forceRefresh = true }, 2) - } - } - - async getMinecraftToken (publicKey) { - // TODO: Fix cache, in order to do cache we also need to cache the ECDH keys so disable it - // is this even a good idea to cache? - if (await this.mca.verifyTokens() && false) { // eslint-disable-line - debug('[mc] Using existing tokens') - return this.mca.getCachedAccessToken().chain - } else { - if (!publicKey) throw new Error('Need to specifiy a ECDH x509 URL encoded public key') - debug('[mc] Need to obtain tokens') - return await retry(async () => { - const xsts = await this.getXboxToken() - debug('[xbl] xsts data', xsts) - const token = await this.mca.getAccessToken(publicKey, xsts) - // If we want to auth with a title ID, make sure there's a TitleID in the response - const body = JSON.parse(Buffer.from(token.chain[1].split('.')[1], 'base64').toString()) - if (!body.extraData.titleId && this.options.authTitle) { - throw Error('missing titleId in response') - } - return token.chain - }, () => { this.xbl.forceRefresh = true }, 2) - } - } -} - -function sha1 (data) { - return crypto.createHash('sha1').update(data || '', 'binary').digest('hex') -} - -module.exports = { MsAuthFlow } diff --git a/src/client/titles.js b/src/client/titles.js deleted file mode 100644 index 66ca06c..0000000 --- a/src/client/titles.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - MinecraftNintendoSwitch: '00000000441cc96b', - MinecraftJava: '00000000402b5328' -} diff --git a/src/client/tokens.js b/src/client/tokens.js deleted file mode 100644 index f4436d6..0000000 --- a/src/client/tokens.js +++ /dev/null @@ -1,592 +0,0 @@ -const msal = require('@azure/msal-node') -const XboxLiveAuth = require('@xboxreplay/xboxlive-auth') -const debug = require('debug')('minecraft-protocol') -const fs = require('fs') -const path = require('path') -const fetch = require('node-fetch') -const authConstants = require('./authConstants') -const crypto = require('crypto') -const { nextUUID } = require('../datatypes/util') -const { SmartBuffer } = require('smart-buffer') -const jose = require('jose-node-cjs-runtime/jwk/from_key_like') - -class LiveTokenManager { - constructor (clientId, scopes, cacheLocation) { - this.clientId = clientId - this.scopes = scopes - this.cacheLocation = cacheLocation - this.reloadCache() - } - - reloadCache () { - try { - this.cache = require(this.cacheLocation) - } catch (e) { - this.cache = {} - fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) - } - } - - async verifyTokens () { - if (this.forceRefresh) try { await this.refreshTokens() } catch { } - const at = this.getAccessToken() - const rt = this.getRefreshToken() - if (!at || !rt) { - return false - } - debug('[live] have at, rt', at, rt) - if (at.valid && rt) { - return true - } else { - try { - await this.refreshTokens() - return true - } catch (e) { - console.warn('Error refreshing token', e) // TODO: looks like an error happens here - return false - } - } - } - - async refreshTokens () { - const rtoken = this.getRefreshToken() - if (!rtoken) { - throw new Error('Cannot refresh without refresh token') - } - - const codeRequest = { - method: 'post', - body: new URLSearchParams({ scope: this.scopes, client_id: this.clientId, grant_type: 'refresh_token', refresh_token: rtoken.token }).toString(), - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - credentials: 'include' // This cookie handler does not work on node-fetch ... - } - - const token = await fetch(authConstants.LiveTokenRequest, codeRequest).then(checkStatus) - this.updateCachce(token) - return token - } - - getAccessToken () { - const token = this.cache.token - if (!token) return - const until = new Date(token.obtainedOn + token.expires_in) - Date.now() - const valid = until > 1000 - return { valid, until: until, token: token.access_token } - } - - getRefreshToken () { - const token = this.cache.token - if (!token) return - const until = new Date(token.obtainedOn + token.expires_in) - Date.now() - const valid = until > 1000 - return { valid, until: until, token: token.refresh_token } - } - - updateCachce (data) { - data.obtainedOn = Date.now() - this.cache.token = data - fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) - } - - async authDeviceCode (deviceCodeCallback) { - const acquireTime = Date.now() - const codeRequest = { - method: 'post', - body: new URLSearchParams({ scope: this.scopes, client_id: this.clientId, response_type: 'device_code' }).toString(), - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - }, - credentials: 'include' // This cookie handler does not work on node-fetch ... - } - - debug('Requesting live device token', codeRequest) - - const cookies = [] - - const res = await fetch(authConstants.LiveDeviceCodeRequest, codeRequest) - .then(res => { - if (res.status !== 200) { - res.text().then(console.warn) - throw Error('Failed to request live.com device code') - } - for (const cookie of Object.values(res.headers.raw()['set-cookie'])) { - const [keyval] = cookie.split(';') - cookies.push(keyval) - } - return res - }) - .then(checkStatus).then(resp => { - resp.message = `To sign in, use a web browser to open the page ${resp.verification_uri} and enter the code ${resp.user_code} to authenticate.` - deviceCodeCallback(resp) - return resp - }) - const expireTime = acquireTime + (res.expires_in * 1000) - 100 /* for safety */ - - this.polling = true - while (this.polling && expireTime > Date.now()) { - await new Promise(resolve => setTimeout(resolve, res.interval * 1000)) - try { - const verifi = { - method: 'post', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - Cookie: cookies.join('; ') - }, - body: new URLSearchParams({ - client_id: this.clientId, - device_code: res.device_code, - grant_type: 'urn:ietf:params:oauth:grant-type:device_code' - }).toString() - } - - const token = await fetch(authConstants.LiveTokenRequest + '?client_id=' + this.clientId, verifi) - .then(res => res.json()).then(res => { - if (res.error) { - if (res.error === 'authorization_pending') { - debug('[live] Still waiting:', res.error_description) - } else { - throw Error(`Failed to acquire authorization code from device token (${res.error}) - ${res.error_description}`) - } - } else { - return res - } - }) - if (!token) continue - this.updateCachce(token) - this.polling = false - return { accessToken: token.access_token } - } catch (e) { - console.debug(e) - } - } - this.polling = false - throw Error('Authenitcation failed, timed out') - } -} - -// Manages Microsoft account tokens -class MsaTokenManager { - constructor (msalConfig, scopes, cacheLocation) { - this.msaClientId = msalConfig.auth.clientId - this.scopes = scopes - this.cacheLocation = cacheLocation || path.join(__dirname, './msa-cache.json') - - this.reloadCache() - - const beforeCacheAccess = async (cacheContext) => { - cacheContext.tokenCache.deserialize(await fs.promises.readFile(this.cacheLocation, 'utf-8')) - } - - const afterCacheAccess = async (cacheContext) => { - if (cacheContext.cacheHasChanged) { - await fs.promises.writeFile(this.cacheLocation, cacheContext.tokenCache.serialize()) - } - } - - const cachePlugin = { - beforeCacheAccess, - afterCacheAccess - } - - msalConfig.cache = { - cachePlugin - } - this.msalApp = new msal.PublicClientApplication(msalConfig) - this.msalConfig = msalConfig - } - - reloadCache () { - try { - this.msaCache = require(this.cacheLocation) - } catch (e) { - this.msaCache = {} - fs.writeFileSync(this.cacheLocation, JSON.stringify(this.msaCache)) - } - } - - getUsers () { - const accounts = this.msaCache.Account - const users = [] - if (!accounts) return users - for (const account of Object.values(accounts)) { - users.push(account) - } - return users - } - - getAccessToken () { - const tokens = this.msaCache.AccessToken - if (!tokens) return - const account = Object.values(tokens).filter(t => t.client_id === this.msaClientId)[0] - if (!account) { - debug('[msa] No valid access token found', tokens) - return - } - const until = new Date(account.expires_on * 1000) - Date.now() - const valid = until > 1000 - return { valid, until: until, token: account.secret } - } - - getRefreshToken () { - const tokens = this.msaCache.RefreshToken - if (!tokens) return - const account = Object.values(tokens).filter(t => t.client_id === this.msaClientId)[0] - if (!account) { - debug('[msa] No valid refresh token found', tokens) - return - } - return { token: account.secret } - } - - async refreshTokens () { - const rtoken = this.getRefreshToken() - if (!rtoken) { - throw new Error('Cannot refresh without refresh token') - } - const refreshTokenRequest = { - refreshToken: rtoken.token, - scopes: this.scopes - } - - return new Promise((resolve, reject) => { - this.msalApp.acquireTokenByRefreshToken(refreshTokenRequest).then((response) => { - debug('[msa] refreshed token', JSON.stringify(response)) - this.reloadCache() - resolve(response) - }).catch((error) => { - debug('[msa] failed to refresh', JSON.stringify(error)) - reject(error) - }) - }) - } - - async verifyTokens () { - if (this.forceRefresh) try { await this.refreshTokens() } catch { } - const at = this.getAccessToken() - const rt = this.getRefreshToken() - if (!at || !rt) { - return false - } - debug('[msa] have at, rt', at, rt) - if (at.valid && rt) { - return true - } else { - try { - await this.refreshTokens() - return true - } catch (e) { - console.warn('Error refreshing token', e) // TODO: looks like an error happens here - return false - } - } - } - - // Authenticate with device_code flow - async authDeviceCode (dataCallback) { - const deviceCodeRequest = { - deviceCodeCallback: (resp) => { - debug('[msa] device_code response: ', resp) - dataCallback(resp) - }, - scopes: this.scopes - } - - return new Promise((resolve, reject) => { - this.msalApp.acquireTokenByDeviceCode(deviceCodeRequest).then((response) => { - debug('[msa] device_code resp', JSON.stringify(response)) - if (!this.msaCache.Account) this.msaCache.Account = { '': response.account } - resolve(response) - }).catch((error) => { - console.warn('[msa] Error getting device code') - console.debug(JSON.stringify(error)) - reject(error) - }) - }) - } -} - -// Manages Xbox Live tokens for xboxlive.com -class XboxTokenManager { - constructor (relyingParty, ecKey, cacheLocation) { - this.relyingParty = relyingParty - this.key = ecKey - jose.fromKeyLike(ecKey.publicKey).then(jwk => { - this.jwk = { ...jwk, alg: 'ES256', use: 'sig' } - }) - this.cacheLocation = cacheLocation || path.join(__dirname, './xbl-cache.json') - try { - this.cache = require(this.cacheLocation) - } catch (e) { - this.cache = {} - } - - this.headers = { 'Cache-Control': 'no-store, must-revalidate, no-cache', 'x-xbl-contract-version': 1 } - } - - getCachedUserToken () { - const token = this.cache.userToken - if (!token) return - const until = new Date(token.NotAfter) - const dn = Date.now() - const remainingMs = until - dn - const valid = remainingMs > 1000 - return { valid, token: token.Token, data: token } - } - - getCachedXstsToken () { - const token = this.cache.xstsToken - if (!token) return - const until = new Date(token.expiresOn) - const dn = Date.now() - const remainingMs = until - dn - const valid = remainingMs > 1000 - return { valid, token: token.XSTSToken, data: token } - } - - setCachedUserToken (data) { - this.cache.userToken = data - fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) - } - - setCachedXstsToken (data) { - this.cache.xstsToken = data - fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) - } - - async verifyTokens () { - const ut = this.getCachedUserToken() - const xt = this.getCachedXstsToken() - if (!ut || !xt || this.forceRefresh) { - return false - } - debug('[xbl] have user, xsts', ut, xt) - if (ut.valid && xt.valid) { - return true - } else if (ut.valid && !xt.valid) { - try { - await this.getXSTSToken(ut.data) - return true - } catch (e) { - return false - } - } - return false - } - - async getUserToken (msaAccessToken, azure) { - debug('[xbl] obtaining xbox token with ms token', msaAccessToken) - msaAccessToken = (azure ? 'd=' : 't=') + msaAccessToken - const xblUserToken = await XboxLiveAuth.exchangeRpsTicketForUserToken(msaAccessToken) - this.setCachedUserToken(xblUserToken) - debug('[xbl] user token:', xblUserToken) - return xblUserToken - } - - // Make signature for the data being sent to server with our private key; server is sent our public key in plaintext - sign (url, authorizationToken, payload) { - // Their backend servers use Windows epoch timestamps, account for that. The server is very picky, - // bad percision or wrong epoch may fail the request. - const windowsTimestamp = (BigInt((Date.now() / 1000) | 0) + 11644473600n) * 10000000n - // Only the /uri?and-query-string - const pathAndQuery = new URL(url).pathname - - // Allocate the buffer for signature, TS, path, tokens and payload and NUL termination - const allocSize = /* sig */ 5 + /* ts */ 9 + /* POST */ 5 + pathAndQuery.length + 1 + authorizationToken.length + 1 + payload.length + 1 - const buf = SmartBuffer.fromSize(allocSize) - buf.writeInt32BE(1) // Policy Version - buf.writeUInt8(0) - buf.writeBigUInt64BE(windowsTimestamp) - buf.writeUInt8(0) // null term - buf.writeStringNT('POST') - buf.writeStringNT(pathAndQuery) - buf.writeStringNT(authorizationToken) - buf.writeStringNT(payload) - - // Get the signature from the payload - const signature = crypto.sign('SHA256', buf.toBuffer(), { key: this.key.privateKey, dsaEncoding: 'ieee-p1363' }) - - const header = SmartBuffer.fromSize(signature.length + 12) - header.writeInt32BE(1) // Policy Version - header.writeBigUInt64BE(windowsTimestamp) - header.writeBuffer(signature) // Add signature at end of header - - return header.toBuffer() - } - - // If we don't need Xbox Title Authentication, we can have xboxreplay lib - // handle the auth, otherwise we need to build the request ourselves with - // the extra token data. - async getXSTSToken (xblUserToken, deviceToken, titleToken) { - if (deviceToken && titleToken) return this.getXSTSTokenWithTitle(xblUserToken, deviceToken, titleToken) - - debug('[xbl] obtaining xsts token with xbox user token (with XboxReplay)', xblUserToken.Token) - const xsts = await XboxLiveAuth.exchangeUserTokenForXSTSIdentity(xblUserToken.Token, { XSTSRelyingParty: this.relyingParty, raw: false }) - this.setCachedXstsToken(xsts) - debug('[xbl] xsts', xsts) - return xsts - } - - async getXSTSTokenWithTitle (xblUserToken, deviceToken, titleToken, optionalDisplayClaims) { - const userToken = xblUserToken.Token - debug('[xbl] obtaining xsts token with xbox user token', userToken) - - const payload = { - RelyingParty: this.relyingParty, - TokenType: 'JWT', - Properties: { - UserTokens: [userToken], - DeviceToken: deviceToken, - TitleToken: titleToken, - OptionalDisplayClaims: optionalDisplayClaims, - ProofKey: this.jwk, - SandboxId: 'RETAIL' - } - } - - const body = JSON.stringify(payload) - const signature = this.sign(authConstants.XstsAuthorize, '', body).toString('base64') - - const headers = { ...this.headers, Signature: signature } - - const ret = await fetch(authConstants.XstsAuthorize, { method: 'post', headers, body }).then(checkStatus) - const xsts = { - userXUID: ret.DisplayClaims.xui[0].xid || null, - userHash: ret.DisplayClaims.xui[0].uhs, - XSTSToken: ret.Token, - expiresOn: ret.NotAfter - } - - this.setCachedXstsToken(xsts) - debug('[xbl] xsts', xsts) - return xsts - } - - /** - * Requests an Xbox Live-related device token that uniquely links the XToken (aka xsts token) - * @param {{ DeviceType, Version }} asDevice The hardware type and version to auth as, for example Android or Nintendo - */ - async getDeviceToken (asDevice) { - const payload = { - Properties: { - AuthMethod: 'ProofOfPossession', - Id: `{${nextUUID()}}`, - DeviceType: asDevice.DeviceType || 'Android', - SerialNumber: `{${nextUUID()}}`, - Version: asDevice.Version || '10', - ProofKey: this.jwk - }, - RelyingParty: 'http://auth.xboxlive.com', - TokenType: 'JWT' - } - - const body = JSON.stringify(payload) - - const signature = this.sign(authConstants.XboxDeviceAuth, '', body).toString('base64') - - const headers = { ...this.headers, Signature: signature } - - const ret = await fetch(authConstants.XboxDeviceAuth, { method: 'post', headers, body }).then(checkStatus) - debug('Xbox Device Token', ret) - return ret.Token - } - - // This *only* works with live.com auth - async getTitleToken (msaAccessToken, deviceToken) { - const payload = { - Properties: { - AuthMethod: 'RPS', - DeviceToken: deviceToken, - RpsTicket: 't=' + msaAccessToken, - SiteName: 'user.auth.xboxlive.com', - ProofKey: this.jwk - }, - RelyingParty: 'http://auth.xboxlive.com', - TokenType: 'JWT' - } - const body = JSON.stringify(payload) - const signature = this.sign(authConstants.XboxTitleAuth, '', body).toString('base64') - - const headers = { ...this.headers, Signature: signature } - - const ret = await fetch(authConstants.XboxTitleAuth, { method: 'post', headers, body }).then(checkStatus) - debug('Xbox Title Token', ret) - return ret.Token - } -} - -// Manages Minecraft tokens for sessionserver.mojang.com -class MinecraftTokenManager { - constructor (clientPublicKey, cacheLocation) { - this.clientPublicKey = clientPublicKey - this.cacheLocation = cacheLocation || path.join(__dirname, './bed-cache.json') - try { - this.cache = require(this.cacheLocation) - } catch (e) { - this.cache = {} - } - } - - getCachedAccessToken () { - const token = this.cache.mca - debug('[mc] token cache', this.cache) - if (!token) return - debug('Auth token', token) - const jwt = token.chain[0] - const [header, payload, signature] = jwt.split('.').map(k => Buffer.from(k, 'base64')) // eslint-disable-line - - const body = JSON.parse(String(payload)) - const expires = new Date(body.exp * 1000) - const remainingMs = expires - Date.now() - const valid = remainingMs > 1000 - return { valid, until: expires, chain: token.chain } - } - - setCachedAccessToken (data) { - data.obtainedOn = Date.now() - this.cache.mca = data - fs.writeFileSync(this.cacheLocation, JSON.stringify(this.cache)) - } - - async verifyTokens () { - const at = this.getCachedAccessToken() - if (!at || this.forceRefresh) { - return false - } - debug('[mc] have user access token', at) - if (at.valid) { - return true - } - return false - } - - async getAccessToken (clientPublicKey, xsts) { - debug('[mc] authing to minecraft', clientPublicKey, xsts) - const headers = { - 'Content-Type': 'application/json', - 'User-Agent': 'node-minecraft-protocol', - Authorization: `XBL3.0 x=${xsts.userHash};${xsts.XSTSToken}` - } - const MineServicesResponse = await fetch(authConstants.MinecraftAuth, { - method: 'post', - headers, - body: JSON.stringify({ identityPublicKey: clientPublicKey }) - }).then(checkStatus) - - debug('[mc] mc auth response', MineServicesResponse) - this.setCachedAccessToken(MineServicesResponse) - return MineServicesResponse - } -} - -function checkStatus (res) { - if (res.ok) { // res.status >= 200 && res.status < 300 - return res.json() - } else { - debug('Request fail', res) - throw Error(res.statusText) - } -} - -module.exports = { LiveTokenManager, MsaTokenManager, XboxTokenManager, MinecraftTokenManager } From 2056b7e00168a8dc44f8193c50d9115d888b8df7 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Tue, 24 Aug 2021 05:28:55 +0200 Subject: [PATCH 222/458] add protocol doc link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04dc13f..a4ca346 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication and encryption. Help [contribute](CONTRIBUTING.md). -This is a work in progress. You can track the progress in https://github.com/PrismarineJS/bedrock-protocol/pull/34. +[Protocol doc](https://minecraft-data.prismarine.js.org/?v=bedrock_1.17.10&d=protocol) ## Features From 1f7e94e5db4f13c2a4e5af04344e81230471519c Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 18 Sep 2021 19:50:43 -0400 Subject: [PATCH 223/458] Update some examples, cleanup (#136) * Update some examples, cleanup * lint --- AUTHORS.md => docs/AUTHORS.md | 0 .../client.js} | 0 .../clientInternal.js} | 3 +++ .../createClient.js} | 0 .../basicServer.js} | 0 examples/{serverTest.js => server/server.js} | 18 +++++++++++------- examples/{ => server}/serverChunks.js | 6 +----- package.json | 5 ----- src/client/auth.js | 18 ------------------ src/handshake/loginVerify.js | 2 -- tools/startVanillaServer.js | 2 +- 11 files changed, 16 insertions(+), 38 deletions(-) rename AUTHORS.md => docs/AUTHORS.md (100%) rename examples/{clientReadmeExample.js => client/client.js} (100%) rename examples/{clientTest.js => client/clientInternal.js} (92%) rename examples/{createClientExample.js => client/createClient.js} (100%) rename examples/{serverReadmeExample.js => server/basicServer.js} (100%) rename examples/{serverTest.js => server/server.js} (91%) rename examples/{ => server}/serverChunks.js (83%) diff --git a/AUTHORS.md b/docs/AUTHORS.md similarity index 100% rename from AUTHORS.md rename to docs/AUTHORS.md diff --git a/examples/clientReadmeExample.js b/examples/client/client.js similarity index 100% rename from examples/clientReadmeExample.js rename to examples/client/client.js diff --git a/examples/clientTest.js b/examples/client/clientInternal.js similarity index 92% rename from examples/clientTest.js rename to examples/client/clientInternal.js index a6996eb..f30fe23 100644 --- a/examples/clientTest.js +++ b/examples/client/clientInternal.js @@ -1,3 +1,6 @@ +/** + * Do not use this example unless you need to change the login procedure, instead see `client.js`. + */ process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('bedrock-protocol') const { ChunkColumn, Version } = require('bedrock-provider') diff --git a/examples/createClientExample.js b/examples/client/createClient.js similarity index 100% rename from examples/createClientExample.js rename to examples/client/createClient.js diff --git a/examples/serverReadmeExample.js b/examples/server/basicServer.js similarity index 100% rename from examples/serverReadmeExample.js rename to examples/server/basicServer.js diff --git a/examples/serverTest.js b/examples/server/server.js similarity index 91% rename from examples/serverTest.js rename to examples/server/server.js index e299b62..8e4e74d 100644 --- a/examples/serverTest.js +++ b/examples/server/server.js @@ -1,27 +1,31 @@ /** + * This example spawns a client. For a basic server that disconnects users, see "basicServer.js". + * * bedrock-protocol server example; to run this example you need to clone this repo from git. * first need to dump some packets from the vanilla server as there is alot of boilerplate - * to send to clients. + * to send to clients. The `serverChunks.js` contains the chunk loading code. * * In your server implementation, you need to implement each of the following packets to * get a client to spawn like vanilla. You can look at the dumped packets in `data/1.16.10/sample` * * First, dump packets for version 1.16.210 by running `npm run dumpPackets`. + * Then you can run `node server.js ` to start this script. */ process.env.DEBUG = 'minecraft-protocol' // packet logging // const fs = require('fs') -const { Server } = require('../src/server') -const { hasDumps } = require('../tools/genPacketDumps') -const DataProvider = require('../data/provider') -const { waitFor } = require('../src/datatypes/util') +const { Server } = require('bedrock-protocol') + +const { hasDumps } = require('../../tools/genPacketDumps') +const DataProvider = require('../../data/provider') +const { waitFor } = require('../../src/datatypes/util') const { loadWorld } = require('./serverChunks') -async function startServer (version = '1.16.220', ok) { +async function startServer (version = '1.17.10', ok) { if (!hasDumps(version)) { throw Error('You need to dump some packets first. Run tools/genPacketDumps.js') } - const Item = require('../types/Item')(version) + const Item = require('../../types/Item')(version) const port = 19132 const server = new Server({ host: '0.0.0.0', port, version }) let loop diff --git a/examples/serverChunks.js b/examples/server/serverChunks.js similarity index 83% rename from examples/serverChunks.js rename to examples/server/serverChunks.js index 0b711c4..d6fac9c 100644 --- a/examples/serverChunks.js +++ b/examples/server/serverChunks.js @@ -4,7 +4,7 @@ const { LevelDB } = require('leveldb-zlib') const { join } = require('path') async function loadWorld (version) { - const path = join(__dirname, `../tools/bds-${version}/worlds/Bedrock level/db`) + const path = join(__dirname, `../../tools/bds-${version}/worlds/Bedrock level/db`) console.log('Loading world at path', path) // Load world from testing server const db = new LevelDB(path, { createIfMissing: false }) await db.open() @@ -19,11 +19,8 @@ async function loadWorld (version) { for (let cx = cxStart; cx < cxEnd; cx++) { for (let cz = czStart; cz < czEnd; cz++) { - // console.log('reading chunk at ', cx, cz) - const cc = await wp.load(cx, cz, true) if (!cc) { - // console.log('no chunk') continue } const cbuf = await cc.networkEncodeNoCache() @@ -35,7 +32,6 @@ async function loadWorld (version) { blobs: [], payload: cbuf }) - // console.log('Ht',cc.sectionsLen,cc.sections) } } diff --git a/package.json b/package.json index e521bae..44bdda2 100644 --- a/package.json +++ b/package.json @@ -21,18 +21,13 @@ ], "license": "MIT", "dependencies": { - "@azure/msal-node": "^1.1.0", - "@xboxreplay/xboxlive-auth": "^3.3.3", "debug": "^4.3.1", - "jose-node-cjs-runtime": "^3.12.1", "jsonwebtoken": "^8.5.1", "jsp-raknet": "^2.1.3", "minecraft-folder-path": "^1.2.0", - "node-fetch": "^2.6.1", "prismarine-auth": "^1.1.0", "prismarine-nbt": "^1.5.0", "protodef": "^1.14.0", - "smart-buffer": "^4.1.0", "uuid-1345": "^1.0.2" }, "optionalDependencies": { diff --git a/src/client/auth.js b/src/client/auth.js index bee00f3..98c334d 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -69,21 +69,3 @@ module.exports = { createOfflineSession, authenticate } - -// async function msaTest () { -// // MsAuthFlow.resetTokenCaches() - -// await authenticateDeviceCode({ -// connect(...args) { -// console.log('Connecting', args) -// }, -// emit(...e) { -// console.log('Event', e) -// } -// }, {}) -// } - -// // debug with node microsoftAuth.js -// if (!module.parent) { -// msaTest() -// } diff --git a/src/handshake/loginVerify.js b/src/handshake/loginVerify.js index 722dd17..62adc6d 100644 --- a/src/handshake/loginVerify.js +++ b/src/handshake/loginVerify.js @@ -24,7 +24,6 @@ module.exports = (client, server, options) => { for (const token of chain) { const decoded = JWT.verify(token, pubKey, { algorithms: ['ES384'] }) - // console.log('Decoded', decoded) // Check if signed by Mojang key const x5u = getX5U(token) @@ -37,7 +36,6 @@ module.exports = (client, server, options) => { finalKey = decoded.identityPublicKey || finalKey // non pem data = { ...data, ...decoded } } - // console.log('Result', data) if (!didVerify && !options.offline) { client.disconnect('disconnectionScreen.notAuthenticated') diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 8e34794..157f458 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -112,7 +112,7 @@ async function startServerAndWait (version, withTimeout, options) { if (!module.parent) { // if (process.argv.length < 3) throw Error('Missing version argument') - startServer(process.argv[2] || '1.16.201', null, process.argv[3] ? { 'server-port': process.argv[3], 'online-mode': !!process.argv[4] } : undefined) + startServer(process.argv[2] || '1.17.10', null, process.argv[3] ? { 'server-port': process.argv[3], 'online-mode': !!process.argv[4] } : undefined) } module.exports = { fetchLatestStable, startServer, startServerAndWait } From f8ea6c01f43e5daaa71da490cf1c4824ed4b804a Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 25 Sep 2021 16:57:29 -0400 Subject: [PATCH 224/458] Use minecraft-data for protocol data (#126) * use minecraft-data protocol data * use minecraft-data for extra data * Update .npmignore * update skin data * fix example * remove .gitattr * fix mcdata skin import, disable install script --- .gitattributes | 1 - .gitignore | 5 +- .npmignore | 4 +- data/1.16.201/protocol.json | 7171 ----------------------- data/1.16.201/steve.json | 120 - data/1.16.201/steveGeometry.json | 5147 ----------------- data/1.16.201/steveSkin.bin | Bin 262144 -> 0 bytes data/1.16.210/protocol.json | 7798 ------------------------- data/1.16.220/protocol.json | 8795 ----------------------------- data/1.17.0/protocol.json | 8907 ----------------------------- data/1.17.10/protocol.json | 9081 ------------------------------ data/latest/proto.yml | 3171 ----------- data/latest/types.yaml | 1703 ------ data/provider.js | 44 - examples/server/server.js | 4 +- package.json | 2 +- src/createClient.js | 2 +- src/handshake/login.js | 9 +- src/options.js | 12 +- src/transforms/serializer.js | 20 +- test/internal.js | 4 +- tools/compileProtocol.js | 71 +- 22 files changed, 39 insertions(+), 52032 deletions(-) delete mode 100644 .gitattributes delete mode 100644 data/1.16.201/protocol.json delete mode 100644 data/1.16.201/steve.json delete mode 100644 data/1.16.201/steveGeometry.json delete mode 100644 data/1.16.201/steveSkin.bin delete mode 100644 data/1.16.210/protocol.json delete mode 100644 data/1.16.220/protocol.json delete mode 100644 data/1.17.0/protocol.json delete mode 100644 data/1.17.10/protocol.json delete mode 100644 data/latest/proto.yml delete mode 100644 data/latest/types.yaml delete mode 100644 data/provider.js diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index cd19a23..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -data/*/*.json linguist-generated \ No newline at end of file diff --git a/.gitignore b/.gitignore index e698980..72abbbc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,7 @@ package-lock.json __* src/**/*.json # Runtime generated data -data/**/sample -data/**/read.js -data/**/write.js -data/**/size.js +data/ tools/bds* tools/*/* *.txt \ No newline at end of file diff --git a/.npmignore b/.npmignore index c80c616..1dab2b5 100644 --- a/.npmignore +++ b/.npmignore @@ -3,9 +3,9 @@ npm-debug.log __* src/**/*.json # Runtime generated data -data/**/sample +data/ tools/bds* # Extra data examples test -.github \ No newline at end of file +.github diff --git a/data/1.16.201/protocol.json b/data/1.16.201/protocol.json deleted file mode 100644 index d82e626..0000000 --- a/data/1.16.201/protocol.json +++ /dev/null @@ -1,7171 +0,0 @@ -{ - "types": { - "varint32": "varint", - "varint64": "native", - "zigzag32": "native", - "zigzag64": "native", - "uuid": "native", - "byterot": "native", - "bitflags": "native", - "restBuffer": "native", - "encapsulated": "native", - "nbt": "native", - "lnbt": "native", - "nbtLoop": "native", - "enum_size_based_on_values_len": "native", - "MapInfo": "native", - "BehaviourPackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - } - ] - ] - } - ], - "TexturePackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "rtx_enabled", - "type": "bool" - } - ] - ] - } - ], - "ResourcePackIdVersions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "ResourcePackIds": [ - "array", - { - "countType": "li16", - "type": "string" - } - ], - "Experiment": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "enabled", - "type": "bool" - } - ] - ], - "Experiments": [ - "array", - { - "countType": "li32", - "type": "Experiment" - } - ], - "GameMode": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "survival", - "1": "creative", - "2": "adventure", - "3": "survival_spectator", - "4": "creative_spectator", - "5": "fallback" - } - } - ], - "GameRule": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "bool", - "2": "int", - "3": "float" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "bool": "bool", - "int": "zigzag32", - "float": "lf32" - }, - "default": "void" - } - ] - } - ] - ], - "GameRules": [ - "array", - { - "countType": "varint", - "type": "GameRule" - } - ], - "Blob": [ - "container", - [ - { - "name": "hash", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "BlockPalette": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "state", - "type": "nbt" - } - ] - ] - } - ], - "Itemstates": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "runtime_id", - "type": "li16" - }, - { - "name": "component_based", - "type": "bool" - } - ] - ] - } - ], - "Item": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "auxiliary_value", - "type": "zigzag32" - }, - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "zigzag32", - "type": "string" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "zigzag32", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "355": [ - "container", - [ - { - "name": "blocking_tick", - "type": "zigzag64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "vec3i": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "vec3u": [ - "container", - [ - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - } - ] - ], - "vec3f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vec2f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "MetadataDictionary": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "key", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "index", - "1": "health", - "2": "variant", - "3": "color", - "4": "nametag", - "5": "owner_eid", - "6": "target_eid", - "7": "air", - "8": "potion_color", - "9": "potion_ambient", - "10": "jump_duration", - "11": "hurt_time", - "12": "hurt_direction", - "13": "paddle_time_left", - "14": "paddle_time_right", - "15": "experience_value", - "16": "minecart_display_block", - "17": "minecart_display_offset", - "18": "minecart_has_display", - "20": "old_swell", - "21": "swell_dir", - "22": "charge_amount", - "23": "enderman_held_runtime_id", - "24": "entity_age", - "26": "player_flags", - "27": "player_index", - "28": "player_bed_position", - "29": "fireball_power_x", - "30": "fireball_power_y", - "31": "fireball_power_z", - "32": "aux_power", - "33": "fish_x", - "34": "fish_z", - "35": "fish_angle", - "36": "potion_aux_value", - "37": "lead_holder_eid", - "38": "scale", - "39": "interactive_tag", - "40": "npc_skin_id", - "41": "url_tag", - "42": "max_airdata_max_air", - "43": "mark_variant", - "44": "container_type", - "45": "container_base_size", - "46": "container_extra_slots_per_strength", - "47": "block_target", - "48": "wither_invulnerable_ticks", - "49": "wither_target_1", - "50": "wither_target_2", - "51": "wither_target_3", - "52": "aerial_attack", - "53": "boundingbox_width", - "54": "boundingbox_height", - "55": "fuse_length", - "56": "rider_seat_position", - "57": "rider_rotation_locked", - "58": "rider_max_rotation", - "59": "rider_min_rotation", - "60": "area_effect_cloud_radius", - "61": "area_effect_cloud_waiting", - "62": "area_effect_cloud_particle_id", - "63": "shulker_peek_id", - "64": "shulker_attach_face", - "65": "shulker_attached", - "66": "shulker_attach_pos", - "67": "trading_player_eid", - "68": "trading_career", - "69": "has_command_block", - "70": "command_block_command", - "71": "command_block_last_output", - "72": "command_block_track_output", - "73": "controlling_rider_seat_number", - "74": "strength", - "75": "max_strength", - "76": "spell_casting_color", - "77": "limited_life", - "78": "armor_stand_pose_index", - "79": "ender_crystal_time_offset", - "80": "always_show_nametag", - "81": "color_2", - "82": "name_author", - "83": "score_tag", - "84": "balloon_attached_entity", - "85": "pufferfish_size", - "86": "bubble_time", - "87": "agent", - "88": "sitting_amount", - "89": "sitting_amount_previous", - "90": "eating_counter", - "91": "flags_extended", - "92": "laying_amount", - "93": "laying_amount_previous", - "94": "duration", - "95": "spawn_time", - "96": "change_rate", - "97": "change_on_pickup", - "98": "pickup_count", - "99": "interact_text", - "100": "trade_tier", - "101": "max_trade_tier", - "102": "trade_experience", - "103": "skin_id", - "104": "spawning_frames", - "105": "command_block_tick_delay", - "106": "command_block_execute_on_first_tick", - "107": "ambient_sound_interval", - "108": "ambient_sound_interval_range", - "109": "ambient_sound_event_name", - "110": "fall_damage_multiplier", - "111": "name_raw_text", - "112": "can_ride_target", - "113": "low_tier_cured_discount", - "114": "high_tier_cured_discount", - "115": "nearby_cured_discount", - "116": "nearby_cured_discount_timestamp", - "117": "hitbox", - "118": "is_buoyant", - "119": "buoyancy_data" - } - } - ] - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "byte", - "1": "short", - "2": "int", - "3": "float", - "4": "string", - "5": "compound", - "6": "vec3i", - "7": "long", - "8": "vec3f" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "byte": "i8", - "short": "li16", - "int": "zigzag32", - "float": "lf32", - "string": "string", - "compound": "nbt", - "vec3i": "vec3i", - "long": "zigzag64", - "vec3f": "vec3f" - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "Link": [ - "container", - [ - { - "name": "ridden_entity_id", - "type": "zigzag64" - }, - { - "name": "rider_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "immediate", - "type": "bool" - }, - { - "name": "rider_initiated", - "type": "bool" - } - ] - ], - "Links": [ - "array", - { - "countType": "varint", - "type": "Link" - } - ], - "EntityAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "min", - "type": "lf32" - }, - { - "name": "value", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - } - ] - ] - } - ], - "Rotation": [ - "container", - [ - { - "name": "yaw", - "type": "byterot" - }, - { - "name": "pitch", - "type": "byterot" - }, - { - "name": "head_yaw", - "type": "byterot" - } - ] - ], - "BlockCoordinates": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "PlayerAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "min", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - }, - { - "name": "current", - "type": "lf32" - }, - { - "name": "default", - "type": "lf32" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "Transaction": [ - "container", - [ - { - "name": "legacy_request_id", - "type": "zigzag32" - }, - { - "name": "legacy_transactions", - "type": [ - "switch", - { - "compareTo": "legacy_request_id", - "fields": { - "0": "void" - }, - "default": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "changed_slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_id", - "type": "u8" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - }, - { - "name": "transaction_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "inventory_mismatch", - "2": "item_use", - "3": "item_use_on_entity", - "4": "item_release" - } - } - ] - }, - { - "name": "network_ids", - "type": "bool" - }, - { - "name": "inventory_actions", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "container", - "1": "global", - "2": "world_interaction", - "3": "creative", - "100": "craft_slot", - "99999": "craft" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "container": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "creative": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "world_interaction": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "craft": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "craft_slot": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - }, - { - "name": "new_item_stack_id", - "type": [ - "switch", - { - "compareTo": "../network_ids", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - { - "name": "transaction_data", - "type": [ - "switch", - { - "compareTo": "transaction_type", - "fields": { - "normal": "void", - "inventory_mismatch": "void", - "item_use": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "click_block", - "1": "click_air", - "2": "break_block" - } - } - ] - }, - { - "name": "block_position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "hotbar_slot", - "type": "varint" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - }, - { - "name": "block_runtime_id", - "type": "varint" - } - ] - ], - "item_use_on_entity": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "interact", - "1": "attack" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - } - ] - ], - "item_release": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "release", - "1": "consume" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "head_pos", - "type": "vec3f" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "ItemStack": [ - "container", - [ - { - "name": "runtime_id", - "type": "zigzag32" - }, - { - "name": "item", - "type": "Item" - } - ] - ], - "ItemStacks": [ - "array", - { - "countType": "varint", - "type": "ItemStack" - } - ], - "RecipeIngredient": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "network_data", - "type": "zigzag32" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ], - "PotionTypeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "input_item_meta", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "ingredient_meta", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - }, - { - "name": "output_item_meta", - "type": "zigzag32" - } - ] - ] - } - ], - "PotionContainerChangeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - } - ] - ] - } - ], - "Recipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "shapeless", - "1": "shaped", - "2": "furnace", - "3": "furnace_with_metadata", - "4": "multi", - "5": "shulker_box", - "6": "shapeless_chemistry", - "7": "shaped_chemistry" - } - } - ] - }, - { - "name": "recipe", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "shapeless": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "shulker_box": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "shapeless_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "shaped": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "shaped_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "furnace": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "output", - "type": "Item" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "furnace_with_metadata": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "input_meta", - "type": "zigzag32" - }, - { - "name": "output", - "type": "Item" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "multi": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "SkinImage": [ - "container", - [ - { - "name": "width", - "type": "li32" - }, - { - "name": "height", - "type": "li32" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "Skin": [ - "container", - [ - { - "name": "skin_id", - "type": "string" - }, - { - "name": "skin_resource_pack", - "type": "string" - }, - { - "name": "skin_data", - "type": "SkinImage" - }, - { - "name": "animations", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "skin_image", - "type": "SkinImage" - }, - { - "name": "animation_type", - "type": "li32" - }, - { - "name": "animation_frames", - "type": "lf32" - }, - { - "name": "expression_type", - "type": "lf32" - } - ] - ] - } - ] - }, - { - "name": "cape_data", - "type": "SkinImage" - }, - { - "name": "geometry_data", - "type": "string" - }, - { - "name": "animation_data", - "type": "string" - }, - { - "name": "premium", - "type": "string" - }, - { - "name": "persona", - "type": "bool" - }, - { - "name": "cape_on_classic", - "type": "bool" - }, - { - "name": "cape_id", - "type": "string" - }, - { - "name": "full_skin_id", - "type": "string" - }, - { - "name": "arm_size", - "type": "string" - }, - { - "name": "skin_color", - "type": "string" - }, - { - "name": "personal_pieces", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_id", - "type": "string" - }, - { - "name": "piece_type", - "type": "string" - }, - { - "name": "pack_id", - "type": "string" - }, - { - "name": "is_default_piece", - "type": "bool" - }, - { - "name": "product_id", - "type": "string" - } - ] - ] - } - ] - }, - { - "name": "piece_tint_colors", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_type", - "type": "string" - }, - { - "name": "colors", - "type": [ - "array", - { - "countType": "li32", - "type": "string" - } - ] - } - ] - ] - } - ] - } - ] - ], - "PlayerRecords": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "remove" - } - } - ] - }, - { - "name": "records_count", - "type": "varint" - }, - { - "name": "records", - "type": [ - "array", - { - "count": "records_count", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "xbox_user_id", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "build_platform", - "type": "li32" - }, - { - "name": "skin_data", - "type": "Skin" - }, - { - "name": "is_teacher", - "type": "bool" - }, - { - "name": "is_host", - "type": "bool" - } - ] - ], - "remove": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - }, - { - "name": "verified", - "type": [ - "array", - { - "count": "records_count", - "type": "bool" - } - ] - } - ] - ], - "ScoreEntries": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "change", - "1": "remove" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "remove": [ - "container", - [ - { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": "zigzag64", - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "custom_name", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "fake_player": "string" - }, - "default": "void" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "ScoreboardIdentityEntries": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "TYPE_REGISTER_IDENTITY", - "1": "TYPE_CLEAR_IDENTITY" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "TYPE_REGISTER_IDENTITY": "zigzag64" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "Enchant": [ - "container", - [ - { - "name": "id", - "type": "u8" - }, - { - "name": "level", - "type": "u8" - } - ] - ], - "EnchantOptions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "cost", - "type": "varint" - }, - { - "name": "slot_flags", - "type": "li32" - }, - { - "name": "equip_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "held_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "self_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "name", - "type": "string" - }, - { - "name": "option_id", - "type": "zigzag32" - } - ] - ] - } - ], - "StackRequestSlotInfo": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "slot_id", - "type": "u8" - }, - { - "name": "stack_id", - "type": "zigzag32" - } - ] - ], - "ItemStackRequests": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "request_id", - "type": "zigzag32" - }, - { - "name": "actions", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "take", - "1": "place", - "2": "swap", - "3": "drop", - "4": "destroy", - "5": "consume", - "6": "create", - "7": "lab_table_combine", - "8": "beacon_payment", - "9": "craft_recipe", - "10": "craft_recipe_auto", - "11": "craft_creative", - "12": "optional", - "13": "non_implemented", - "14": "results_deprecated" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type_id", - "fields": { - "take": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "place": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "swap": [ - "container", - [ - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "drop": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "randomly", - "type": "bool" - } - ] - ], - "destroy": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "consume": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "create": [ - "container", - [ - { - "name": "result_slot_id", - "type": "u8" - } - ] - ], - "beacon_payment": [ - "container", - [ - { - "name": "primary_effect", - "type": "zigzag32" - }, - { - "name": "secondary_effect", - "type": "zigzag32" - } - ] - ], - "craft_recipe": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_recipe_auto": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_creative": [ - "container", - [ - { - "name": "creative_item_network_id", - "type": "varint32" - } - ] - ], - "optional": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - }, - { - "name": "filtered_string_index", - "type": "li32" - } - ] - ], - "non_implemented": "void", - "results_deprecated": [ - "container", - [ - { - "name": "result_items", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "times_crafted", - "type": "u8" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - { - "name": "custom_names", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ], - "ItemStackResponses": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "result", - "type": "u8" - }, - { - "name": "request_id", - "type": "varint32" - }, - { - "name": "containers", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot", - "type": "u8" - }, - { - "name": "hotbar_slot", - "type": "u8" - }, - { - "name": "count", - "type": "u8" - }, - { - "name": "item_stack_id", - "type": "varint32" - }, - { - "name": "custom_name", - "type": "string" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ] - } - ], - "ItemComponentList": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ] - } - ], - "CommandOrigin": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "player", - "1": "block", - "2": "minecart_block", - "3": "dev_console", - "4": "test", - "5": "automation_player", - "6": "client_automation", - "7": "dedicated_server", - "8": "entity", - "9": "virtual", - "10": "game_argument", - "11": "entity_server" - } - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "player_entity_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "dev_console": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ], - "test": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "WindowID": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowType": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "container", - "1": "workbench", - "2": "furnace", - "3": "enchantment", - "4": "brewing_stand", - "5": "anvil", - "6": "dispenser", - "7": "dropper", - "8": "hopper", - "9": "cauldron", - "10": "minecart_chest", - "11": "minecart_hopper", - "12": "horse", - "13": "beacon", - "14": "structure_editor", - "15": "trading", - "16": "command_block", - "17": "jukebox", - "18": "armor", - "19": "hand", - "20": "compound_creator", - "21": "element_constructor", - "22": "material_reducer", - "23": "lab_table", - "24": "loom", - "25": "lectern", - "26": "grindstone", - "27": "blast_furnace", - "28": "smoker", - "29": "stonecutter", - "30": "cartography", - "31": "hud", - "32": "jigsaw_editor", - "33": "smithing_table" - } - } - ], - "LegacyEntityType": [ - "mapper", - { - "type": "li32", - "mappings": { - "10": "chicken", - "11": "cow", - "12": "pig", - "13": "sheep", - "14": "wolf", - "15": "villager", - "16": "mooshroom", - "17": "squid", - "18": "rabbit", - "19": "bat", - "20": "iron_golem", - "21": "snow_golem", - "22": "ocelot", - "23": "horse", - "24": "donkey", - "25": "mule", - "26": "skeleton_horse", - "27": "zombie_horse", - "28": "polar_bear", - "29": "llama", - "30": "parrot", - "31": "dolphin", - "32": "zombie", - "33": "creeper", - "34": "skeleton", - "35": "spider", - "36": "zombie_pigman", - "37": "slime", - "38": "enderman", - "39": "silverfish", - "40": "cave_spider", - "41": "ghast", - "42": "magma_cube", - "43": "blaze", - "44": "zombie_villager", - "45": "witch", - "46": "stray", - "47": "husk", - "48": "wither_skeleton", - "49": "guardian", - "50": "elder_guardian", - "51": "npc", - "52": "wither", - "53": "ender_dragon", - "54": "shulker", - "55": "endermite", - "56": "agent", - "57": "vindicator", - "58": "phantom", - "61": "armor_stand", - "62": "tripod_camera", - "63": "player", - "64": "item", - "65": "tnt", - "66": "falling_block", - "67": "moving_block", - "68": "xp_bottle", - "69": "xp_orb", - "70": "eye_of_ender_signal", - "71": "ender_crystal", - "72": "fireworks_rocket", - "73": "thrown_trident", - "74": "turtle", - "75": "cat", - "76": "shulker_bullet", - "77": "fishing_hook", - "78": "chalkboard", - "79": "dragon_fireball", - "80": "arrow", - "81": "snowball", - "82": "egg", - "83": "painting", - "84": "minecart", - "85": "fireball", - "86": "splash_potion", - "87": "ender_pearl", - "88": "leash_knot", - "89": "wither_skull", - "90": "boat", - "91": "wither_skull_dangerous", - "93": "lightning_bolt", - "94": "small_fireball", - "95": "area_effect_cloud", - "96": "hopper_minecart", - "97": "tnt_minecart", - "98": "chest_minecart", - "100": "command_block_minecart", - "101": "lingering_potion", - "102": "llama_spit", - "103": "evocation_fang", - "104": "evocation_illager", - "105": "vex", - "106": "ice_bomb", - "107": "balloon", - "108": "pufferfish", - "109": "salmon", - "110": "drowned", - "111": "tropicalfish", - "112": "cod", - "113": "panda" - } - } - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "login", - "2": "play_status", - "3": "server_to_client_handshake", - "4": "client_to_server_handshake", - "5": "disconnect", - "6": "resource_packs_info", - "7": "resource_pack_stack", - "8": "resource_pack_client_response", - "9": "text", - "10": "set_time", - "11": "start_game", - "12": "add_player", - "13": "add_entity", - "14": "remove_entity", - "15": "add_item_entity", - "17": "take_item_entity", - "18": "move_entity", - "19": "move_player", - "20": "rider_jump", - "21": "update_block", - "22": "add_painting", - "23": "tick_sync", - "24": "level_sound_event_old", - "25": "level_event", - "26": "block_event", - "27": "entity_event", - "28": "mob_effect", - "29": "update_attributes", - "30": "inventory_transaction", - "31": "mob_equipment", - "32": "mob_armor_equipment", - "33": "interact", - "34": "block_pick_request", - "35": "entity_pick_request", - "36": "player_action", - "38": "hurt_armor", - "39": "set_entity_data", - "40": "set_entity_motion", - "41": "set_entity_link", - "42": "set_health", - "43": "set_spawn_position", - "44": "animate", - "45": "respawn", - "46": "container_open", - "47": "container_close", - "48": "player_hotbar", - "49": "inventory_content", - "50": "inventory_slot", - "51": "container_set_data", - "52": "crafting_data", - "53": "crafting_event", - "54": "gui_data_pick_item", - "55": "adventure_settings", - "56": "block_entity_data", - "57": "player_input", - "58": "level_chunk", - "59": "set_commands_enabled", - "60": "set_difficulty", - "61": "change_dimension", - "62": "set_player_game_type", - "63": "player_list", - "64": "simple_event", - "65": "event", - "66": "spawn_experience_orb", - "67": "clientbound_map_item_data", - "68": "map_info_request", - "69": "request_chunk_radius", - "70": "chunk_radius_update", - "71": "item_frame_drop_item", - "72": "game_rules_changed", - "73": "camera", - "74": "boss_event", - "75": "show_credits", - "76": "available_commands", - "77": "command_request", - "78": "command_block_update", - "79": "command_output", - "80": "update_trade", - "81": "update_equipment", - "82": "resource_pack_data_info", - "83": "resource_pack_chunk_data", - "84": "resource_pack_chunk_request", - "85": "transfer", - "86": "play_sound", - "87": "stop_sound", - "88": "set_title", - "89": "add_behavior_tree", - "90": "structure_block_update", - "91": "show_store_offer", - "92": "purchase_receipt", - "93": "player_skin", - "94": "sub_client_login", - "95": "initiate_web_socket_connection", - "96": "set_last_hurt_by", - "97": "book_edit", - "98": "npc_request", - "99": "photo_transfer", - "100": "modal_form_request", - "101": "modal_form_response", - "102": "server_settings_request", - "103": "server_settings_response", - "104": "show_profile", - "105": "set_default_game_type", - "106": "remove_objective", - "107": "set_display_objective", - "108": "set_score", - "109": "lab_table", - "110": "update_block_synced", - "111": "move_entity_delta", - "112": "set_scoreboard_identity", - "113": "set_local_player_as_initialized", - "114": "update_soft_enum", - "115": "network_stack_latency", - "117": "script_custom_event", - "118": "spawn_particle_effect", - "119": "available_entity_identifiers", - "120": "level_sound_event_v2", - "121": "network_chunk_publisher_update", - "122": "biome_definition_list", - "123": "level_sound_event", - "124": "level_event_generic", - "125": "lectern_update", - "126": "video_stream_connect", - "127": "add_ecs_entity", - "128": "remove_ecs_entity", - "129": "client_cache_status", - "130": "on_screen_texture_animation", - "131": "map_create_locked_copy", - "132": "structure_template_data_export_request", - "133": "structure_template_data_export_response", - "134": "update_block_properties", - "135": "client_cache_blob_status", - "136": "client_cache_miss_response", - "137": "education_settings", - "139": "multiplayer_settings", - "140": "settings_command", - "141": "anvil_damage", - "142": "completed_using_item", - "143": "network_settings", - "144": "player_auth_input", - "145": "creative_content", - "146": "player_enchant_options", - "147": "item_stack_request", - "148": "item_stack_response", - "149": "player_armor_damage", - "151": "update_player_game_type", - "153": "position_tracking_db_broadcast", - "154": "position_tracking_db_request", - "156": "packet_violation_warning", - "157": "motion_prediction_hints", - "158": "animate_entity", - "159": "camera_shake", - "160": "player_fog", - "161": "correct_player_move_prediction", - "162": "item_component", - "163": "filter_text_packet" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "login": "packet_login", - "play_status": "packet_play_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "tick_sync": "packet_tick_sync", - "level_sound_event_old": "packet_level_sound_event_old", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "inventory_transaction": "packet_inventory_transaction", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "block_pick_request": "packet_block_pick_request", - "entity_pick_request": "packet_entity_pick_request", - "player_action": "packet_player_action", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "player_hotbar": "packet_player_hotbar", - "inventory_content": "packet_inventory_content", - "inventory_slot": "packet_inventory_slot", - "container_set_data": "packet_container_set_data", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "gui_data_pick_item": "packet_gui_data_pick_item", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "level_chunk": "packet_level_chunk", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "simple_event": "packet_simple_event", - "event": "packet_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data": "packet_clientbound_map_item_data", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_frame_drop_item": "packet_item_frame_drop_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "boss_event": "packet_boss_event", - "show_credits": "packet_show_credits", - "available_commands": "packet_available_commands", - "command_request": "packet_command_request", - "command_block_update": "packet_command_block_update", - "command_output": "packet_command_output", - "update_trade": "packet_update_trade", - "update_equipment": "packet_update_equipment", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request", - "transfer": "packet_transfer", - "play_sound": "packet_play_sound", - "stop_sound": "packet_stop_sound", - "set_title": "packet_set_title", - "add_behavior_tree": "packet_add_behavior_tree", - "structure_block_update": "packet_structure_block_update", - "show_store_offer": "packet_show_store_offer", - "purchase_receipt": "packet_purchase_receipt", - "player_skin": "packet_player_skin", - "sub_client_login": "packet_sub_client_login", - "initiate_web_socket_connection": "packet_initiate_web_socket_connection", - "set_last_hurt_by": "packet_set_last_hurt_by", - "book_edit": "packet_book_edit", - "npc_request": "packet_npc_request", - "photo_transfer": "packet_photo_transfer", - "modal_form_request": "packet_modal_form_request", - "modal_form_response": "packet_modal_form_response", - "server_settings_request": "packet_server_settings_request", - "server_settings_response": "packet_server_settings_response", - "show_profile": "packet_show_profile", - "set_default_game_type": "packet_set_default_game_type", - "remove_objective": "packet_remove_objective", - "set_display_objective": "packet_set_display_objective", - "set_score": "packet_set_score", - "lab_table": "packet_lab_table", - "update_block_synced": "packet_update_block_synced", - "move_entity_delta": "packet_move_entity_delta", - "set_scoreboard_identity": "packet_set_scoreboard_identity", - "set_local_player_as_initialized": "packet_set_local_player_as_initialized", - "update_soft_enum": "packet_update_soft_enum", - "network_stack_latency": "packet_network_stack_latency", - "script_custom_event": "packet_script_custom_event", - "spawn_particle_effect": "packet_spawn_particle_effect", - "available_entity_identifiers": "packet_available_entity_identifiers", - "level_sound_event_v2": "packet_level_sound_event_v2", - "network_chunk_publisher_update": "packet_network_chunk_publisher_update", - "biome_definition_list": "packet_biome_definition_list", - "level_sound_event": "packet_level_sound_event", - "level_event_generic": "packet_level_event_generic", - "lectern_update": "packet_lectern_update", - "video_stream_connect": "packet_video_stream_connect", - "add_ecs_entity": "packet_add_ecs_entity", - "remove_ecs_entity": "packet_remove_ecs_entity", - "client_cache_status": "packet_client_cache_status", - "on_screen_texture_animation": "packet_on_screen_texture_animation", - "map_create_locked_copy": "packet_map_create_locked_copy", - "structure_template_data_export_request": "packet_structure_template_data_export_request", - "structure_template_data_export_response": "packet_structure_template_data_export_response", - "update_block_properties": "packet_update_block_properties", - "client_cache_blob_status": "packet_client_cache_blob_status", - "client_cache_miss_response": "packet_client_cache_miss_response", - "education_settings": "packet_education_settings", - "multiplayer_settings": "packet_multiplayer_settings", - "settings_command": "packet_settings_command", - "anvil_damage": "packet_anvil_damage", - "completed_using_item": "packet_completed_using_item", - "network_settings": "packet_network_settings", - "player_auth_input": "packet_player_auth_input", - "creative_content": "packet_creative_content", - "player_enchant_options": "packet_player_enchant_options", - "item_stack_request": "packet_item_stack_request", - "item_stack_response": "packet_item_stack_response", - "player_armor_damage": "packet_player_armor_damage", - "update_player_game_type": "packet_update_player_game_type", - "position_tracking_db_request": "packet_position_tracking_db_request", - "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", - "packet_violation_warning": "packet_packet_violation_warning", - "motion_prediction_hints": "packet_motion_prediction_hints", - "animate_entity": "packet_animate_entity", - "camera_shake": "packet_camera_shake", - "player_fog": "packet_player_fog", - "correct_player_move_prediction": "packet_correct_player_move_prediction", - "item_component": "packet_item_component", - "filter_text_packet": "packet_filter_text_packet" - }, - "default": "void" - } - ] - } - ] - ], - "packet_login": [ - "container", - [ - { - "name": "protocol_version", - "type": "i32" - }, - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "LoginTokens": [ - "container", - [ - { - "name": "identity", - "type": "LittleString" - }, - { - "name": "client", - "type": "LittleString" - } - ] - ], - "packet_play_status": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "i32", - "mappings": { - "0": "login_success", - "1": "failed_client", - "2": "failed_spawn", - "3": "player_spawn", - "4": "failed_invalid_tenant", - "5": "failed_vanilla_edu", - "6": "failed_edu_vanilla", - "7": "failed_server_full" - } - } - ] - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "token", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "behaviour_packs", - "type": "BehaviourPackInfos" - }, - { - "name": "texture_packs", - "type": "TexturePackInfos" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behavior_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "resource_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "refused", - "2": "send_packs", - "3": "have_all_packs", - "4": "completed" - } - } - ] - }, - { - "name": "resourcepackids", - "type": "ResourcePackIds" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "raw", - "1": "chat", - "2": "translation", - "3": "popup", - "4": "jukebox_popup", - "5": "tip", - "6": "system", - "7": "whisper", - "8": "announcement", - "9": "json_whisper", - "10": "json" - } - } - ] - }, - { - "name": "needs_translation", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "chat": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "whisper": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "announcement": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "raw": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "tip": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "system": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json_whisper": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "translation": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "jukebox_popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "xuid", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "zigzag32" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "player_gamemode", - "type": "GameMode" - }, - { - "name": "spawn", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "vec2f" - }, - { - "name": "seed", - "type": "zigzag32" - }, - { - "name": "biome_type", - "type": "li16" - }, - { - "name": "biome_name", - "type": "string" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "generator", - "type": "zigzag32" - }, - { - "name": "world_gamemode", - "type": "GameMode" - }, - { - "name": "difficulty", - "type": "zigzag32" - }, - { - "name": "spawn_position", - "type": "BlockCoordinates" - }, - { - "name": "achievements_disabled", - "type": "bool" - }, - { - "name": "day_cycle_stop_time", - "type": "zigzag32" - }, - { - "name": "edu_offer", - "type": "zigzag32" - }, - { - "name": "edu_features_enabled", - "type": "bool" - }, - { - "name": "edu_product_uuid", - "type": "string" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightning_level", - "type": "lf32" - }, - { - "name": "has_confirmed_platform_locked_content", - "type": "bool" - }, - { - "name": "is_multiplayer", - "type": "bool" - }, - { - "name": "broadcast_to_lan", - "type": "bool" - }, - { - "name": "xbox_live_broadcast_mode", - "type": "varint" - }, - { - "name": "platform_broadcast_mode", - "type": "varint" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - { - "name": "gamerules", - "type": "GameRules" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - }, - { - "name": "bonus_chest", - "type": "bool" - }, - { - "name": "map_enabled", - "type": "bool" - }, - { - "name": "permission_level", - "type": "zigzag32" - }, - { - "name": "server_chunk_tick_range", - "type": "li32" - }, - { - "name": "has_locked_behavior_pack", - "type": "bool" - }, - { - "name": "has_locked_resource_pack", - "type": "bool" - }, - { - "name": "is_from_locked_world_template", - "type": "bool" - }, - { - "name": "msa_gamertags_only", - "type": "bool" - }, - { - "name": "is_from_world_template", - "type": "bool" - }, - { - "name": "is_world_template_option_locked", - "type": "bool" - }, - { - "name": "only_spawn_v1_villagers", - "type": "bool" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "limited_world_width", - "type": "li32" - }, - { - "name": "limited_world_length", - "type": "li32" - }, - { - "name": "is_new_nether", - "type": "bool" - }, - { - "name": "experimental_gameplay_override", - "type": "bool" - }, - { - "name": "level_id", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - }, - { - "name": "premium_world_template_id", - "type": "string" - }, - { - "name": "is_trial", - "type": "bool" - }, - { - "name": "movement_authority", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "client", - "1": "server", - "2": "server_v2_rewind" - } - } - ] - }, - { - "name": "current_tick", - "type": "li64" - }, - { - "name": "enchantment_seed", - "type": "zigzag32" - }, - { - "name": "block_palette", - "type": "BlockPalette" - }, - { - "name": "itemstates", - "type": "Itemstates" - }, - { - "name": "multiplayer_correlation_id", - "type": "string" - }, - { - "name": "server_authoritative_inventory", - "type": "bool" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - }, - { - "name": "links", - "type": "Links" - }, - { - "name": "device_id", - "type": "string" - }, - { - "name": "device_os", - "type": "li32" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "attributes", - "type": "EntityAttributes" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "links", - "type": "Links" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "is_from_fishing", - "type": "bool" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "target", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "Rotation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "normal", - "1": "reset", - "2": "teleport", - "3": "rotation" - } - } - ] - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "ridden_runtime_id", - "type": "varint" - }, - { - "name": "teleport", - "type": [ - "switch", - { - "compareTo": "mode", - "fields": { - "teleport": [ - "container", - [ - { - "name": "cause", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "unknown", - "1": "projectile", - "2": "chorus_fruit", - "3": "command", - "4": "behavior" - } - } - ] - }, - { - "name": "source_entity_type", - "type": "LegacyEntityType" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_rider_jump": [ - "container", - [ - { - "name": "jump_strength", - "type": "zigzag32" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "block_priority", - "type": "varint" - }, - { - "name": "storage", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "direction", - "type": "zigzag32" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_tick_sync": [ - "container", - [ - { - "name": "request_time", - "type": "li64" - }, - { - "name": "response_time", - "type": "li64" - } - ] - ], - "packet_level_sound_event_old": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "zigzag32" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "1000": "sound_click", - "1001": "sound_click_fail", - "1002": "sound_shoot", - "1003": "sound_door", - "1004": "sound_fizz", - "1005": "sound_ignite", - "1007": "sound_ghast", - "1008": "sound_ghast_shoot", - "1009": "sound_blaze_shoot", - "1010": "sound_door_bump", - "1012": "sound_door_crash", - "1018": "sound_enderman_teleport", - "1020": "sound_anvil_break", - "1021": "sound_anvil_use", - "1022": "sound_anvil_fall", - "1030": "sound_pop", - "1032": "sound_portal", - "1040": "sound_itemframe_add_item", - "1041": "sound_itemframe_remove", - "1042": "sound_itemframe_place", - "1043": "sound_itemframe_remove_item", - "1044": "sound_itemframe_rotate_item", - "1050": "sound_camera", - "1051": "sound_orb", - "1052": "sound_totem", - "1060": "sound_armor_stand_break", - "1061": "sound_armor_stand_hit", - "1062": "sound_armor_stand_fall", - "1063": "sound_armor_stand_place", - "2000": "particle_shoot", - "2001": "particle_destroy", - "2002": "particle_splash", - "2003": "particle_eye_despawn", - "2004": "particle_spawn", - "2006": "guardian_curse", - "2008": "particle_block_force_field", - "2009": "particle_projectile_hit", - "2013": "particle_enderman_teleport", - "2014": "particle_punch_block", - "3001": "start_rain", - "3002": "start_thunder", - "3003": "stop_rain", - "3004": "stop_thunder", - "3005": "pause_game", - "3006": "pause_game_no_screen", - "3007": "set_game_speed", - "3500": "redstone_trigger", - "3501": "cauldron_explode", - "3502": "cauldron_dye_armor", - "3503": "cauldron_clean_armor", - "3504": "cauldron_fill_potion", - "3505": "cauldron_take_potion", - "3506": "cauldron_fill_water", - "3507": "cauldron_take_water", - "3508": "cauldron_add_dye", - "3509": "cauldron_clean_banner", - "3600": "block_start_break", - "3601": "block_stop_break", - "4000": "set_data", - "9800": "players_sleeping", - "16384": "add_particle_mask" - } - } - ] - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "sound", - "1": "change_state" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "jump", - "2": "hurt_animation", - "3": "death_animation", - "4": "arm_swing", - "5": "stop_attack", - "6": "tame_fail", - "7": "tame_success", - "8": "shake_wet", - "9": "use_item", - "10": "eat_grass_animation", - "11": "fish_hook_bubble", - "12": "fish_hook_position", - "13": "fish_hook_hook", - "14": "fish_hook_tease", - "15": "squid_ink_cloud", - "16": "zombie_villager_cure", - "18": "respawn", - "19": "iron_golem_offer_flower", - "20": "iron_golem_withdraw_flower", - "21": "love_particles", - "22": "villager_angry", - "23": "villager_happy", - "24": "witch_spell_particles", - "25": "firework_particles", - "26": "in_love_particles", - "27": "silverfish_spawn_animation", - "28": "guardian_attack", - "29": "witch_drink_potion", - "30": "witch_throw_potion", - "31": "minecart_tnt_prime_fuse", - "32": "creeper_prime_fuse", - "33": "air_supply_expired", - "34": "player_add_xp_levels", - "35": "elder_guardian_curse", - "36": "agent_arm_swing", - "37": "ender_dragon_death", - "38": "dust_particles", - "39": "arrow_shake", - "57": "eating_item", - "60": "baby_animal_feed", - "61": "death_smoke_cloud", - "62": "complete_trade", - "63": "remove_leash", - "65": "consume_totem", - "66": "player_check_treasure_hunter_achievement", - "67": "entity_spawn", - "68": "dragon_puke", - "69": "item_entity_merge", - "70": "start_swim", - "71": "balloon_pop", - "72": "treasure_hunt", - "73": "agent_summon", - "74": "charged_crossbow", - "75": "fall" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "zigzag32" - }, - { - "name": "amplifier", - "type": "zigzag32" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "zigzag32" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "attributes", - "type": "PlayerAttributes" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_inventory_transaction": [ - "container", - [ - { - "name": "transaction", - "type": "Transaction" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "windows_id", - "type": "WindowID" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "helmet", - "type": "Item" - }, - { - "name": "chestplate", - "type": "Item" - }, - { - "name": "leggings", - "type": "Item" - }, - { - "name": "boots", - "type": "Item" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "3": "leave_vehicle", - "4": "mouse_over_entity", - "6": "open_inventory" - } - } - ] - }, - { - "name": "target_runtime_entity_id", - "type": "varint" - }, - { - "name": "position", - "type": [ - "switch", - { - "compareTo": "action_id", - "fields": { - "mouse_over_entity": "vec3f", - "leave_vehicle": "vec3f" - }, - "default": "void" - } - ] - } - ] - ], - "packet_block_pick_request": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "add_user_data", - "type": "bool" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_entity_pick_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "lu64" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "action", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "start_break", - "1": "abort_break", - "2": "stop_break", - "3": "get_updated_block", - "4": "drop_item", - "5": "start_sleeping", - "6": "stop_sleeping", - "7": "respawn", - "8": "jump", - "9": "start_sprint", - "10": "stop_sprint", - "11": "start_sneak", - "12": "stop_sneak", - "13": "creative_player_destroy_block", - "14": "dimension_change_ack", - "15": "start_glide", - "16": "stop_glide", - "17": "build_denied", - "18": "continue_break", - "19": "change_skin", - "20": "set_enchatnment_seed", - "21": "swimming", - "22": "stop_swimming", - "23": "start_spin_attack", - "24": "stop_spin_attack", - "25": "ineract_block" - } - } - ] - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "tick", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "velocity", - "type": "vec3f" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "link", - "type": "Link" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "spawn_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "player", - "1": "world" - } - } - ] - }, - { - "name": "player_position", - "type": "BlockCoordinates" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "world_position", - "type": "BlockCoordinates" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": "zigzag32" - }, - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "state", - "type": "u8" - }, - { - "name": "runtime_entity_id", - "type": "varint" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "runtime_entity_id", - "type": "zigzag64" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "server", - "type": "bool" - } - ] - ], - "packet_player_hotbar": [ - "container", - [ - { - "name": "selected_slot", - "type": "varint" - }, - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "select_slot", - "type": "bool" - } - ] - ], - "packet_inventory_content": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - }, - { - "name": "input", - "type": "ItemStacks" - } - ] - ], - "packet_inventory_slot": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "ItemStack" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "property", - "type": "zigzag32" - }, - { - "name": "value", - "type": "zigzag32" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "Recipes" - }, - { - "name": "potion_type_recipes", - "type": "PotionTypeRecipes" - }, - { - "name": "potion_container_recipes", - "type": "PotionContainerChangeRecipes" - }, - { - "name": "is_clean", - "type": "bool" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "recipe_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "inventory", - "1": "crafting", - "2": "workbench" - } - } - ] - }, - { - "name": "recipe_id", - "type": "uuid" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "result", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - } - ] - ], - "packet_gui_data_pick_item": [ - "container", - [] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "AdventureFlags" - }, - { - "name": "command_permission", - "type": [ - "mapper", - { - "type": "varint32", - "mappings": { - "0": "normal", - "1": "operator", - "2": "host", - "3": "automation", - "4": "admin" - } - } - ] - }, - { - "name": "action_permissions", - "type": "ActionPermissions" - }, - { - "name": "permission_level", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "visitor", - "1": "member", - "2": "operator", - "3": "custom" - } - } - ] - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "jumping", - "type": "bool" - }, - { - "name": "sneaking", - "type": "bool" - } - ] - ], - "packet_level_chunk": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "sub_chunk_count", - "type": "varint" - }, - { - "name": "cache_enabled", - "type": "bool" - }, - { - "name": "blobs", - "type": [ - "switch", - { - "compareTo": "cache_enabled", - "fields": { - "true": [ - "container", - [ - { - "name": "hashes", - "type": [ - "array", - { - "countType": "varint", - "type": "lu64" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "respawn", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "PlayerRecords" - } - ] - ], - "packet_simple_event": [ - "container", - [ - { - "name": "event_type", - "type": "lu16" - } - ] - ], - "packet_event": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint64" - }, - { - "name": "event_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "achievement_awarded", - "1": "entity_interact", - "2": "portal_built", - "3": "portal_used", - "4": "mob_killed", - "5": "cauldron_used", - "6": "player_death", - "7": "boss_killed", - "8": "agent_command", - "9": "agent_created", - "10": "banner_pattern_removed", - "11": "commaned_executed", - "12": "fish_bucketed", - "13": "mob_born", - "14": "pet_died", - "15": "cauldron_block_used", - "16": "composter_block_used", - "17": "bell_block_used" - } - } - ] - }, - { - "name": "use_player_id", - "type": "u8" - }, - { - "name": "event_data", - "type": "restBuffer" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ], - "packet_clientbound_map_item_data": [ - "container", - [ - { - "name": "mapinfo", - "type": "MapInfo" - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_item_frame_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - } - ] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "GameRules" - } - ] - ], - "packet_camera": [ - "container", - [ - { - "name": "camera_entity_unique_id", - "type": "zigzag64" - }, - { - "name": "target_player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_boss_event": [ - "container", - [ - { - "name": "boss_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "show_bar", - "1": "register_player", - "2": "hide_bar", - "3": "unregister_player", - "4": "set_bar_progress", - "5": "set_bar_title", - "6": "update_properties", - "7": "texture" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "register_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "unregister_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "show": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "bar_progress", - "type": "lf32" - } - ] - ], - "update_properties": [ - "container", - [ - { - "name": "darkness_factor", - "type": "li16" - } - ] - ], - "texture": [ - "container", - [ - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "set_bar_progress": [ - "container", - [ - { - "name": "bar_progress", - "type": "lf32" - } - ] - ], - "set_bar_title": [ - "container", - [ - { - "name": "title", - "type": "string" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_show_credits": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "status", - "type": "zigzag32" - } - ] - ], - "packet_available_commands": [ - "container", - [ - { - "name": "values_len", - "type": "varint" - }, - { - "name": "_enum_type", - "type": [ - "enum_size_based_on_values_len" - ] - }, - { - "name": "enum_values", - "type": [ - "array", - { - "count": "values_len", - "type": "string" - } - ] - }, - { - "name": "suffixes", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - }, - { - "name": "enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "switch", - { - "compareTo": "../_enum_type", - "fields": { - "byte": "u8", - "short": "lu16", - "int": "lu32" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "command_data", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "description", - "type": "string" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "permission_level", - "type": "u8" - }, - { - "name": "alias", - "type": "li32" - }, - { - "name": "overloads", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "paramater_name", - "type": "string" - }, - { - "name": "value_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "1": "int", - "2": "float", - "3": "value", - "4": "wildcard_int", - "5": "operator", - "6": "target", - "14": "file_path", - "29": "string", - "37": "position", - "41": "message", - "43": "raw_text", - "46": "json", - "53": "command" - } - } - ] - }, - { - "name": "enum_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "16": "valid", - "32": "enum", - "256": "suffixed", - "1024": "soft_enum" - } - } - ] - }, - { - "name": "optional", - "type": "bool" - }, - { - "name": "options", - "type": "CommandFlags" - } - ] - ] - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "dynamic_enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "enum_constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "value_index", - "type": "li32" - }, - { - "name": "enum_index", - "type": "li32" - }, - { - "name": "constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "constraint", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "cheats_enabled" - } - } - ] - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_command_request": [ - "container", - [ - { - "name": "command", - "type": "string" - }, - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "interval", - "type": "bool" - } - ] - ], - "packet_command_block_update": [ - "container", - [ - { - "name": "is_block", - "type": "bool" - } - ] - ], - "packet_command_output": [ - "container", - [ - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "output_type", - "type": "i8" - }, - { - "name": "success_count", - "type": "varint" - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "success", - "type": "bool" - }, - { - "name": "message_id", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_update_trade": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "varint" - }, - { - "name": "trade_tier", - "type": "varint" - }, - { - "name": "villager_unique_id", - "type": "varint64" - }, - { - "name": "entity_unique_id", - "type": "varint64" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "new_trading_ui", - "type": "bool" - }, - { - "name": "economic_trades", - "type": "bool" - }, - { - "name": "offers", - "type": "nbt" - } - ] - ], - "packet_update_equipment": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "inventory", - "type": "nbt" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "max_chunk_size", - "type": "lu32" - }, - { - "name": "chunk_count", - "type": "lu32" - }, - { - "name": "compressed_package_size", - "type": "lu64" - }, - { - "name": "hash", - "type": "ByteArray" - }, - { - "name": "is_premium", - "type": "bool" - }, - { - "name": "pack_type", - "type": "u8" - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - }, - { - "name": "progress", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "server_address", - "type": "string" - }, - { - "name": "port", - "type": "lu16" - } - ] - ], - "packet_play_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "volume", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - } - ] - ], - "packet_stop_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "stop_all", - "type": "bool" - } - ] - ], - "packet_set_title": [ - "container", - [ - { - "name": "type", - "type": "zigzag32" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "fade_in_time", - "type": "zigzag32" - }, - { - "name": "stay_time", - "type": "zigzag32" - }, - { - "name": "fade_out_time", - "type": "zigzag32" - } - ] - ], - "packet_add_behavior_tree": [ - "container", - [ - { - "name": "behaviortree", - "type": "string" - } - ] - ], - "packet_structure_block_update": [ - "container", - [] - ], - "packet_show_store_offer": [ - "container", - [ - { - "name": "unknown0", - "type": "string" - }, - { - "name": "unknown1", - "type": "bool" - } - ] - ], - "packet_purchase_receipt": [ - "container", - [] - ], - "packet_player_skin": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "skin", - "type": "Skin" - }, - { - "name": "skin_name", - "type": "string" - }, - { - "name": "old_skin_name", - "type": "string" - }, - { - "name": "is_verified", - "type": "bool" - } - ] - ], - "packet_sub_client_login": [ - "container", - [] - ], - "packet_initiate_web_socket_connection": [ - "container", - [ - { - "name": "server", - "type": "string" - } - ] - ], - "packet_set_last_hurt_by": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_book_edit": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "replace_page", - "1": "add_page", - "2": "delete_page", - "3": "swap_pages", - "4": "sign" - } - } - ] - }, - { - "name": "slot", - "type": "u8" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "replace_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "add_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "delete_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - } - ] - ], - "swap_pages": [ - "container", - [ - { - "name": "page1", - "type": "u8" - }, - { - "name": "page2", - "type": "u8" - } - ] - ], - "sign": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "author", - "type": "string" - }, - { - "name": "xuid", - "type": "string" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_npc_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint" - }, - { - "name": "unknown0", - "type": "u8" - }, - { - "name": "unknown1", - "type": "string" - }, - { - "name": "unknown2", - "type": "u8" - } - ] - ], - "packet_photo_transfer": [ - "container", - [ - { - "name": "file_name", - "type": "string" - }, - { - "name": "image_data", - "type": "string" - }, - { - "name": "unknown2", - "type": "string" - } - ] - ], - "packet_modal_form_request": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_modal_form_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_server_settings_request": [ - "container", - [] - ], - "packet_server_settings_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_show_profile": [ - "container", - [ - { - "name": "xuid", - "type": "string" - } - ] - ], - "packet_set_default_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_remove_objective": [ - "container", - [ - { - "name": "objective_name", - "type": "string" - } - ] - ], - "packet_set_display_objective": [ - "container", - [ - { - "name": "display_slot", - "type": "string" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "criteria_name", - "type": "string" - }, - { - "name": "sort_order", - "type": "zigzag32" - } - ] - ], - "packet_set_score": [ - "container", - [ - { - "name": "entries", - "type": "ScoreEntries" - } - ] - ], - "packet_lab_table": [ - "container", - [ - { - "name": "useless_byte", - "type": "u8" - }, - { - "name": "lab_table_x", - "type": "varint" - }, - { - "name": "lab_table_y", - "type": "varint" - }, - { - "name": "lab_table_z", - "type": "varint" - }, - { - "name": "reaction_type", - "type": "u8" - } - ] - ], - "packet_update_block_synced": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "block_priority", - "type": "varint" - }, - { - "name": "data_layer_id", - "type": "varint" - }, - { - "name": "unknown0", - "type": "varint" - }, - { - "name": "unknown1", - "type": "varint" - } - ] - ], - "packet_move_entity_delta": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "DeltaMoveFlags" - }, - { - "name": "x", - "type": [ - "switch", - { - "compareTo": "flags.has_x", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "y", - "type": [ - "switch", - { - "compareTo": "flags.has_y", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "z", - "type": [ - "switch", - { - "compareTo": "flags.has_z", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "rot_x", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_x", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_y", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_y", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_z", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_z", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_scoreboard_identity": [ - "container", - [ - { - "name": "entries", - "type": "ScoreboardIdentityEntries" - } - ] - ], - "packet_set_local_player_as_initialized": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_update_soft_enum": [ - "container", - [] - ], - "packet_network_stack_latency": [ - "container", - [ - { - "name": "timestamp", - "type": "lu64" - }, - { - "name": "unknown_flag", - "type": "u8" - } - ] - ], - "packet_script_custom_event": [ - "container", - [ - { - "name": "event_name", - "type": "string" - }, - { - "name": "event_data", - "type": "string" - } - ] - ], - "packet_spawn_particle_effect": [ - "container", - [ - { - "name": "dimension_id", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "particle_name", - "type": "string" - } - ] - ], - "packet_available_entity_identifiers": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event_v2": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_network_chunk_publisher_update": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "radius", - "type": "varint" - } - ] - ], - "packet_biome_definition_list": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "varint" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event_generic": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "nbt", - "type": "nbtLoop" - } - ] - ], - "packet_lectern_update": [ - "container", - [ - { - "name": "page", - "type": "u8" - }, - { - "name": "page_count", - "type": "u8" - }, - { - "name": "position", - "type": "vec3i" - }, - { - "name": "drop_book", - "type": "bool" - } - ] - ], - "packet_video_stream_connect": [ - "container", - [ - { - "name": "server_uri", - "type": "string" - }, - { - "name": "frame_send_frequency", - "type": "lf32" - }, - { - "name": "action", - "type": "u8" - }, - { - "name": "resolution_x", - "type": "li32" - }, - { - "name": "resolution_y", - "type": "li32" - } - ] - ], - "packet_add_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_remove_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_client_cache_status": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_on_screen_texture_animation": [ - "container", - [] - ], - "packet_map_create_locked_copy": [ - "container", - [] - ], - "packet_structure_template_data_export_request": [ - "container", - [] - ], - "packet_structure_template_data_export_response": [ - "container", - [] - ], - "packet_update_block_properties": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_client_cache_blob_status": [ - "container", - [ - { - "name": "misses", - "type": "varint" - }, - { - "name": "haves", - "type": "varint" - }, - { - "name": "missing", - "type": [ - "array", - { - "count": "misses", - "type": "lu64" - } - ] - }, - { - "name": "have", - "type": [ - "array", - { - "count": "haves", - "type": "lu64" - } - ] - } - ] - ], - "packet_client_cache_miss_response": [ - "container", - [ - { - "name": "blobs", - "type": [ - "array", - { - "countType": "varint", - "type": "Blob" - } - ] - } - ] - ], - "packet_education_settings": [ - "container", - [ - { - "name": "CodeBuilderDefaultURI", - "type": "string" - }, - { - "name": "CodeBuilderTitle", - "type": "string" - }, - { - "name": "CanResizeCodeBuilder", - "type": "bool" - }, - { - "name": "HasOverrideURI", - "type": "bool" - }, - { - "name": "OverrideURI", - "type": [ - "switch", - { - "compareTo": "HasOverrideURI", - "fields": { - "true": "string" - }, - "default": "void" - } - ] - }, - { - "name": "HasQuiz", - "type": "bool" - } - ] - ], - "packet_multiplayer_settings": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "enable_multiplayer", - "1": "disable_multiplayer", - "2": "refresh_join_code" - } - } - ] - } - ] - ], - "packet_settings_command": [ - "container", - [ - { - "name": "command_line", - "type": "string" - }, - { - "name": "suppress_output", - "type": "bool" - } - ] - ], - "packet_anvil_damage": [ - "container", - [ - { - "name": "damage", - "type": "u8" - }, - { - "name": "position", - "type": "BlockCoordinates" - } - ] - ], - "packet_completed_using_item": [ - "container", - [ - { - "name": "used_item_id", - "type": "li16" - }, - { - "name": "use_method", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "equip_armor", - "1": "eat", - "2": "attack", - "3": "consume", - "4": "throw", - "5": "shoot", - "6": "place", - "7": "fill_bottle", - "8": "fill_bucket", - "9": "pour_bucket", - "10": "use_tool", - "11": "interact", - "12": "retrieved", - "13": "dyed", - "14": "traded" - } - } - ] - } - ] - ], - "packet_network_settings": [ - "container", - [ - { - "name": "compression_threshold", - "type": "u16" - } - ] - ], - "packet_player_auth_input": [ - "container", - [ - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "move_vector", - "type": "vec2f" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "input_data", - "type": "InputFlag" - }, - { - "name": "input_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "mouse", - "1": "touch", - "2": "game_pad", - "3": "motion_controller" - } - } - ] - }, - { - "name": "play_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "teaser", - "2": "screen", - "3": "viewer", - "4": "reality", - "5": "placement", - "6": "living_room", - "7": "exit_level", - "8": "exit_level_living_room", - "9": "num_modes" - } - } - ] - }, - { - "name": "gaze_direction", - "type": [ - "switch", - { - "compareTo": "play_mode", - "fields": { - "reality": "vec3f" - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - }, - { - "name": "delta", - "type": "vec3f" - } - ] - ], - "packet_creative_content": [ - "container", - [ - { - "name": "items", - "type": "ItemStacks" - } - ] - ], - "packet_player_enchant_options": [ - "container", - [ - { - "name": "enchant_options", - "type": "EnchantOptions" - } - ] - ], - "packet_item_stack_request": [ - "container", - [ - { - "name": "requests", - "type": "ItemStackRequests" - } - ] - ], - "packet_item_stack_response": [ - "container", - [ - { - "name": "responses", - "type": "ItemStackResponses" - } - ] - ], - "packet_player_armor_damage": [ - "container", - [ - { - "name": "type", - "type": "ArmorDamageType" - }, - { - "name": "helmet_damage", - "type": [ - "switch", - { - "compareTo": "type.head", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "chestplate_damage", - "type": [ - "switch", - { - "compareTo": "type.chest", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "leggings_damage", - "type": [ - "switch", - { - "compareTo": "type.legs", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "boots_damage", - "type": [ - "switch", - { - "compareTo": "types.feet", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - }, - { - "name": "player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_position_tracking_db_request": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "query" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - } - ] - ], - "packet_position_tracking_db_broadcast": [ - "container", - [ - { - "name": "broadcast_action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "update", - "1": "destory", - "2": "not_found" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_packet_violation_warning": [ - "container", - [ - { - "name": "violation_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "malformed" - } - } - ] - }, - { - "name": "severity", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "warning", - "1": "final_warning", - "2": "terminating" - } - } - ] - }, - { - "name": "packet_id", - "type": "zigzag32" - }, - { - "name": "reason", - "type": "string" - } - ] - ], - "packet_motion_prediction_hints": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - } - ] - ], - "packet_animate_entity": [ - "container", - [ - { - "name": "animation", - "type": "string" - }, - { - "name": "next_state", - "type": "string" - }, - { - "name": "stop_condition", - "type": "string" - }, - { - "name": "controller", - "type": "string" - }, - { - "name": "blend_out_time", - "type": "lf32" - }, - { - "name": "runtime_entity_ids", - "type": [ - "array", - { - "countType": "varint", - "type": "varint64" - } - ] - } - ] - ], - "packet_camera_shake": [ - "container", - [ - { - "name": "intensity", - "type": "lf32" - }, - { - "name": "duration", - "type": "lf32" - }, - { - "name": "type", - "type": "u8" - } - ] - ], - "packet_player_fog": [ - "container", - [ - { - "name": "stack", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_correct_player_move_prediction": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_item_component": [ - "container", - [ - { - "name": "entries", - "type": "ItemComponentList" - } - ] - ], - "packet_filter_text_packet": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "from_server", - "type": "bool" - } - ] - ], - "string": [ - "pstring", - { - "countType": "varint" - } - ], - "ByteArray": [ - "buffer", - { - "countType": "varint" - } - ], - "SignedByteArray": [ - "buffer", - { - "countType": "zigzag32" - } - ], - "LittleString": [ - "pstring", - { - "countType": "li32" - } - ], - "AdventureFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "world_immutable": 1, - "no_pvp": 2, - "auto_jump": 32, - "allow_flight": 64, - "no_clip": 128, - "world_builder": 256, - "flying": 512, - "muted": 1024 - } - } - ], - "ActionPermissions": [ - "bitflags", - { - "type": "varint", - "flags": { - "build_and_mine": 65537, - "doors_and_switches": 65538, - "open_containers": 65540, - "attack_players": 65544, - "attack_mobs": 65552, - "operator": 65568, - "teleport": 65664 - } - } - ], - "CommandFlags": [ - "bitfield", - [ - { - "name": "unused", - "size": 6, - "signed": false - }, - { - "name": "has_semantic_constraint", - "size": 1, - "signed": false - }, - { - "name": "collapse_enum", - "size": 1, - "signed": false - } - ] - ], - "DeltaMoveFlags": [ - "bitflags", - { - "type": "lu16", - "flags": { - "has_x": 1, - "has_y": 2, - "has_z": 4, - "has_rot_x": 8, - "has_rot_y": 16, - "has_rot_z": 32, - "on_ground": 64, - "teleport": 128, - "force_move": 256 - } - } - ], - "InputFlag": [ - "bitflags", - { - "type": "varint", - "flags": { - "ascend": 1, - "descend": 2, - "north_jump": 4, - "jump_down": 8, - "sprint_down": 16, - "change_height": 32, - "jumping": 64, - "auto_jumping_in_water": 128, - "sneaking": 256, - "sneak_down": 512, - "up": 1024, - "down": 2048, - "left": 4096, - "right": 8192, - "up_left": 16384, - "up_right": 32768, - "want_up": 65536, - "want_down": 131072, - "want_down_slow": 262144, - "want_up_slow": 524288, - "sprinting": 1048576, - "ascend_scaffolding": 2097152, - "descend_scaffolding": 4194304, - "sneak_toggle_down": 8388608, - "persist_sneak": 16777216 - } - } - ], - "ArmorDamageType": [ - "bitflags", - { - "type": "u8", - "flags": { - "head": 1, - "chest": 2, - "legs": 4, - "feet": 8 - } - } - ] - } -} \ No newline at end of file diff --git a/data/1.16.201/steve.json b/data/1.16.201/steve.json deleted file mode 100644 index 8b66dc7..0000000 --- a/data/1.16.201/steve.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "AnimatedImageData": [ - { - "AnimationExpression": 1, - "Frames": 2, - "Image": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEAH/HBAB/xAHAP8cEAH/HBAB/xAHAP8QBwD/CgQA/3NBNP9zQTT/c0E0/3NBNP9zQTT/c0E0/3NBNP9zQTT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwQAf8QBwD/HxME/x8TBP8cEAH/EAcA/xAHAP8QBwD/c0E0/1QyKf9qPDH/VDIp/2o8Mf9qPDH/ckAz/3NBNP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBAB/x8TBP8fEwT/FAoA/xwQAf8QBwD/EAcA/xAHAP9zQTT/VDIp/zgjHv84Ix7/OCMe/zgjHv9UMin/c0E0/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQBwD/HxME/xwQAf8QBwD/HBAB/xwQAf8fEwT/HBAB/3NBNP9UMin/OCMe/zgjHv84Ix7/OCMe/1QyKf9zQTT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwQAf8fEwT/HBAB/xQKAP8UCgD/HxME/x8TBP8cEAH/c0E0/1QyKf84Ix7/OCMe/zgjHv84Ix7/VDIp/3NBNP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBAB/xwQAf8UCgD/FAoA/x8TBP8fEwT/HxME/xwQAf9zQTT/VDIp/zgjHv84Ix7/OCMe/zgjHv9MLSX/c0E0/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEAH/FAoA/x8TBP8cEAH/FAoA/woEAP8fEwT/HBAB/3NBNP9UMin/VDIp/1QyKf9UMin/VDIp/1QyKf9zQTT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwQAf8cEAH/FAoA/xQKAP8UCgD/FAoA/xwQAf8cEAH/c0E0/3NBNP9zQTT/c0E0/3NBNP9zQTT/c0E0/3NBNP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQKAP8UCgD/FAoA/xQKAP8cEAH/KBkK/x8TBP8fEwT/IRQF/xwQAf8fEwT/FAoA/xAHAP8UCgD/HBAB/xwQAf8fEwT/HxME/ygZCv8cEAH/FAoA/xQKAP8ZDgD/GQ4A/xwQAf8cEAH/EAcA/xwQAf8cEAH/EAcA/xAHAP8KBAD/FAoA/xQKAP8UCgD/FAoA/x8TBP8cEAH/HxME/ygZCv8cEAH/HBAB/xwQAf8hFAX/Lh8P/y4fD/8fEwT/HBAB/ygZCv8cEAH/FAoA/x8TBP8UCgD/FAoA/xkOAP8ZDgD/HBAB/xAHAP8fEwT/HxME/xwQAf8QBwD/EAcA/xAHAP8fEwT/CgQA/xQKAP8cEAH/HxME/xwQAf8UCgD/HBAB/xwQAf+wcFf/snti/7WGbf+ye2L/tIJp/61sU/8oGQr/HBAB/xAHAP8UCgD/HBAB/xQKAP8UCgD/EAcA/x8TBP8cEAH/HxME/x8TBP8UCgD/HBAB/xAHAP8QBwD/EAcA/xkOAP8ZDgD/HxME/x8TBP8ZDgD/GQ4A/x8TBP8fEwT/sHBX/7N9ZP+wcFf/snti/61sU/+ye2L/qmZM/6pmTP8fEwT/HxME/xQKAP8UCgD/HxME/x8TBP8UCgD/FAoA/xAHAP8fEwT/HBAB/xAHAP8cEAH/HBAB/x8TBP8cEAH/GQ4A/xkOAP8ZDgD/GQ4A/woEAP+MTTv/q2ZP/yEUBf+zfWT/9/fr/1I9if+wcFf/snti/1I9if/39+v/sHBX/yEUBf+rZk//lVA9/xAHAP8UCgD/FAoA/xQKAP8UCgD/HBAB/x8TBP8cEAH/FAoA/xQKAP8fEwT/HxME/xwQAf8ZDgD/GQ4A/xkOAP8KBAD/HREC/39CNP+MTTv/iUc2/5VTQP+oZk//snti/4JHOP+CRzj/snti/6tmT/96QzX/iUg3/5VQPf96QzX/HREC/xkOAP8UCgD/FAoA/xQKAP8cEAH/HBAB/xQKAP8UCgD/HxME/x8TBP8fEwT/HBAB/yEUBf8ZDgD/IRQF/7N9ZP+rZk//lU07/39CNP+AQzT/i0o5/5VTQP92QjX/dkI1/3ZCNf92QjX/iUg3/3pDNf9zQTT/ekM1/4ZJOf+hV0P/sHBX/xQKAP8UCgD/HxME/xwQAf8UCgD/HxME/xwQAf8UCgD/CgQA/x8TBP8cEAH/f0I0/39CNP+hV0P/f0I0/5VNO/+MTTv/f0I0/4BDNP+AQzT/gEM0/49OPP+PTjz/gUY3/4tKOf+LSjn/dUI1/3NBNP9/QjT/oVdD/6FXQ/+nYEr/oVdD/6dgSv9/QjT/f0I0/3NBNP8UCgD/FAoA/xQKAP8UCgD/c0E0/39CNP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBAB/xwQAf8QBwD/HBAB/xwQAf8QBwD/EAcA/woEAP9zQTT/c0E0/3NBNP9zQTT/c0E0/3NBNP9zQTT/c0E0/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEAH/EAcA/x8TBP8fEwT/HBAB/xAHAP8QBwD/EAcA/3NBNP9UMin/ajwx/1QyKf9qPDH/ajwx/3JAM/9zQTT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwQAf8fEwT/HxME/xQKAP8cEAH/EAcA/xAHAP8QBwD/c0E0/1QyKf84Ix7/OCMe/zgjHv84Ix7/VDIp/3NBNP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAcA/x8TBP8cEAH/EAcA/xwQAf8cEAH/HxME/xwQAf9zQTT/VDIp/zgjHv84Ix7/OCMe/zgjHv9UMin/c0E0/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEAH/HxME/xwQAf8UCgD/FAoA/x8TBP8fEwT/HBAB/3NBNP9UMin/OCMe/zgjHv84Ix7/OCMe/1QyKf9zQTT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwQAf8cEAH/FAoA/xQKAP8fEwT/HxME/x8TBP8cEAH/c0E0/1QyKf84Ix7/OCMe/zgjHv84Ix7/TC0l/3NBNP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBAB/xQKAP8fEwT/HBAB/xQKAP8KBAD/HxME/xwQAf9zQTT/VDIp/1QyKf9UMin/VDIp/1QyKf9UMin/c0E0/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcEAH/HBAB/xQKAP8UCgD/FAoA/xQKAP8cEAH/HBAB/3NBNP9zQTT/c0E0/3NBNP9zQTT/c0E0/3NBNP9zQTT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUCgD/FAoA/xQKAP8UCgD/HBAB/ygZCv8fEwT/HxME/yEUBf8cEAH/HxME/xQKAP8QBwD/FAoA/xwQAf8cEAH/HxME/x8TBP8oGQr/HBAB/xQKAP8UCgD/GQ4A/xkOAP8cEAH/HBAB/xAHAP8cEAH/HBAB/xAHAP8QBwD/CgQA/xQKAP8UCgD/FAoA/xQKAP8fEwT/HBAB/x8TBP8oGQr/HBAB/xwQAf8cEAH/IRQF/y4fD/8uHw//HxME/xwQAf8oGQr/HBAB/xQKAP8fEwT/FAoA/xQKAP8ZDgD/GQ4A/xwQAf8QBwD/HxME/x8TBP8cEAH/EAcA/xAHAP8QBwD/HxME/woEAP8UCgD/HBAB/x8TBP8cEAH/FAoA/xwQAf8cEAH/sHBX/7J7Yv+1hm3/snti/7SCaf+tbFP/KBkK/xwQAf8QBwD/FAoA/xwQAf8UCgD/FAoA/xAHAP8fEwT/HBAB/x8TBP8fEwT/FAoA/xwQAf8QBwD/EAcA/xAHAP8ZDgD/GQ4A/x8TBP8fEwT/GQ4A/xkOAP8fEwT/HxME/7BwV/+zfWT/sHBX/7J7Yv+tbFP/snti/6pmTP+qZkz/HxME/x8TBP8UCgD/FAoA/x8TBP8fEwT/FAoA/xQKAP8QBwD/HxME/xwQAf8QBwD/HBAB/xwQAf8fEwT/HBAB/xkOAP8ZDgD/GQ4A/xkOAP8KBAD/jE07/6tmT/8hFAX/s31k/69sUv+vbFL/sHBX/7J7Yv+vbFL/r2xS/7BwV/8hFAX/q2ZP/5VQPf8QBwD/FAoA/xQKAP8UCgD/FAoA/xwQAf8fEwT/HBAB/xQKAP8UCgD/HxME/x8TBP8cEAH/GQ4A/xkOAP8ZDgD/CgQA/x0RAv9/QjT/jE07/4lHNv+VU0D/qGZP/7J7Yv+CRzj/gkc4/7J7Yv+rZk//ekM1/4lIN/+VUD3/ekM1/x0RAv8ZDgD/FAoA/xQKAP8UCgD/HBAB/xwQAf8UCgD/FAoA/x8TBP8fEwT/HxME/xwQAf8hFAX/GQ4A/yEUBf+zfWT/q2ZP/5VNO/9/QjT/gEM0/4tKOf+VU0D/dkI1/3ZCNf92QjX/dkI1/4lIN/96QzX/c0E0/3pDNf+GSTn/oVdD/7BwV/8UCgD/FAoA/x8TBP8cEAH/FAoA/x8TBP8cEAH/FAoA/woEAP8fEwT/HBAB/39CNP9/QjT/oVdD/39CNP+VTTv/jE07/39CNP+AQzT/gEM0/4BDNP+PTjz/j048/4FGN/+LSjn/i0o5/3VCNf9zQTT/f0I0/6FXQ/+hV0P/p2BK/6FXQ/+nYEr/f0I0/39CNP9zQTT/FAoA/xQKAP8UCgD/FAoA/3NBNP9/QjT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", - "ImageHeight": 64, - "ImageWidth": 32, - "Type": 1 - } - ], - "ArmSize": "wide", - "CapeData": "", - "CapeId": "", - "CapeImageHeight": 0, - "CapeImageWidth": 0, - "CapeOnClassicSkin": false, - "PersonaPieces": [ - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "8f96d1f8-e9bb-40d2-acc8-eb79746c5d7c", - "PieceType": "persona_skeleton", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "1042557f-d1f9-44e3-ba78-f404e8fb7363", - "PieceType": "persona_body", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "f1e4c577-19ba-4d77-9222-47f145857f78", - "PieceType": "persona_skin", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "49f93789-a512-4c47-95cb-0606cdc1c2be", - "PieceType": "persona_bottom", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "68bfe60d-f30a-422f-b32c-72374ebdd057", - "PieceType": "persona_feet", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "b6702f0e-a4b5-497a-8820-6c8e3946bb55", - "PieceType": "persona_top", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "52dd0726-cd68-4d7d-8561-515a4866de39", - "PieceType": "persona_mouth", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "a0f263b3-e093-4c85-aadb-3759417898ff", - "PieceType": "persona_eyes", - "ProductId": "" - }, - { - "IsDefault": true, - "PackId": "2099de18-429a-465a-a49b-fc4710a17bb3", - "PieceId": "2bb1473b-9a5c-4eae-9fd5-82302a6aa3da", - "PieceType": "persona_hair", - "ProductId": "" - } - ], - "PersonaSkin": true, - "PieceTintColors": [ - { - "Colors": [ - "#2f1f0f", - "#0", - "#0", - "#0" - ], - "PieceType": "persona_hair" - }, - { - "Colors": [ - "#523d89", - "#0", - "#0", - "#0" - ], - "PieceType": "persona_eyes" - }, - { - "Colors": [ - "#0", - "#0", - "#774235", - "#0" - ], - "PieceType": "persona_mouth" - } - ], - "PremiumSkin": false, - "SkinAnimationData": "", - "SkinColor": "#b37b62", - "SkinId": "5eb65f73-af11-448e-82aa-1b7b165316ad.persona-3891382d5e3f67c4-0", - "SkinImageHeight": 256, - "SkinImageWidth": 256, - "SkinResourcePatch": "ewogICAiZ2VvbWV0cnkiIDogewogICAgICAiYW5pbWF0ZWRfZmFjZSIgOiAiZ2VvbWV0cnkuYW5pbWF0ZWRfZmFjZV9wZXJzb25hLTM4OTEzODJkNWUzZjY3YzQtMCIsCiAgICAgICJkZWZhdWx0IiA6ICJnZW9tZXRyeS5wZXJzb25hXzM4OTEzODJkNWUzZjY3YzQtMCIKICAgfQp9Cg==" -} \ No newline at end of file diff --git a/data/1.16.201/steveGeometry.json b/data/1.16.201/steveGeometry.json deleted file mode 100644 index fcc59f4..0000000 --- a/data/1.16.201/steveGeometry.json +++ /dev/null @@ -1,5147 +0,0 @@ -{ - "format_version": "1.14.0", - "minecraft:geometry": [ - { - "bones": [ - { - "name": "belt", - "parent": "body", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "locators": { - "armor_offset.default_neck": [ - 0.0, - 24.0, - 0.0 - ] - }, - "name": "body", - "parent": "waist", - "pivot": [ - 0.0, - 24.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -4.0, - 24.0, - -2.0 - ], - [ - 4.0, - 24.0, - -2.0 - ], - [ - 4.0, - 24.0, - 2.0 - ], - [ - -4.0, - 24.0, - 2.0 - ], - [ - -4.0, - 12.0, - 2.0 - ], - [ - 4.0, - 12.0, - 2.0 - ], - [ - 4.0, - 12.0, - -2.0 - ], - [ - -4.0, - 12.0, - -2.0 - ], - [ - -4.0, - 12.0, - 2.0 - ], - [ - -4.0, - 12.0, - -2.0 - ], - [ - -4.0, - 24.0, - -2.0 - ], - [ - -4.0, - 24.0, - 2.0 - ], - [ - 4.0, - 12.0, - -2.0 - ], - [ - 4.0, - 12.0, - 2.0 - ], - [ - 4.0, - 24.0, - 2.0 - ], - [ - 4.0, - 24.0, - -2.0 - ], - [ - -4.0, - 12.0, - -2.0 - ], - [ - 4.0, - 12.0, - -2.0 - ], - [ - 4.0, - 24.0, - -2.0 - ], - [ - -4.0, - 24.0, - -2.0 - ], - [ - 4.0, - 12.0, - 2.0 - ], - [ - -4.0, - 12.0, - 2.0 - ], - [ - -4.0, - 24.0, - 2.0 - ], - [ - 4.0, - 24.0, - 2.0 - ] - ], - "uvs": [ - [ - 0.082031250, - 0.980468750 - ], - [ - 0.113281250, - 0.980468750 - ], - [ - 0.113281250, - 0.996093750 - ], - [ - 0.082031250, - 0.996093750 - ], - [ - 0.144531250, - 0.996093750 - ], - [ - 0.113281250, - 0.996093750 - ], - [ - 0.113281250, - 0.980468750 - ], - [ - 0.144531250, - 0.980468750 - ], - [ - 0.066406250, - 0.933593750 - ], - [ - 0.082031250, - 0.933593750 - ], - [ - 0.082031250, - 0.980468750 - ], - [ - 0.066406250, - 0.980468750 - ], - [ - 0.113281250, - 0.933593750 - ], - [ - 0.128906250, - 0.933593750 - ], - [ - 0.128906250, - 0.980468750 - ], - [ - 0.113281250, - 0.980468750 - ], - [ - 0.082031250, - 0.933593750 - ], - [ - 0.113281250, - 0.933593750 - ], - [ - 0.113281250, - 0.980468750 - ], - [ - 0.082031250, - 0.980468750 - ], - [ - 0.128906250, - 0.933593750 - ], - [ - 0.160156250, - 0.933593750 - ], - [ - 0.160156250, - 0.980468750 - ], - [ - 0.128906250, - 0.980468750 - ] - ] - } - }, - { - "name": "bodyarmor", - "parent": "body", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "name": "head", - "parent": "body", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "name": "helmet", - "parent": "head", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "name": "jacket", - "parent": "body", - "pivot": [ - 0.0, - 24.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -4.250, - 24.250, - -2.250 - ], - [ - 4.250, - 24.250, - -2.250 - ], - [ - 4.250, - 24.250, - 2.250 - ], - [ - -4.250, - 24.250, - 2.250 - ], - [ - -4.250, - 11.750, - 2.250 - ], - [ - 4.250, - 11.750, - 2.250 - ], - [ - 4.250, - 11.750, - -2.250 - ], - [ - -4.250, - 11.750, - -2.250 - ], - [ - -4.250, - 11.750, - 2.250 - ], - [ - -4.250, - 11.750, - -2.250 - ], - [ - -4.250, - 24.250, - -2.250 - ], - [ - -4.250, - 24.250, - 2.250 - ], - [ - 4.250, - 11.750, - -2.250 - ], - [ - 4.250, - 11.750, - 2.250 - ], - [ - 4.250, - 24.250, - 2.250 - ], - [ - 4.250, - 24.250, - -2.250 - ], - [ - -4.250, - 11.750, - -2.250 - ], - [ - 4.250, - 11.750, - -2.250 - ], - [ - 4.250, - 24.250, - -2.250 - ], - [ - -4.250, - 24.250, - -2.250 - ], - [ - 4.250, - 11.750, - 2.250 - ], - [ - -4.250, - 11.750, - 2.250 - ], - [ - -4.250, - 24.250, - 2.250 - ], - [ - 4.250, - 24.250, - 2.250 - ] - ], - "uvs": [ - [ - 0.082031250, - 0.917968750 - ], - [ - 0.113281250, - 0.917968750 - ], - [ - 0.113281250, - 0.933593750 - ], - [ - 0.082031250, - 0.933593750 - ], - [ - 0.144531250, - 0.933593750 - ], - [ - 0.113281250, - 0.933593750 - ], - [ - 0.113281250, - 0.917968750 - ], - [ - 0.144531250, - 0.917968750 - ], - [ - 0.066406250, - 0.871093750 - ], - [ - 0.082031250, - 0.871093750 - ], - [ - 0.082031250, - 0.917968750 - ], - [ - 0.066406250, - 0.917968750 - ], - [ - 0.113281250, - 0.871093750 - ], - [ - 0.128906250, - 0.871093750 - ], - [ - 0.128906250, - 0.917968750 - ], - [ - 0.113281250, - 0.917968750 - ], - [ - 0.082031250, - 0.871093750 - ], - [ - 0.113281250, - 0.871093750 - ], - [ - 0.113281250, - 0.917968750 - ], - [ - 0.082031250, - 0.917968750 - ], - [ - 0.128906250, - 0.871093750 - ], - [ - 0.160156250, - 0.871093750 - ], - [ - 0.160156250, - 0.917968750 - ], - [ - 0.128906250, - 0.917968750 - ] - ] - } - }, - { - "name": "leftarm", - "parent": "body", - "pivot": [ - 5.0, - 22.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - 4.0, - 24.0, - -2.0 - ], - [ - 8.0, - 24.0, - -2.0 - ], - [ - 8.0, - 24.0, - 2.0 - ], - [ - 4.0, - 24.0, - 2.0 - ], - [ - 4.0, - 12.0, - 2.0 - ], - [ - 8.0, - 12.0, - 2.0 - ], - [ - 8.0, - 12.0, - -2.0 - ], - [ - 4.0, - 12.0, - -2.0 - ], - [ - 4.0, - 12.0, - 2.0 - ], - [ - 4.0, - 12.0, - -2.0 - ], - [ - 4.0, - 24.0, - -2.0 - ], - [ - 4.0, - 24.0, - 2.0 - ], - [ - 8.0, - 12.0, - -2.0 - ], - [ - 8.0, - 12.0, - 2.0 - ], - [ - 8.0, - 24.0, - 2.0 - ], - [ - 8.0, - 24.0, - -2.0 - ], - [ - 4.0, - 12.0, - -2.0 - ], - [ - 8.0, - 12.0, - -2.0 - ], - [ - 8.0, - 24.0, - -2.0 - ], - [ - 4.0, - 24.0, - -2.0 - ], - [ - 8.0, - 12.0, - 2.0 - ], - [ - 4.0, - 12.0, - 2.0 - ], - [ - 4.0, - 24.0, - 2.0 - ], - [ - 8.0, - 24.0, - 2.0 - ] - ], - "uvs": [ - [ - 0.175781250, - 0.980468750 - ], - [ - 0.191406250, - 0.980468750 - ], - [ - 0.191406250, - 0.996093750 - ], - [ - 0.175781250, - 0.996093750 - ], - [ - 0.207031250, - 0.996093750 - ], - [ - 0.191406250, - 0.996093750 - ], - [ - 0.191406250, - 0.980468750 - ], - [ - 0.207031250, - 0.980468750 - ], - [ - 0.160156250, - 0.933593750 - ], - [ - 0.175781250, - 0.933593750 - ], - [ - 0.175781250, - 0.980468750 - ], - [ - 0.160156250, - 0.980468750 - ], - [ - 0.191406250, - 0.933593750 - ], - [ - 0.207031250, - 0.933593750 - ], - [ - 0.207031250, - 0.980468750 - ], - [ - 0.191406250, - 0.980468750 - ], - [ - 0.175781250, - 0.933593750 - ], - [ - 0.191406250, - 0.933593750 - ], - [ - 0.191406250, - 0.980468750 - ], - [ - 0.175781250, - 0.980468750 - ], - [ - 0.207031250, - 0.933593750 - ], - [ - 0.222656250, - 0.933593750 - ], - [ - 0.222656250, - 0.980468750 - ], - [ - 0.207031250, - 0.980468750 - ] - ] - } - }, - { - "mirror": true, - "name": "leftarmarmor", - "parent": "leftarm", - "pivot": [ - 5.0, - 22.0, - 0.0 - ] - }, - { - "mirror": true, - "name": "leftboot", - "parent": "leftleg", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "leftitem", - "parent": "leftarm", - "pivot": [ - 6.0, - 15.0, - 0.0 - ] - }, - { - "name": "leftleg", - "parent": "root", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -0.1000000014901161, - 12.0, - -2.0 - ], - [ - 3.900000095367432, - 12.0, - -2.0 - ], - [ - 3.900000095367432, - 12.0, - 2.0 - ], - [ - -0.1000000014901161, - 12.0, - 2.0 - ], - [ - -0.1000000014901161, - 0.0, - 2.0 - ], - [ - 3.900000095367432, - 0.0, - 2.0 - ], - [ - 3.900000095367432, - 0.0, - -2.0 - ], - [ - -0.1000000014901161, - 0.0, - -2.0 - ], - [ - -0.1000000014901161, - 0.0, - 2.0 - ], - [ - -0.1000000014901161, - 0.0, - -2.0 - ], - [ - -0.1000000014901161, - 12.0, - -2.0 - ], - [ - -0.1000000014901161, - 12.0, - 2.0 - ], - [ - 3.900000095367432, - 0.0, - -2.0 - ], - [ - 3.900000095367432, - 0.0, - 2.0 - ], - [ - 3.900000095367432, - 12.0, - 2.0 - ], - [ - 3.900000095367432, - 12.0, - -2.0 - ], - [ - -0.1000000014901161, - 0.0, - -2.0 - ], - [ - 3.900000095367432, - 0.0, - -2.0 - ], - [ - 3.900000095367432, - 12.0, - -2.0 - ], - [ - -0.1000000014901161, - 12.0, - -2.0 - ], - [ - 3.900000095367432, - 0.0, - 2.0 - ], - [ - -0.1000000014901161, - 0.0, - 2.0 - ], - [ - -0.1000000014901161, - 12.0, - 2.0 - ], - [ - 3.900000095367432, - 12.0, - 2.0 - ] - ], - "uvs": [ - [ - 0.144531250, - 0.855468750 - ], - [ - 0.160156250, - 0.855468750 - ], - [ - 0.160156250, - 0.871093750 - ], - [ - 0.144531250, - 0.871093750 - ], - [ - 0.175781250, - 0.871093750 - ], - [ - 0.160156250, - 0.871093750 - ], - [ - 0.160156250, - 0.855468750 - ], - [ - 0.175781250, - 0.855468750 - ], - [ - 0.128906250, - 0.808593750 - ], - [ - 0.144531250, - 0.808593750 - ], - [ - 0.144531250, - 0.855468750 - ], - [ - 0.128906250, - 0.855468750 - ], - [ - 0.160156250, - 0.808593750 - ], - [ - 0.175781250, - 0.808593750 - ], - [ - 0.175781250, - 0.855468750 - ], - [ - 0.160156250, - 0.855468750 - ], - [ - 0.144531250, - 0.808593750 - ], - [ - 0.160156250, - 0.808593750 - ], - [ - 0.160156250, - 0.855468750 - ], - [ - 0.144531250, - 0.855468750 - ], - [ - 0.175781250, - 0.808593750 - ], - [ - 0.191406250, - 0.808593750 - ], - [ - 0.191406250, - 0.855468750 - ], - [ - 0.175781250, - 0.855468750 - ] - ] - } - }, - { - "mirror": true, - "name": "leftlegging", - "parent": "leftleg", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "leftpants", - "parent": "leftleg", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -0.3499999940395355, - 12.250, - -2.250 - ], - [ - 4.150000095367432, - 12.250, - -2.250 - ], - [ - 4.150000095367432, - 12.250, - 2.250 - ], - [ - -0.3499999940395355, - 12.250, - 2.250 - ], - [ - -0.3499999940395355, - -0.250, - 2.250 - ], - [ - 4.150000095367432, - -0.250, - 2.250 - ], - [ - 4.150000095367432, - -0.250, - -2.250 - ], - [ - -0.3499999940395355, - -0.250, - -2.250 - ], - [ - -0.3499999940395355, - -0.250, - 2.250 - ], - [ - -0.3499999940395355, - -0.250, - -2.250 - ], - [ - -0.3499999940395355, - 12.250, - -2.250 - ], - [ - -0.3499999940395355, - 12.250, - 2.250 - ], - [ - 4.150000095367432, - -0.250, - -2.250 - ], - [ - 4.150000095367432, - -0.250, - 2.250 - ], - [ - 4.150000095367432, - 12.250, - 2.250 - ], - [ - 4.150000095367432, - 12.250, - -2.250 - ], - [ - -0.3499999940395355, - -0.250, - -2.250 - ], - [ - 4.150000095367432, - -0.250, - -2.250 - ], - [ - 4.150000095367432, - 12.250, - -2.250 - ], - [ - -0.3499999940395355, - 12.250, - -2.250 - ], - [ - 4.150000095367432, - -0.250, - 2.250 - ], - [ - -0.3499999940395355, - -0.250, - 2.250 - ], - [ - -0.3499999940395355, - 12.250, - 2.250 - ], - [ - 4.150000095367432, - 12.250, - 2.250 - ] - ], - "uvs": [ - [ - 0.207031250, - 0.855468750 - ], - [ - 0.222656250, - 0.855468750 - ], - [ - 0.222656250, - 0.871093750 - ], - [ - 0.207031250, - 0.871093750 - ], - [ - 0.238281250, - 0.871093750 - ], - [ - 0.222656250, - 0.871093750 - ], - [ - 0.222656250, - 0.855468750 - ], - [ - 0.238281250, - 0.855468750 - ], - [ - 0.191406250, - 0.808593750 - ], - [ - 0.207031250, - 0.808593750 - ], - [ - 0.207031250, - 0.855468750 - ], - [ - 0.191406250, - 0.855468750 - ], - [ - 0.222656250, - 0.808593750 - ], - [ - 0.238281250, - 0.808593750 - ], - [ - 0.238281250, - 0.855468750 - ], - [ - 0.222656250, - 0.855468750 - ], - [ - 0.207031250, - 0.808593750 - ], - [ - 0.222656250, - 0.808593750 - ], - [ - 0.222656250, - 0.855468750 - ], - [ - 0.207031250, - 0.855468750 - ], - [ - 0.238281250, - 0.808593750 - ], - [ - 0.253906250, - 0.808593750 - ], - [ - 0.253906250, - 0.855468750 - ], - [ - 0.238281250, - 0.855468750 - ] - ] - } - }, - { - "name": "leftsleeve", - "parent": "leftarm", - "pivot": [ - 5.0, - 22.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - 3.750, - 24.250, - -2.250 - ], - [ - 8.250, - 24.250, - -2.250 - ], - [ - 8.250, - 24.250, - 2.250 - ], - [ - 3.750, - 24.250, - 2.250 - ], - [ - 3.750, - 11.750, - 2.250 - ], - [ - 8.250, - 11.750, - 2.250 - ], - [ - 8.250, - 11.750, - -2.250 - ], - [ - 3.750, - 11.750, - -2.250 - ], - [ - 3.750, - 11.750, - 2.250 - ], - [ - 3.750, - 11.750, - -2.250 - ], - [ - 3.750, - 24.250, - -2.250 - ], - [ - 3.750, - 24.250, - 2.250 - ], - [ - 8.250, - 11.750, - -2.250 - ], - [ - 8.250, - 11.750, - 2.250 - ], - [ - 8.250, - 24.250, - 2.250 - ], - [ - 8.250, - 24.250, - -2.250 - ], - [ - 3.750, - 11.750, - -2.250 - ], - [ - 8.250, - 11.750, - -2.250 - ], - [ - 8.250, - 24.250, - -2.250 - ], - [ - 3.750, - 24.250, - -2.250 - ], - [ - 8.250, - 11.750, - 2.250 - ], - [ - 3.750, - 11.750, - 2.250 - ], - [ - 3.750, - 24.250, - 2.250 - ], - [ - 8.250, - 24.250, - 2.250 - ] - ], - "uvs": [ - [ - 0.175781250, - 0.917968750 - ], - [ - 0.191406250, - 0.917968750 - ], - [ - 0.191406250, - 0.933593750 - ], - [ - 0.175781250, - 0.933593750 - ], - [ - 0.207031250, - 0.933593750 - ], - [ - 0.191406250, - 0.933593750 - ], - [ - 0.191406250, - 0.917968750 - ], - [ - 0.207031250, - 0.917968750 - ], - [ - 0.160156250, - 0.871093750 - ], - [ - 0.175781250, - 0.871093750 - ], - [ - 0.175781250, - 0.917968750 - ], - [ - 0.160156250, - 0.917968750 - ], - [ - 0.191406250, - 0.871093750 - ], - [ - 0.207031250, - 0.871093750 - ], - [ - 0.207031250, - 0.917968750 - ], - [ - 0.191406250, - 0.917968750 - ], - [ - 0.175781250, - 0.871093750 - ], - [ - 0.191406250, - 0.871093750 - ], - [ - 0.191406250, - 0.917968750 - ], - [ - 0.175781250, - 0.917968750 - ], - [ - 0.207031250, - 0.871093750 - ], - [ - 0.222656250, - 0.871093750 - ], - [ - 0.222656250, - 0.917968750 - ], - [ - 0.207031250, - 0.917968750 - ] - ] - } - }, - { - "mirror": true, - "name": "leftsock", - "parent": "leftleg", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "rightarm", - "parent": "body", - "pivot": [ - -5.0, - 22.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -8.0, - 24.0, - -2.0 - ], - [ - -4.0, - 24.0, - -2.0 - ], - [ - -4.0, - 24.0, - 2.0 - ], - [ - -8.0, - 24.0, - 2.0 - ], - [ - -8.0, - 12.0, - 2.0 - ], - [ - -4.0, - 12.0, - 2.0 - ], - [ - -4.0, - 12.0, - -2.0 - ], - [ - -8.0, - 12.0, - -2.0 - ], - [ - -8.0, - 12.0, - 2.0 - ], - [ - -8.0, - 12.0, - -2.0 - ], - [ - -8.0, - 24.0, - -2.0 - ], - [ - -8.0, - 24.0, - 2.0 - ], - [ - -4.0, - 12.0, - -2.0 - ], - [ - -4.0, - 12.0, - 2.0 - ], - [ - -4.0, - 24.0, - 2.0 - ], - [ - -4.0, - 24.0, - -2.0 - ], - [ - -8.0, - 12.0, - -2.0 - ], - [ - -4.0, - 12.0, - -2.0 - ], - [ - -4.0, - 24.0, - -2.0 - ], - [ - -8.0, - 24.0, - -2.0 - ], - [ - -4.0, - 12.0, - 2.0 - ], - [ - -8.0, - 12.0, - 2.0 - ], - [ - -8.0, - 24.0, - 2.0 - ], - [ - -4.0, - 24.0, - 2.0 - ] - ], - "uvs": [ - [ - 0.019531250, - 0.980468750 - ], - [ - 0.035156250, - 0.980468750 - ], - [ - 0.035156250, - 0.996093750 - ], - [ - 0.019531250, - 0.996093750 - ], - [ - 0.050781250, - 0.996093750 - ], - [ - 0.035156250, - 0.996093750 - ], - [ - 0.035156250, - 0.980468750 - ], - [ - 0.050781250, - 0.980468750 - ], - [ - 0.003906250, - 0.933593750 - ], - [ - 0.019531250, - 0.933593750 - ], - [ - 0.019531250, - 0.980468750 - ], - [ - 0.003906250, - 0.980468750 - ], - [ - 0.035156250, - 0.933593750 - ], - [ - 0.050781250, - 0.933593750 - ], - [ - 0.050781250, - 0.980468750 - ], - [ - 0.035156250, - 0.980468750 - ], - [ - 0.019531250, - 0.933593750 - ], - [ - 0.035156250, - 0.933593750 - ], - [ - 0.035156250, - 0.980468750 - ], - [ - 0.019531250, - 0.980468750 - ], - [ - 0.050781250, - 0.933593750 - ], - [ - 0.066406250, - 0.933593750 - ], - [ - 0.066406250, - 0.980468750 - ], - [ - 0.050781250, - 0.980468750 - ] - ] - } - }, - { - "name": "rightarmarmor", - "parent": "rightarm", - "pivot": [ - -5.0, - 22.0, - 0.0 - ] - }, - { - "name": "rightboot", - "parent": "rightleg", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "locators": { - "lead_hold": [ - -6.0, - 15.0, - 0.0 - ] - }, - "name": "rightitem", - "parent": "rightarm", - "pivot": [ - -6.0, - 15.0, - 0.0 - ] - }, - { - "name": "rightleg", - "parent": "root", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -3.900000095367432, - 12.0, - -2.0 - ], - [ - 0.09999989718198776, - 12.0, - -2.0 - ], - [ - 0.09999989718198776, - 12.0, - 2.0 - ], - [ - -3.900000095367432, - 12.0, - 2.0 - ], - [ - -3.900000095367432, - 0.0, - 2.0 - ], - [ - 0.09999989718198776, - 0.0, - 2.0 - ], - [ - 0.09999989718198776, - 0.0, - -2.0 - ], - [ - -3.900000095367432, - 0.0, - -2.0 - ], - [ - -3.900000095367432, - 0.0, - 2.0 - ], - [ - -3.900000095367432, - 0.0, - -2.0 - ], - [ - -3.900000095367432, - 12.0, - -2.0 - ], - [ - -3.900000095367432, - 12.0, - 2.0 - ], - [ - 0.09999989718198776, - 0.0, - -2.0 - ], - [ - 0.09999989718198776, - 0.0, - 2.0 - ], - [ - 0.09999989718198776, - 12.0, - 2.0 - ], - [ - 0.09999989718198776, - 12.0, - -2.0 - ], - [ - -3.900000095367432, - 0.0, - -2.0 - ], - [ - 0.09999989718198776, - 0.0, - -2.0 - ], - [ - 0.09999989718198776, - 12.0, - -2.0 - ], - [ - -3.900000095367432, - 12.0, - -2.0 - ], - [ - 0.09999989718198776, - 0.0, - 2.0 - ], - [ - -3.900000095367432, - 0.0, - 2.0 - ], - [ - -3.900000095367432, - 12.0, - 2.0 - ], - [ - 0.09999989718198776, - 12.0, - 2.0 - ] - ], - "uvs": [ - [ - 0.082031250, - 0.855468750 - ], - [ - 0.097656250, - 0.855468750 - ], - [ - 0.097656250, - 0.871093750 - ], - [ - 0.082031250, - 0.871093750 - ], - [ - 0.113281250, - 0.871093750 - ], - [ - 0.097656250, - 0.871093750 - ], - [ - 0.097656250, - 0.855468750 - ], - [ - 0.113281250, - 0.855468750 - ], - [ - 0.066406250, - 0.808593750 - ], - [ - 0.082031250, - 0.808593750 - ], - [ - 0.082031250, - 0.855468750 - ], - [ - 0.066406250, - 0.855468750 - ], - [ - 0.097656250, - 0.808593750 - ], - [ - 0.113281250, - 0.808593750 - ], - [ - 0.113281250, - 0.855468750 - ], - [ - 0.097656250, - 0.855468750 - ], - [ - 0.082031250, - 0.808593750 - ], - [ - 0.097656250, - 0.808593750 - ], - [ - 0.097656250, - 0.855468750 - ], - [ - 0.082031250, - 0.855468750 - ], - [ - 0.113281250, - 0.808593750 - ], - [ - 0.128906250, - 0.808593750 - ], - [ - 0.128906250, - 0.855468750 - ], - [ - 0.113281250, - 0.855468750 - ] - ] - } - }, - { - "name": "rightlegging", - "parent": "rightleg", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "rightpants", - "parent": "rightleg", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -4.150000095367432, - 12.250, - -2.250 - ], - [ - 0.3499999046325684, - 12.250, - -2.250 - ], - [ - 0.3499999046325684, - 12.250, - 2.250 - ], - [ - -4.150000095367432, - 12.250, - 2.250 - ], - [ - -4.150000095367432, - -0.250, - 2.250 - ], - [ - 0.3499999046325684, - -0.250, - 2.250 - ], - [ - 0.3499999046325684, - -0.250, - -2.250 - ], - [ - -4.150000095367432, - -0.250, - -2.250 - ], - [ - -4.150000095367432, - -0.250, - 2.250 - ], - [ - -4.150000095367432, - -0.250, - -2.250 - ], - [ - -4.150000095367432, - 12.250, - -2.250 - ], - [ - -4.150000095367432, - 12.250, - 2.250 - ], - [ - 0.3499999046325684, - -0.250, - -2.250 - ], - [ - 0.3499999046325684, - -0.250, - 2.250 - ], - [ - 0.3499999046325684, - 12.250, - 2.250 - ], - [ - 0.3499999046325684, - 12.250, - -2.250 - ], - [ - -4.150000095367432, - -0.250, - -2.250 - ], - [ - 0.3499999046325684, - -0.250, - -2.250 - ], - [ - 0.3499999046325684, - 12.250, - -2.250 - ], - [ - -4.150000095367432, - 12.250, - -2.250 - ], - [ - 0.3499999046325684, - -0.250, - 2.250 - ], - [ - -4.150000095367432, - -0.250, - 2.250 - ], - [ - -4.150000095367432, - 12.250, - 2.250 - ], - [ - 0.3499999046325684, - 12.250, - 2.250 - ] - ], - "uvs": [ - [ - 0.019531250, - 0.855468750 - ], - [ - 0.035156250, - 0.855468750 - ], - [ - 0.035156250, - 0.871093750 - ], - [ - 0.019531250, - 0.871093750 - ], - [ - 0.050781250, - 0.871093750 - ], - [ - 0.035156250, - 0.871093750 - ], - [ - 0.035156250, - 0.855468750 - ], - [ - 0.050781250, - 0.855468750 - ], - [ - 0.003906250, - 0.808593750 - ], - [ - 0.019531250, - 0.808593750 - ], - [ - 0.019531250, - 0.855468750 - ], - [ - 0.003906250, - 0.855468750 - ], - [ - 0.035156250, - 0.808593750 - ], - [ - 0.050781250, - 0.808593750 - ], - [ - 0.050781250, - 0.855468750 - ], - [ - 0.035156250, - 0.855468750 - ], - [ - 0.019531250, - 0.808593750 - ], - [ - 0.035156250, - 0.808593750 - ], - [ - 0.035156250, - 0.855468750 - ], - [ - 0.019531250, - 0.855468750 - ], - [ - 0.050781250, - 0.808593750 - ], - [ - 0.066406250, - 0.808593750 - ], - [ - 0.066406250, - 0.855468750 - ], - [ - 0.050781250, - 0.855468750 - ] - ] - } - }, - { - "name": "rightsleeve", - "parent": "rightarm", - "pivot": [ - -5.0, - 22.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -8.250, - 24.250, - -2.250 - ], - [ - -3.750, - 24.250, - -2.250 - ], - [ - -3.750, - 24.250, - 2.250 - ], - [ - -8.250, - 24.250, - 2.250 - ], - [ - -8.250, - 11.750, - 2.250 - ], - [ - -3.750, - 11.750, - 2.250 - ], - [ - -3.750, - 11.750, - -2.250 - ], - [ - -8.250, - 11.750, - -2.250 - ], - [ - -8.250, - 11.750, - 2.250 - ], - [ - -8.250, - 11.750, - -2.250 - ], - [ - -8.250, - 24.250, - -2.250 - ], - [ - -8.250, - 24.250, - 2.250 - ], - [ - -3.750, - 11.750, - -2.250 - ], - [ - -3.750, - 11.750, - 2.250 - ], - [ - -3.750, - 24.250, - 2.250 - ], - [ - -3.750, - 24.250, - -2.250 - ], - [ - -8.250, - 11.750, - -2.250 - ], - [ - -3.750, - 11.750, - -2.250 - ], - [ - -3.750, - 24.250, - -2.250 - ], - [ - -8.250, - 24.250, - -2.250 - ], - [ - -3.750, - 11.750, - 2.250 - ], - [ - -8.250, - 11.750, - 2.250 - ], - [ - -8.250, - 24.250, - 2.250 - ], - [ - -3.750, - 24.250, - 2.250 - ] - ], - "uvs": [ - [ - 0.019531250, - 0.917968750 - ], - [ - 0.035156250, - 0.917968750 - ], - [ - 0.035156250, - 0.933593750 - ], - [ - 0.019531250, - 0.933593750 - ], - [ - 0.050781250, - 0.933593750 - ], - [ - 0.035156250, - 0.933593750 - ], - [ - 0.035156250, - 0.917968750 - ], - [ - 0.050781250, - 0.917968750 - ], - [ - 0.003906250, - 0.871093750 - ], - [ - 0.019531250, - 0.871093750 - ], - [ - 0.019531250, - 0.917968750 - ], - [ - 0.003906250, - 0.917968750 - ], - [ - 0.035156250, - 0.871093750 - ], - [ - 0.050781250, - 0.871093750 - ], - [ - 0.050781250, - 0.917968750 - ], - [ - 0.035156250, - 0.917968750 - ], - [ - 0.019531250, - 0.871093750 - ], - [ - 0.035156250, - 0.871093750 - ], - [ - 0.035156250, - 0.917968750 - ], - [ - 0.019531250, - 0.917968750 - ], - [ - 0.050781250, - 0.871093750 - ], - [ - 0.066406250, - 0.871093750 - ], - [ - 0.066406250, - 0.917968750 - ], - [ - 0.050781250, - 0.917968750 - ] - ] - } - }, - { - "name": "rightsock", - "parent": "rightleg", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "root" - }, - { - "name": "waist", - "parent": "root", - "pivot": [ - 0.0, - 12.0, - 0.0 - ] - } - ], - "description": { - "identifier": "geometry.persona_3891382d5e3f67c4-0", - "texture_height": 256.0, - "texture_width": 256.0 - } - }, - { - "bones": [ - { - "name": "belt", - "parent": "body", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "locators": { - "armor_offset.default_neck": [ - 0.0, - 24.0, - 0.0 - ] - }, - "name": "body", - "parent": "waist", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "name": "bodyarmor", - "parent": "body", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "name": "hat", - "parent": "head", - "pivot": [ - 0.0, - 24.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -4.50, - 32.50, - -4.50 - ], - [ - 4.50, - 32.50, - -4.50 - ], - [ - 4.50, - 32.50, - 4.50 - ], - [ - -4.50, - 32.50, - 4.50 - ], - [ - -4.50, - 23.50, - 4.50 - ], - [ - 4.50, - 23.50, - 4.50 - ], - [ - 4.50, - 23.50, - -4.50 - ], - [ - -4.50, - 23.50, - -4.50 - ], - [ - -4.50, - 23.50, - 4.50 - ], - [ - -4.50, - 23.50, - -4.50 - ], - [ - -4.50, - 32.50, - -4.50 - ], - [ - -4.50, - 32.50, - 4.50 - ], - [ - 4.50, - 23.50, - -4.50 - ], - [ - 4.50, - 23.50, - 4.50 - ], - [ - 4.50, - 32.50, - 4.50 - ], - [ - 4.50, - 32.50, - -4.50 - ], - [ - -4.50, - 23.50, - -4.50 - ], - [ - 4.50, - 23.50, - -4.50 - ], - [ - 4.50, - 32.50, - -4.50 - ], - [ - -4.50, - 32.50, - -4.50 - ], - [ - 4.50, - 23.50, - 4.50 - ], - [ - -4.50, - 23.50, - 4.50 - ], - [ - -4.50, - 32.50, - 4.50 - ], - [ - 4.50, - 32.50, - 4.50 - ] - ], - "uvs": [ - [ - 0.250, - 0.6250 - ], - [ - 0.50, - 0.6250 - ], - [ - 0.50, - 0.750 - ], - [ - 0.250, - 0.750 - ], - [ - 0.750, - 0.750 - ], - [ - 0.50, - 0.750 - ], - [ - 0.50, - 0.6250 - ], - [ - 0.750, - 0.6250 - ], - [ - 0.0, - 0.50 - ], - [ - 0.250, - 0.50 - ], - [ - 0.250, - 0.6250 - ], - [ - 0.0, - 0.6250 - ], - [ - 0.50, - 0.50 - ], - [ - 0.750, - 0.50 - ], - [ - 0.750, - 0.6250 - ], - [ - 0.50, - 0.6250 - ], - [ - 0.250, - 0.50 - ], - [ - 0.50, - 0.50 - ], - [ - 0.50, - 0.6250 - ], - [ - 0.250, - 0.6250 - ], - [ - 0.750, - 0.50 - ], - [ - 1.0, - 0.50 - ], - [ - 1.0, - 0.6250 - ], - [ - 0.750, - 0.6250 - ] - ] - } - }, - { - "name": "head", - "parent": "body", - "pivot": [ - 0.0, - 24.0, - 0.0 - ], - "poly_mesh": { - "normalized_uvs": true, - "normals": [ - [ - 0.0, - 1.0, - 0.0 - ], - [ - 0.0, - -1.0, - 0.0 - ], - [ - -1.0, - 0.0, - 0.0 - ], - [ - 1.0, - 0.0, - 0.0 - ], - [ - 0.0, - 0.0, - -1.0 - ], - [ - 0.0, - 0.0, - 1.0 - ] - ], - "polys": [ - [ - [ - 0, - 0, - 0 - ], - [ - 1, - 0, - 1 - ], - [ - 2, - 0, - 2 - ], - [ - 3, - 0, - 3 - ] - ], - [ - [ - 4, - 1, - 4 - ], - [ - 5, - 1, - 5 - ], - [ - 6, - 1, - 6 - ], - [ - 7, - 1, - 7 - ] - ], - [ - [ - 8, - 2, - 8 - ], - [ - 9, - 2, - 9 - ], - [ - 10, - 2, - 10 - ], - [ - 11, - 2, - 11 - ] - ], - [ - [ - 12, - 3, - 12 - ], - [ - 13, - 3, - 13 - ], - [ - 14, - 3, - 14 - ], - [ - 15, - 3, - 15 - ] - ], - [ - [ - 16, - 4, - 16 - ], - [ - 17, - 4, - 17 - ], - [ - 18, - 4, - 18 - ], - [ - 19, - 4, - 19 - ] - ], - [ - [ - 20, - 5, - 20 - ], - [ - 21, - 5, - 21 - ], - [ - 22, - 5, - 22 - ], - [ - 23, - 5, - 23 - ] - ] - ], - "positions": [ - [ - -4.0, - 32.0, - -4.0 - ], - [ - 4.0, - 32.0, - -4.0 - ], - [ - 4.0, - 32.0, - 4.0 - ], - [ - -4.0, - 32.0, - 4.0 - ], - [ - -4.0, - 24.0, - 4.0 - ], - [ - 4.0, - 24.0, - 4.0 - ], - [ - 4.0, - 24.0, - -4.0 - ], - [ - -4.0, - 24.0, - -4.0 - ], - [ - -4.0, - 24.0, - 4.0 - ], - [ - -4.0, - 24.0, - -4.0 - ], - [ - -4.0, - 32.0, - -4.0 - ], - [ - -4.0, - 32.0, - 4.0 - ], - [ - 4.0, - 24.0, - -4.0 - ], - [ - 4.0, - 24.0, - 4.0 - ], - [ - 4.0, - 32.0, - 4.0 - ], - [ - 4.0, - 32.0, - -4.0 - ], - [ - -4.0, - 24.0, - -4.0 - ], - [ - 4.0, - 24.0, - -4.0 - ], - [ - 4.0, - 32.0, - -4.0 - ], - [ - -4.0, - 32.0, - -4.0 - ], - [ - 4.0, - 24.0, - 4.0 - ], - [ - -4.0, - 24.0, - 4.0 - ], - [ - -4.0, - 32.0, - 4.0 - ], - [ - 4.0, - 32.0, - 4.0 - ] - ], - "uvs": [ - [ - 0.250, - 0.8750 - ], - [ - 0.50, - 0.8750 - ], - [ - 0.50, - 1.0 - ], - [ - 0.250, - 1.0 - ], - [ - 0.750, - 1.0 - ], - [ - 0.50, - 1.0 - ], - [ - 0.50, - 0.8750 - ], - [ - 0.750, - 0.8750 - ], - [ - 0.0, - 0.750 - ], - [ - 0.250, - 0.750 - ], - [ - 0.250, - 0.8750 - ], - [ - 0.0, - 0.8750 - ], - [ - 0.50, - 0.750 - ], - [ - 0.750, - 0.750 - ], - [ - 0.750, - 0.8750 - ], - [ - 0.50, - 0.8750 - ], - [ - 0.250, - 0.750 - ], - [ - 0.50, - 0.750 - ], - [ - 0.50, - 0.8750 - ], - [ - 0.250, - 0.8750 - ], - [ - 0.750, - 0.750 - ], - [ - 1.0, - 0.750 - ], - [ - 1.0, - 0.8750 - ], - [ - 0.750, - 0.8750 - ] - ] - } - }, - { - "name": "helmet", - "parent": "head", - "pivot": [ - 0.0, - 24.0, - 0.0 - ] - }, - { - "name": "leftarm", - "parent": "body", - "pivot": [ - 5.0, - 22.0, - 0.0 - ] - }, - { - "mirror": true, - "name": "leftarmarmor", - "parent": "leftarm", - "pivot": [ - 5.0, - 22.0, - 0.0 - ] - }, - { - "mirror": true, - "name": "leftboot", - "parent": "leftleg", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "leftitem", - "parent": "leftarm", - "pivot": [ - 6.0, - 15.0, - 0.0 - ] - }, - { - "name": "leftleg", - "parent": "root", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "mirror": true, - "name": "leftlegging", - "parent": "leftleg", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "mirror": true, - "name": "leftsock", - "parent": "leftleg", - "pivot": [ - 1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "rightarm", - "parent": "body", - "pivot": [ - -5.0, - 22.0, - 0.0 - ] - }, - { - "name": "rightarmarmor", - "parent": "rightarm", - "pivot": [ - -5.0, - 22.0, - 0.0 - ] - }, - { - "name": "rightboot", - "parent": "rightleg", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "locators": { - "lead_hold": [ - -6.0, - 15.0, - 0.0 - ] - }, - "name": "rightitem", - "parent": "rightarm", - "pivot": [ - -6.0, - 15.0, - 0.0 - ] - }, - { - "name": "rightleg", - "parent": "root", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "rightlegging", - "parent": "rightleg", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "rightsock", - "parent": "rightleg", - "pivot": [ - -1.899999976158142, - 12.0, - 0.0 - ] - }, - { - "name": "root" - }, - { - "name": "waist", - "parent": "root", - "pivot": [ - 0.0, - 12.0, - 0.0 - ] - } - ], - "description": { - "identifier": "geometry.animated_face_persona-3891382d5e3f67c4-0", - "texture_height": 64.0, - "texture_width": 32.0 - } - } - ] -} \ No newline at end of file diff --git a/data/1.16.201/steveSkin.bin b/data/1.16.201/steveSkin.bin deleted file mode 100644 index e2c09e28abf1ed6379af552eb7d3b534af73363e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262144 zcmeI5v5q6f7KZ0p2(APfB4P+_@BY2I_W%C-@#e=*|FgF} z5s$mN*u?Z*+j)QfdGm1UdOX|Vt0upiTh=@bxNuLizI-ms*XiaZV11wFFQ3zV^xifB z?)^J^&iyU-3 zmU-&hnLmDF&>v&)Ge_*yuXca;#^(}@rZP5u9s;TDw!W)&qO()}j758~8B2U(qm?`l zpx1VMVi@0N`_`{>C1xnUsbo*h-KUQ^Gr*Pr(NqG z{nx%@<8w}ATr^eNQ}dhp&Q4wb*nZ*5USV`>JmW6SC+qsPN&-BeWAn4Lzkm4l(Um^@ zv8{ir{nRX1>XcedZPBKmaoCJ$YnqtOSJyr(zlrZ`UBBIb{rLvt=H!zcl2grrys*_r zdmpptUa{xL&rt6GB`)PAVpn1-M*rI=OU|n*gpFQBm zPJL^b7Y@ve9bBKiJ~N+l^UFS_GBW-)38Z#w{idCIKwGiY6*|Drm`C@2^dC*5>z$7G z_jvRli~bwU*E585$&+=l^pod7eiPps)^F#}I=Sd)9R1j9^I_dSKFJY(wG$B;exn4U zovNRYICit7%?W{ij{W z_q552JZjx05Awp++|r)<&a~^-`I8IlVyl0<{;B=uoa6auA|LYXdXYFnOY;%4Ru6) zVdKXa`^kqtZ9e+o`@Q|*#h;t@`t0Lh-v2zH(?iA+ldl*OE;>Wgp_UB#Bfn4>x<6Ok{>A#N8S-|VGFK|94->Hm@zfA(vY_;en zHW#}8^~)Dq9klgb^`CaDeO_<%-PLX^+Hc1*h8Xlue#wQr$O9j?=6{LWW?ndCPS%d4 zA6tFNrSi$X>)vQ@_l>r%d_E@M+pJ!*mca89K>yf!zNC%rZ}ogs|Ic4Tt{?#kNI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}ocL0y zz*PNCjh}Dlt}FowOx5qy_{F{h`Ha7J@3x=WSO2E^V7?_TpEX46V4MRaFav?9`kfj- z!!r)N6zNc7*?QTi`&>VM|< z(B%&ZpvzPG&6rbud>Pm3yTv@n8>i?v8je=;8ejbzi1F3_j6>s`8~CeF{m)SOE*Sz<+i4H! zKi{+0Yij&r--W92s#Wge$8_Arab~pVMx9grFSZQsJu&plJv{nH-)YCsm{@$+>Px#X zK65iaaoEN3ZFS6Z{Lp>;+_=SpFtK|k5Y1K%58eO!{Ae5f*D-bOKL1kL^7n$U`8zxO zZ7}+<_+sh9^7n@Nd^K*V9L(#!2}F}sqgA_U)8n7rj=k;=`ix_H2m1jbpy} zYTT{!GXEPV!0)Ma77fP^?yAJyyZ+HD8phI({^^g6{_#ii_|*SkWjWxQ1h|iPdQOdU z1`MWv{>MHy3{E`nfatSc=r~$N!@qv{Vmk(XqkrNuE`9jv$I>4=?`~av^#ss=XGiJ3 z#BpXk>A7L`zy%_q7BhFdG4W1|6H9_tk%==I7gtsXqF~#?7`-7nXno4hXb5=HH^C zb+pZxKK*k>;7dGxeQ^f~*dYN4%toMUHEr}C+v-1k_|Z1;^vBXie9i`9XWOU?OF#k# z1gch}*LojEzgT>+#9`5Yd>PLbe~mjxzzzvWU^W8i7mHS-XEc0D|BPw%&wT2Cwzt-W zB``<;{i0X&-`>YF4vn{GLws!<^R;n<2{}Ll61WoMm{nH;C{o~J^_|*T^ z-bxpez-R*KAB&EoWi;&Xw~WSWfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drdo|iy=AFq5S zPkxp+>T@}EpZ}A%_S(*y-~Tyv4ehSUujZEZhQjqrKmsQSp#7aaNB_}e-?i62zZ=}z zoC`x=O@8Ws2$+5ej37|&ubtLL>uVQt75#U)jy|78pm3-JR!5-fziXeP|Mt0`*Zceb z1)u-b|LQ8#4PS~tpAMt{d=^hEpXE`<@i{-(>U;HS^YGhm+c^IJ9{)dRJ6GR)>C0MN z%**RKf7*;E$JS3gb}Xx`%l8;vd-VCz#d6-Y_BqbK(dYA69*)0X0%(Wt!_gPoicKH> zSagN0{z{mE zoBW5qn*7xN5HS5m38da~QHQO5qO()}=#1Fd8lTwcGtUF)wH=?Bs@1mLw|<=~8O|^UTi~kT$Wg=)d+I8=rF` zn9$&->3}(F6|I{q?T*s!JtMic`7G0A^^5V)E`msm0{=U1_Z}Q~ zJHDy;_3ha{33LR|6xxn$^;5^-M}x8Z`b?eXqRwNvS7FoF)^i=7dgt{{7k%s39OFm- zY1iDIqW>Dp`BCR+=g*w+Gv<+=a~3rDALzQC7u^5*Vs^~fKY6k)mVWX)$j?fbz!3t} z7PS+Lw%Yol&ZsZ!Cm;T_`RIf1H`p&;{JCkb&p!U;-}_wZywiWi6O*y=Z^v-&>&E4E zd^NXLpUI*6(*K@L{4-|gJ!OB`#BgOU=8er5eAt8MnLM{} z<-FtBhi9Ai`G>JbEP0U!`(u6b!qSf&+P{7YteF71LTBg(iyxbQG#I?V{&=nd&SLld-Z2b6Q>+?^ZYwEKL z?d@|7+V1qfr0;)*_~@6wJrh9x*sATc(fz%C|8vjpt$UMz1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-I3)1u ztA952dinC@re22;k9%rt+BG)q$D@5E0SPRLz*PNCjb9QAbCJN>2u#)Q)cCo1PtAX7 z{M`F@{dE(VTEA1{=cYe3|EckF@89*;MS#!!<1_vE%o}X|e4MoTT+iySW9Y|LU)uD? zZa-INVYsL2cWV5?aG1`W6No0OMyo#4#y5064Eb57oquU~r|NfV{L*-s&wUd>m#6g0 z84%m*xBAZU&rLTu*F6mF@7|w(=6*k1|GEU8QvYN0F{Gc?f8E_4uJ)Au=WIN6K0d|I zI!oLCArX7lM4)Or?Y2ItTk1dezj{rLpPO~NzoGs2`C)U6-zopx`*;0y6F|SzXzCk% zr`_rUAC`E=^~Gmy<|ht2H~qf+tH#;avHYjT&%J-wUpIlazH9AQ{WIUCf0>`T({AUV zd;hM#ZUX%Oe00#(C;g0j^XAQ_Ui33=Z2a8x$s2nt|L5}0y?@tVHv#mEt=dkTe(a_F zbJJ&EL;7aivHhPLKllD!f87MAYwWT5elGvq^w}47ZTp{_zw0lAK>o(Oa@-zd!EJn741=Uo|G}jE_IDt*^#C?{22g zp8TWb&W_T5iBtd6-v(#65`k#-_3M8xbevj_W~(n_s*Z_?%{Y9V8~Cd)W0v-n{OXmx z=VBk##~x#Af7{U1Sl*L;8ukHMM3M0qdErF`lw9$WT ztN--jN87~HA4?zc(LJ$C1KH+U_d)*bl|5uX^bud<=p%l~`(N7oVLsO-P-`{ynp&k^ zsb4Iy&SbSJC-fE-jhB)Snuf|<>cf+f( zH}YNE{)Y)U;+_fg)jxVg6IlAuKmD=M4gSoD?-upXKG*}6{(IX0J=eB-8zzAMvFJE8 zPTl|d<%{jJKwJOBWL$js>BrI^JDkyVN01|SZTr72ZC6_w0qP#Rw)$t^*tP9{Y4vD6 z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv zAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnw zfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz z0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8< z2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|Drd zBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J- zkbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(T zKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU z0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb z1SB8<2}nQ!5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ! z5|DrdBp?9^NI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^ zNI(J-kbndvAOQ(TKmrnwfCMBU0SQPz0uqpb1SB8<2}nQ!5|DrdBp?9^NI(J-kbndv TAOQ(TKmrnwfCMCPIRgI&V?knt diff --git a/data/1.16.210/protocol.json b/data/1.16.210/protocol.json deleted file mode 100644 index 96a88ca..0000000 --- a/data/1.16.210/protocol.json +++ /dev/null @@ -1,7798 +0,0 @@ -{ - "types": { - "varint32": "varint", - "varint64": "native", - "zigzag32": "native", - "zigzag64": "native", - "uuid": "native", - "byterot": "native", - "bitflags": "native", - "restBuffer": "native", - "encapsulated": "native", - "nbt": "native", - "lnbt": "native", - "nbtLoop": "native", - "enum_size_based_on_values_len": "native", - "MapInfo": "native", - "BehaviourPackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - } - ] - ] - } - ], - "TexturePackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "rtx_enabled", - "type": "bool" - } - ] - ] - } - ], - "ResourcePackIdVersions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "ResourcePackIds": [ - "array", - { - "countType": "li16", - "type": "string" - } - ], - "Experiment": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "enabled", - "type": "bool" - } - ] - ], - "Experiments": [ - "array", - { - "countType": "li32", - "type": "Experiment" - } - ], - "GameMode": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "survival", - "1": "creative", - "2": "adventure", - "3": "survival_spectator", - "4": "creative_spectator", - "5": "fallback" - } - } - ], - "GameRule": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "bool", - "2": "int", - "3": "float" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "bool": "bool", - "int": "zigzag32", - "float": "lf32" - }, - "default": "void" - } - ] - } - ] - ], - "GameRules": [ - "array", - { - "countType": "varint", - "type": "GameRule" - } - ], - "Blob": [ - "container", - [ - { - "name": "hash", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "BlockPalette": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "state", - "type": "nbt" - } - ] - ] - } - ], - "Itemstates": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "runtime_id", - "type": "li16" - }, - { - "name": "component_based", - "type": "bool" - } - ] - ] - } - ], - "Item": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "auxiliary_value", - "type": "zigzag32" - }, - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "zigzag32", - "type": "string" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "zigzag32", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "355": [ - "container", - [ - { - "name": "blocking_tick", - "type": "zigzag64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "vec3i": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "vec3u": [ - "container", - [ - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - } - ] - ], - "vec3f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vec2f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "MetadataDictionary": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "key", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "flags", - "1": "health", - "2": "variant", - "3": "color", - "4": "nametag", - "5": "owner_eid", - "6": "target_eid", - "7": "air", - "8": "potion_color", - "9": "potion_ambient", - "10": "jump_duration", - "11": "hurt_time", - "12": "hurt_direction", - "13": "paddle_time_left", - "14": "paddle_time_right", - "15": "experience_value", - "16": "minecart_display_block", - "17": "minecart_display_offset", - "18": "minecart_has_display", - "20": "old_swell", - "21": "swell_dir", - "22": "charge_amount", - "23": "enderman_held_runtime_id", - "24": "entity_age", - "26": "player_flags", - "27": "player_index", - "28": "player_bed_position", - "29": "fireball_power_x", - "30": "fireball_power_y", - "31": "fireball_power_z", - "32": "aux_power", - "33": "fish_x", - "34": "fish_z", - "35": "fish_angle", - "36": "potion_aux_value", - "37": "lead_holder_eid", - "38": "scale", - "39": "interactive_tag", - "40": "npc_skin_id", - "41": "url_tag", - "42": "max_airdata_max_air", - "43": "mark_variant", - "44": "container_type", - "45": "container_base_size", - "46": "container_extra_slots_per_strength", - "47": "block_target", - "48": "wither_invulnerable_ticks", - "49": "wither_target_1", - "50": "wither_target_2", - "51": "wither_target_3", - "52": "aerial_attack", - "53": "boundingbox_width", - "54": "boundingbox_height", - "55": "fuse_length", - "56": "rider_seat_position", - "57": "rider_rotation_locked", - "58": "rider_max_rotation", - "59": "rider_min_rotation", - "60": "rider_rotation_offset", - "61": "area_effect_cloud_radius", - "62": "area_effect_cloud_waiting", - "63": "area_effect_cloud_particle_id", - "64": "shulker_peek_id", - "65": "shulker_attach_face", - "66": "shulker_attached", - "67": "shulker_attach_pos", - "68": "trading_player_eid", - "69": "trading_career", - "70": "has_command_block", - "71": "command_block_command", - "72": "command_block_last_output", - "73": "command_block_track_output", - "74": "controlling_rider_seat_number", - "75": "strength", - "76": "max_strength", - "77": "spell_casting_color", - "78": "limited_life", - "79": "armor_stand_pose_index", - "80": "ender_crystal_time_offset", - "81": "always_show_nametag", - "82": "color_2", - "83": "name_author", - "84": "score_tag", - "85": "balloon_attached_entity", - "86": "pufferfish_size", - "87": "bubble_time", - "88": "agent", - "89": "sitting_amount", - "90": "sitting_amount_previous", - "91": "eating_counter", - "92": "flags_extended", - "93": "laying_amount", - "94": "laying_amount_previous", - "95": "duration", - "96": "spawn_time", - "97": "change_rate", - "98": "change_on_pickup", - "99": "pickup_count", - "100": "interact_text", - "101": "trade_tier", - "102": "max_trade_tier", - "103": "trade_experience", - "104": "skin_id", - "105": "spawning_frames", - "106": "command_block_tick_delay", - "107": "command_block_execute_on_first_tick", - "108": "ambient_sound_interval", - "109": "ambient_sound_interval_range", - "110": "ambient_sound_event_name", - "111": "fall_damage_multiplier", - "112": "name_raw_text", - "113": "can_ride_target", - "114": "low_tier_cured_discount", - "115": "high_tier_cured_discount", - "116": "nearby_cured_discount", - "117": "nearby_cured_discount_timestamp", - "118": "hitbox", - "119": "is_buoyant", - "120": "buoyancy_data", - "121": "goat_horn_count" - } - } - ] - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "byte", - "1": "short", - "2": "int", - "3": "float", - "4": "string", - "5": "compound", - "6": "vec3i", - "7": "long", - "8": "vec3f" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "key", - "fields": { - "flags": "MetadataFlags1", - "flags_extended": "MetadataFlags2" - }, - "default": [ - "switch", - { - "compareTo": "type", - "fields": { - "byte": "i8", - "short": "li16", - "int": "zigzag32", - "float": "lf32", - "string": "string", - "compound": "nbt", - "vec3i": "vec3i", - "long": "zigzag64", - "vec3f": "vec3f" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ], - "Link": [ - "container", - [ - { - "name": "ridden_entity_id", - "type": "zigzag64" - }, - { - "name": "rider_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "immediate", - "type": "bool" - }, - { - "name": "rider_initiated", - "type": "bool" - } - ] - ], - "Links": [ - "array", - { - "countType": "varint", - "type": "Link" - } - ], - "EntityAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "min", - "type": "lf32" - }, - { - "name": "value", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - } - ] - ] - } - ], - "Rotation": [ - "container", - [ - { - "name": "yaw", - "type": "byterot" - }, - { - "name": "pitch", - "type": "byterot" - }, - { - "name": "head_yaw", - "type": "byterot" - } - ] - ], - "BlockCoordinates": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "PlayerAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "min", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - }, - { - "name": "current", - "type": "lf32" - }, - { - "name": "default", - "type": "lf32" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "TransactionUseItem": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "click_block", - "1": "click_air", - "2": "break_block" - } - } - ] - }, - { - "name": "block_position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "hotbar_slot", - "type": "varint" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - }, - { - "name": "block_runtime_id", - "type": "varint" - } - ] - ], - "TransactionActions": [ - "container", - [ - { - "name": "network_ids", - "type": "bool" - }, - { - "name": "actions", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "container", - "1": "global", - "2": "world_interaction", - "3": "creative", - "100": "craft_slot", - "99999": "craft" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "container": [ - "container", - [ - { - "name": "inventory_id", - "type": "varint" - } - ] - ], - "craft": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "world_interaction": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "craft_slot": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - }, - { - "name": "new_item_stack_id", - "type": [ - "switch", - { - "compareTo": "../network_ids", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "TransactionLegacy": [ - "container", - [ - { - "name": "legacy_request_id", - "type": "zigzag32" - }, - { - "name": "legacy_transactions", - "type": [ - "switch", - { - "compareTo": "legacy_request_id", - "fields": { - "0": "void" - }, - "default": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "changed_slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_id", - "type": "u8" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - } - ] - ], - "Transaction": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "transaction_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "inventory_mismatch", - "2": "item_use", - "3": "item_use_on_entity", - "4": "item_release" - } - } - ] - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "transaction_data", - "type": [ - "switch", - { - "compareTo": "transaction_type", - "fields": { - "normal": "void", - "inventory_mismatch": "void", - "item_use": "TransactionUseItem", - "item_use_on_entity": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "interact", - "1": "attack" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - } - ] - ], - "item_release": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "release", - "1": "consume" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "head_pos", - "type": "vec3f" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "ItemStack": [ - "container", - [ - { - "name": "stack_id", - "type": "varint" - }, - { - "name": "item", - "type": "Item" - } - ] - ], - "ItemStacks": [ - "array", - { - "countType": "varint", - "type": "ItemStack" - } - ], - "RecipeIngredient": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "network_data", - "type": "zigzag32" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ], - "PotionTypeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "input_item_meta", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "ingredient_meta", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - }, - { - "name": "output_item_meta", - "type": "zigzag32" - } - ] - ] - } - ], - "PotionContainerChangeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - } - ] - ] - } - ], - "Recipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "shapeless", - "1": "shaped", - "2": "furnace", - "3": "furnace_with_metadata", - "4": "multi", - "5": "shulker_box", - "6": "shapeless_chemistry", - "7": "shaped_chemistry" - } - } - ] - }, - { - "name": "recipe", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "shapeless": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shulker_box": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shapeless_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "furnace": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "output", - "type": "Item" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "furnace_with_metadata": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "input_meta", - "type": "zigzag32" - }, - { - "name": "output", - "type": "Item" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "multi": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "SkinImage": [ - "container", - [ - { - "name": "width", - "type": "li32" - }, - { - "name": "height", - "type": "li32" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "Skin": [ - "container", - [ - { - "name": "skin_id", - "type": "string" - }, - { - "name": "play_fab_id", - "type": "string" - }, - { - "name": "skin_resource_pack", - "type": "string" - }, - { - "name": "skin_data", - "type": "SkinImage" - }, - { - "name": "animations", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "skin_image", - "type": "SkinImage" - }, - { - "name": "animation_type", - "type": "li32" - }, - { - "name": "animation_frames", - "type": "lf32" - }, - { - "name": "expression_type", - "type": "lf32" - } - ] - ] - } - ] - }, - { - "name": "cape_data", - "type": "SkinImage" - }, - { - "name": "geometry_data", - "type": "string" - }, - { - "name": "animation_data", - "type": "string" - }, - { - "name": "premium", - "type": "string" - }, - { - "name": "persona", - "type": "bool" - }, - { - "name": "cape_on_classic", - "type": "bool" - }, - { - "name": "cape_id", - "type": "string" - }, - { - "name": "full_skin_id", - "type": "string" - }, - { - "name": "arm_size", - "type": "string" - }, - { - "name": "skin_color", - "type": "string" - }, - { - "name": "personal_pieces", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_id", - "type": "string" - }, - { - "name": "piece_type", - "type": "string" - }, - { - "name": "pack_id", - "type": "string" - }, - { - "name": "is_default_piece", - "type": "bool" - }, - { - "name": "product_id", - "type": "string" - } - ] - ] - } - ] - }, - { - "name": "piece_tint_colors", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_type", - "type": "string" - }, - { - "name": "colors", - "type": [ - "array", - { - "countType": "li32", - "type": "string" - } - ] - } - ] - ] - } - ] - } - ] - ], - "PlayerRecords": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "remove" - } - } - ] - }, - { - "name": "records_count", - "type": "varint" - }, - { - "name": "records", - "type": [ - "array", - { - "count": "records_count", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "xbox_user_id", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "build_platform", - "type": "li32" - }, - { - "name": "skin_data", - "type": "Skin" - }, - { - "name": "is_teacher", - "type": "bool" - }, - { - "name": "is_host", - "type": "bool" - } - ] - ], - "remove": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - }, - { - "name": "verified", - "type": [ - "array", - { - "count": "records_count", - "type": "bool" - } - ] - } - ] - ], - "ScoreEntries": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "change", - "1": "remove" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "remove": [ - "container", - [ - { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": "zigzag64", - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "custom_name", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "fake_player": "string" - }, - "default": "void" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "ScoreboardIdentityEntries": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "TYPE_REGISTER_IDENTITY", - "1": "TYPE_CLEAR_IDENTITY" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "TYPE_REGISTER_IDENTITY": "zigzag64" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "Enchant": [ - "container", - [ - { - "name": "id", - "type": "u8" - }, - { - "name": "level", - "type": "u8" - } - ] - ], - "EnchantOptions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "cost", - "type": "varint" - }, - { - "name": "slot_flags", - "type": "li32" - }, - { - "name": "equip_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "held_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "self_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "name", - "type": "string" - }, - { - "name": "option_id", - "type": "zigzag32" - } - ] - ] - } - ], - "Action": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "start_break", - "1": "abort_break", - "2": "stop_break", - "3": "get_updated_block", - "4": "drop_item", - "5": "start_sleeping", - "6": "stop_sleeping", - "7": "respawn", - "8": "jump", - "9": "start_sprint", - "10": "stop_sprint", - "11": "start_sneak", - "12": "stop_sneak", - "13": "creative_player_destroy_block", - "14": "dimension_change_ack", - "15": "start_glide", - "16": "stop_glide", - "17": "build_denied", - "18": "crack_break", - "19": "change_skin", - "20": "set_enchatnment_seed", - "21": "swimming", - "22": "stop_swimming", - "23": "start_spin_attack", - "24": "stop_spin_attack", - "25": "interact_block", - "26": "predict_break", - "27": "continue_break" - } - } - ], - "StackRequestSlotInfo": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "stack_id", - "type": "zigzag32" - } - ] - ], - "ItemStackRequest": [ - "container", - [ - { - "name": "request_id", - "type": "varint" - }, - { - "name": "actions", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "take", - "1": "place", - "2": "swap", - "3": "drop", - "4": "destroy", - "5": "consume", - "6": "create", - "7": "lab_table_combine", - "8": "beacon_payment", - "9": "mine_block", - "10": "craft_recipe", - "11": "craft_recipe_auto", - "12": "craft_creative", - "13": "optional", - "14": "non_implemented", - "15": "results_deprecated" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type_id", - "fields": { - "take": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "place": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "swap": [ - "container", - [ - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "drop": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "randomly", - "type": "bool" - } - ] - ], - "destroy": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "consume": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "create": [ - "container", - [ - { - "name": "result_slot_id", - "type": "u8" - } - ] - ], - "beacon_payment": [ - "container", - [ - { - "name": "primary_effect", - "type": "zigzag32" - }, - { - "name": "secondary_effect", - "type": "zigzag32" - } - ] - ], - "mine_block": [ - "container", - [ - { - "name": "unknown1", - "type": "zigzag32" - }, - { - "name": "predicted_durability", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "craft_recipe": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_recipe_auto": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_creative": [ - "container", - [ - { - "name": "item_id", - "type": "varint32" - } - ] - ], - "optional": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - }, - { - "name": "filtered_string_index", - "type": "li32" - } - ] - ], - "non_implemented": "void", - "results_deprecated": [ - "container", - [ - { - "name": "result_items", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "times_crafted", - "type": "u8" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - { - "name": "custom_names", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "ItemStackResponses": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "ok", - "1": "error" - } - } - ] - }, - { - "name": "request_id", - "type": "varint32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "status", - "fields": { - "ok": [ - "container", - [ - { - "name": "containers", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot", - "type": "u8" - }, - { - "name": "hotbar_slot", - "type": "u8" - }, - { - "name": "count", - "type": "u8" - }, - { - "name": "item_stack_id", - "type": "varint32" - }, - { - "name": "custom_name", - "type": "string" - }, - { - "name": "durability_correction", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "ItemComponentList": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ] - } - ], - "CommandOrigin": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "player", - "1": "block", - "2": "minecart_block", - "3": "dev_console", - "4": "test", - "5": "automation_player", - "6": "client_automation", - "7": "dedicated_server", - "8": "entity", - "9": "virtual", - "10": "game_argument", - "11": "entity_server" - } - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "player_entity_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "dev_console": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ], - "test": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "WindowID": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowIDVarint": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowType": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "container", - "1": "workbench", - "2": "furnace", - "3": "enchantment", - "4": "brewing_stand", - "5": "anvil", - "6": "dispenser", - "7": "dropper", - "8": "hopper", - "9": "cauldron", - "10": "minecart_chest", - "11": "minecart_hopper", - "12": "horse", - "13": "beacon", - "14": "structure_editor", - "15": "trading", - "16": "command_block", - "17": "jukebox", - "18": "armor", - "19": "hand", - "20": "compound_creator", - "21": "element_constructor", - "22": "material_reducer", - "23": "lab_table", - "24": "loom", - "25": "lectern", - "26": "grindstone", - "27": "blast_furnace", - "28": "smoker", - "29": "stonecutter", - "30": "cartography", - "31": "hud", - "32": "jigsaw_editor", - "33": "smithing_table", - "-9": "none", - "-1": "inventory" - } - } - ], - "ContainerSlotType": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "anvil_input", - "1": "anvil_material", - "2": "anvil_result", - "3": "smithing_table_input", - "4": "smithing_table_material", - "5": "smithing_table_result", - "6": "armor", - "7": "container", - "8": "beacon_payment", - "9": "brewing_input", - "10": "brewing_result", - "11": "brewing_fuel", - "12": "hotbar_and_inventory", - "13": "crafting_input", - "14": "crafting_output", - "15": "recipe_construction", - "16": "recipe_nature", - "17": "recipe_items", - "18": "recipe_search", - "19": "recipe_search_bar", - "20": "recipe_equipment", - "21": "enchanting_input", - "22": "enchanting_lapis", - "23": "furnace_fuel", - "24": "furnace_ingredient", - "25": "furnace_output", - "26": "horse_equip", - "27": "hotbar", - "28": "inventory", - "29": "shulker", - "30": "trade_ingredient1", - "31": "trade_ingredient2", - "32": "trade_result", - "33": "offhand", - "34": "compcreate_input", - "35": "compcreate_output", - "36": "elemconstruct_output", - "37": "matreduce_input", - "38": "matreduce_output", - "39": "labtable_input", - "40": "loom_input", - "41": "loom_dye", - "42": "loom_material", - "43": "loom_result", - "44": "blast_furnace_ingredient", - "45": "smoker_ingredient", - "46": "trade2_ingredient1", - "47": "trade2_ingredient2", - "48": "trade2_result", - "49": "grindstone_input", - "50": "grindstone_additional", - "51": "grindstone_result", - "52": "stonecutter_input", - "53": "stonecutter_result", - "54": "cartography_input", - "55": "cartography_additional", - "56": "cartography_result", - "57": "barrel", - "58": "cursor", - "59": "creative_output" - } - } - ], - "LegacyEntityType": [ - "mapper", - { - "type": "li32", - "mappings": { - "10": "chicken", - "11": "cow", - "12": "pig", - "13": "sheep", - "14": "wolf", - "15": "villager", - "16": "mooshroom", - "17": "squid", - "18": "rabbit", - "19": "bat", - "20": "iron_golem", - "21": "snow_golem", - "22": "ocelot", - "23": "horse", - "24": "donkey", - "25": "mule", - "26": "skeleton_horse", - "27": "zombie_horse", - "28": "polar_bear", - "29": "llama", - "30": "parrot", - "31": "dolphin", - "32": "zombie", - "33": "creeper", - "34": "skeleton", - "35": "spider", - "36": "zombie_pigman", - "37": "slime", - "38": "enderman", - "39": "silverfish", - "40": "cave_spider", - "41": "ghast", - "42": "magma_cube", - "43": "blaze", - "44": "zombie_villager", - "45": "witch", - "46": "stray", - "47": "husk", - "48": "wither_skeleton", - "49": "guardian", - "50": "elder_guardian", - "51": "npc", - "52": "wither", - "53": "ender_dragon", - "54": "shulker", - "55": "endermite", - "56": "agent", - "57": "vindicator", - "58": "phantom", - "61": "armor_stand", - "62": "tripod_camera", - "63": "player", - "64": "item", - "65": "tnt", - "66": "falling_block", - "67": "moving_block", - "68": "xp_bottle", - "69": "xp_orb", - "70": "eye_of_ender_signal", - "71": "ender_crystal", - "72": "fireworks_rocket", - "73": "thrown_trident", - "74": "turtle", - "75": "cat", - "76": "shulker_bullet", - "77": "fishing_hook", - "78": "chalkboard", - "79": "dragon_fireball", - "80": "arrow", - "81": "snowball", - "82": "egg", - "83": "painting", - "84": "minecart", - "85": "fireball", - "86": "splash_potion", - "87": "ender_pearl", - "88": "leash_knot", - "89": "wither_skull", - "90": "boat", - "91": "wither_skull_dangerous", - "93": "lightning_bolt", - "94": "small_fireball", - "95": "area_effect_cloud", - "96": "hopper_minecart", - "97": "tnt_minecart", - "98": "chest_minecart", - "100": "command_block_minecart", - "101": "lingering_potion", - "102": "llama_spit", - "103": "evocation_fang", - "104": "evocation_illager", - "105": "vex", - "106": "ice_bomb", - "107": "balloon", - "108": "pufferfish", - "109": "salmon", - "110": "drowned", - "111": "tropicalfish", - "112": "cod", - "113": "panda" - } - } - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "login", - "2": "play_status", - "3": "server_to_client_handshake", - "4": "client_to_server_handshake", - "5": "disconnect", - "6": "resource_packs_info", - "7": "resource_pack_stack", - "8": "resource_pack_client_response", - "9": "text", - "10": "set_time", - "11": "start_game", - "12": "add_player", - "13": "add_entity", - "14": "remove_entity", - "15": "add_item_entity", - "17": "take_item_entity", - "18": "move_entity", - "19": "move_player", - "20": "rider_jump", - "21": "update_block", - "22": "add_painting", - "23": "tick_sync", - "24": "level_sound_event_old", - "25": "level_event", - "26": "block_event", - "27": "entity_event", - "28": "mob_effect", - "29": "update_attributes", - "30": "inventory_transaction", - "31": "mob_equipment", - "32": "mob_armor_equipment", - "33": "interact", - "34": "block_pick_request", - "35": "entity_pick_request", - "36": "player_action", - "38": "hurt_armor", - "39": "set_entity_data", - "40": "set_entity_motion", - "41": "set_entity_link", - "42": "set_health", - "43": "set_spawn_position", - "44": "animate", - "45": "respawn", - "46": "container_open", - "47": "container_close", - "48": "player_hotbar", - "49": "inventory_content", - "50": "inventory_slot", - "51": "container_set_data", - "52": "crafting_data", - "53": "crafting_event", - "54": "gui_data_pick_item", - "55": "adventure_settings", - "56": "block_entity_data", - "57": "player_input", - "58": "level_chunk", - "59": "set_commands_enabled", - "60": "set_difficulty", - "61": "change_dimension", - "62": "set_player_game_type", - "63": "player_list", - "64": "simple_event", - "65": "event", - "66": "spawn_experience_orb", - "67": "clientbound_map_item_data", - "68": "map_info_request", - "69": "request_chunk_radius", - "70": "chunk_radius_update", - "71": "item_frame_drop_item", - "72": "game_rules_changed", - "73": "camera", - "74": "boss_event", - "75": "show_credits", - "76": "available_commands", - "77": "command_request", - "78": "command_block_update", - "79": "command_output", - "80": "update_trade", - "81": "update_equipment", - "82": "resource_pack_data_info", - "83": "resource_pack_chunk_data", - "84": "resource_pack_chunk_request", - "85": "transfer", - "86": "play_sound", - "87": "stop_sound", - "88": "set_title", - "89": "add_behavior_tree", - "90": "structure_block_update", - "91": "show_store_offer", - "92": "purchase_receipt", - "93": "player_skin", - "94": "sub_client_login", - "95": "initiate_web_socket_connection", - "96": "set_last_hurt_by", - "97": "book_edit", - "98": "npc_request", - "99": "photo_transfer", - "100": "modal_form_request", - "101": "modal_form_response", - "102": "server_settings_request", - "103": "server_settings_response", - "104": "show_profile", - "105": "set_default_game_type", - "106": "remove_objective", - "107": "set_display_objective", - "108": "set_score", - "109": "lab_table", - "110": "update_block_synced", - "111": "move_entity_delta", - "112": "set_scoreboard_identity", - "113": "set_local_player_as_initialized", - "114": "update_soft_enum", - "115": "network_stack_latency", - "117": "script_custom_event", - "118": "spawn_particle_effect", - "119": "available_entity_identifiers", - "120": "level_sound_event_v2", - "121": "network_chunk_publisher_update", - "122": "biome_definition_list", - "123": "level_sound_event", - "124": "level_event_generic", - "125": "lectern_update", - "126": "video_stream_connect", - "127": "add_ecs_entity", - "128": "remove_ecs_entity", - "129": "client_cache_status", - "130": "on_screen_texture_animation", - "131": "map_create_locked_copy", - "132": "structure_template_data_export_request", - "133": "structure_template_data_export_response", - "134": "update_block_properties", - "135": "client_cache_blob_status", - "136": "client_cache_miss_response", - "137": "education_settings", - "139": "multiplayer_settings", - "140": "settings_command", - "141": "anvil_damage", - "142": "completed_using_item", - "143": "network_settings", - "144": "player_auth_input", - "145": "creative_content", - "146": "player_enchant_options", - "147": "item_stack_request", - "148": "item_stack_response", - "149": "player_armor_damage", - "151": "update_player_game_type", - "153": "position_tracking_db_broadcast", - "154": "position_tracking_db_request", - "156": "packet_violation_warning", - "157": "motion_prediction_hints", - "158": "animate_entity", - "159": "camera_shake", - "160": "player_fog", - "161": "correct_player_move_prediction", - "162": "item_component", - "163": "filter_text_packet", - "164": "debug_renderer" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "login": "packet_login", - "play_status": "packet_play_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "tick_sync": "packet_tick_sync", - "level_sound_event_old": "packet_level_sound_event_old", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "inventory_transaction": "packet_inventory_transaction", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "block_pick_request": "packet_block_pick_request", - "entity_pick_request": "packet_entity_pick_request", - "player_action": "packet_player_action", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "player_hotbar": "packet_player_hotbar", - "inventory_content": "packet_inventory_content", - "inventory_slot": "packet_inventory_slot", - "container_set_data": "packet_container_set_data", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "gui_data_pick_item": "packet_gui_data_pick_item", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "level_chunk": "packet_level_chunk", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "simple_event": "packet_simple_event", - "event": "packet_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data": "packet_clientbound_map_item_data", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_frame_drop_item": "packet_item_frame_drop_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "boss_event": "packet_boss_event", - "show_credits": "packet_show_credits", - "available_commands": "packet_available_commands", - "command_request": "packet_command_request", - "command_block_update": "packet_command_block_update", - "command_output": "packet_command_output", - "update_trade": "packet_update_trade", - "update_equipment": "packet_update_equipment", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request", - "transfer": "packet_transfer", - "play_sound": "packet_play_sound", - "stop_sound": "packet_stop_sound", - "set_title": "packet_set_title", - "add_behavior_tree": "packet_add_behavior_tree", - "structure_block_update": "packet_structure_block_update", - "show_store_offer": "packet_show_store_offer", - "purchase_receipt": "packet_purchase_receipt", - "player_skin": "packet_player_skin", - "sub_client_login": "packet_sub_client_login", - "initiate_web_socket_connection": "packet_initiate_web_socket_connection", - "set_last_hurt_by": "packet_set_last_hurt_by", - "book_edit": "packet_book_edit", - "npc_request": "packet_npc_request", - "photo_transfer": "packet_photo_transfer", - "modal_form_request": "packet_modal_form_request", - "modal_form_response": "packet_modal_form_response", - "server_settings_request": "packet_server_settings_request", - "server_settings_response": "packet_server_settings_response", - "show_profile": "packet_show_profile", - "set_default_game_type": "packet_set_default_game_type", - "remove_objective": "packet_remove_objective", - "set_display_objective": "packet_set_display_objective", - "set_score": "packet_set_score", - "lab_table": "packet_lab_table", - "update_block_synced": "packet_update_block_synced", - "move_entity_delta": "packet_move_entity_delta", - "set_scoreboard_identity": "packet_set_scoreboard_identity", - "set_local_player_as_initialized": "packet_set_local_player_as_initialized", - "update_soft_enum": "packet_update_soft_enum", - "network_stack_latency": "packet_network_stack_latency", - "script_custom_event": "packet_script_custom_event", - "spawn_particle_effect": "packet_spawn_particle_effect", - "available_entity_identifiers": "packet_available_entity_identifiers", - "level_sound_event_v2": "packet_level_sound_event_v2", - "network_chunk_publisher_update": "packet_network_chunk_publisher_update", - "biome_definition_list": "packet_biome_definition_list", - "level_sound_event": "packet_level_sound_event", - "level_event_generic": "packet_level_event_generic", - "lectern_update": "packet_lectern_update", - "video_stream_connect": "packet_video_stream_connect", - "add_ecs_entity": "packet_add_ecs_entity", - "remove_ecs_entity": "packet_remove_ecs_entity", - "client_cache_status": "packet_client_cache_status", - "on_screen_texture_animation": "packet_on_screen_texture_animation", - "map_create_locked_copy": "packet_map_create_locked_copy", - "structure_template_data_export_request": "packet_structure_template_data_export_request", - "structure_template_data_export_response": "packet_structure_template_data_export_response", - "update_block_properties": "packet_update_block_properties", - "client_cache_blob_status": "packet_client_cache_blob_status", - "client_cache_miss_response": "packet_client_cache_miss_response", - "education_settings": "packet_education_settings", - "multiplayer_settings": "packet_multiplayer_settings", - "settings_command": "packet_settings_command", - "anvil_damage": "packet_anvil_damage", - "completed_using_item": "packet_completed_using_item", - "network_settings": "packet_network_settings", - "player_auth_input": "packet_player_auth_input", - "creative_content": "packet_creative_content", - "player_enchant_options": "packet_player_enchant_options", - "item_stack_request": "packet_item_stack_request", - "item_stack_response": "packet_item_stack_response", - "player_armor_damage": "packet_player_armor_damage", - "update_player_game_type": "packet_update_player_game_type", - "position_tracking_db_request": "packet_position_tracking_db_request", - "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", - "packet_violation_warning": "packet_packet_violation_warning", - "motion_prediction_hints": "packet_motion_prediction_hints", - "animate_entity": "packet_animate_entity", - "camera_shake": "packet_camera_shake", - "player_fog": "packet_player_fog", - "correct_player_move_prediction": "packet_correct_player_move_prediction", - "item_component": "packet_item_component", - "filter_text_packet": "packet_filter_text_packet", - "debug_renderer": "packet_debug_renderer" - }, - "default": "void" - } - ] - } - ] - ], - "packet_login": [ - "container", - [ - { - "name": "protocol_version", - "type": "i32" - }, - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "LoginTokens": [ - "container", - [ - { - "name": "identity", - "type": "LittleString" - }, - { - "name": "client", - "type": "LittleString" - } - ] - ], - "packet_play_status": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "i32", - "mappings": { - "0": "login_success", - "1": "failed_client", - "2": "failed_spawn", - "3": "player_spawn", - "4": "failed_invalid_tenant", - "5": "failed_vanilla_edu", - "6": "failed_edu_vanilla", - "7": "failed_server_full" - } - } - ] - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "token", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "behaviour_packs", - "type": "BehaviourPackInfos" - }, - { - "name": "texture_packs", - "type": "TexturePackInfos" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behavior_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "resource_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "refused", - "2": "send_packs", - "3": "have_all_packs", - "4": "completed" - } - } - ] - }, - { - "name": "resourcepackids", - "type": "ResourcePackIds" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "raw", - "1": "chat", - "2": "translation", - "3": "popup", - "4": "jukebox_popup", - "5": "tip", - "6": "system", - "7": "whisper", - "8": "announcement", - "9": "json_whisper", - "10": "json" - } - } - ] - }, - { - "name": "needs_translation", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "chat": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "whisper": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "announcement": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "raw": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "tip": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "system": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json_whisper": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "translation": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "jukebox_popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "xuid", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "zigzag32" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "player_gamemode", - "type": "GameMode" - }, - { - "name": "player_position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "vec2f" - }, - { - "name": "seed", - "type": "zigzag32" - }, - { - "name": "biome_type", - "type": "li16" - }, - { - "name": "biome_name", - "type": "string" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "generator", - "type": "zigzag32" - }, - { - "name": "world_gamemode", - "type": "GameMode" - }, - { - "name": "difficulty", - "type": "zigzag32" - }, - { - "name": "spawn_position", - "type": "BlockCoordinates" - }, - { - "name": "achievements_disabled", - "type": "bool" - }, - { - "name": "day_cycle_stop_time", - "type": "zigzag32" - }, - { - "name": "edu_offer", - "type": "zigzag32" - }, - { - "name": "edu_features_enabled", - "type": "bool" - }, - { - "name": "edu_product_uuid", - "type": "string" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightning_level", - "type": "lf32" - }, - { - "name": "has_confirmed_platform_locked_content", - "type": "bool" - }, - { - "name": "is_multiplayer", - "type": "bool" - }, - { - "name": "broadcast_to_lan", - "type": "bool" - }, - { - "name": "xbox_live_broadcast_mode", - "type": "varint" - }, - { - "name": "platform_broadcast_mode", - "type": "varint" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - { - "name": "gamerules", - "type": "GameRules" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - }, - { - "name": "bonus_chest", - "type": "bool" - }, - { - "name": "map_enabled", - "type": "bool" - }, - { - "name": "permission_level", - "type": "zigzag32" - }, - { - "name": "server_chunk_tick_range", - "type": "li32" - }, - { - "name": "has_locked_behavior_pack", - "type": "bool" - }, - { - "name": "has_locked_resource_pack", - "type": "bool" - }, - { - "name": "is_from_locked_world_template", - "type": "bool" - }, - { - "name": "msa_gamertags_only", - "type": "bool" - }, - { - "name": "is_from_world_template", - "type": "bool" - }, - { - "name": "is_world_template_option_locked", - "type": "bool" - }, - { - "name": "only_spawn_v1_villagers", - "type": "bool" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "limited_world_width", - "type": "li32" - }, - { - "name": "limited_world_length", - "type": "li32" - }, - { - "name": "is_new_nether", - "type": "bool" - }, - { - "name": "experimental_gameplay_override", - "type": "bool" - }, - { - "name": "level_id", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - }, - { - "name": "premium_world_template_id", - "type": "string" - }, - { - "name": "is_trial", - "type": "bool" - }, - { - "name": "movement_authority", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "client", - "1": "server", - "2": "server_with_rewind" - } - } - ] - }, - { - "name": "rewind_history_size", - "type": "zigzag32" - }, - { - "name": "server_authoritative_block_breaking", - "type": "bool" - }, - { - "name": "current_tick", - "type": "li64" - }, - { - "name": "enchantment_seed", - "type": "zigzag32" - }, - { - "name": "block_palette", - "type": "BlockPalette" - }, - { - "name": "itemstates", - "type": "Itemstates" - }, - { - "name": "multiplayer_correlation_id", - "type": "string" - }, - { - "name": "server_authoritative_inventory", - "type": "bool" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - }, - { - "name": "links", - "type": "Links" - }, - { - "name": "device_id", - "type": "string" - }, - { - "name": "device_os", - "type": "li32" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "attributes", - "type": "EntityAttributes" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "links", - "type": "Links" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "speed_x", - "type": "lf32" - }, - { - "name": "speed_y", - "type": "lf32" - }, - { - "name": "speed_z", - "type": "lf32" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "is_from_fishing", - "type": "bool" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "target", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "Rotation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "normal", - "1": "reset", - "2": "teleport", - "3": "rotation" - } - } - ] - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "ridden_runtime_id", - "type": "varint" - }, - { - "name": "teleport", - "type": [ - "switch", - { - "compareTo": "mode", - "fields": { - "teleport": [ - "container", - [ - { - "name": "cause", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "unknown", - "1": "projectile", - "2": "chorus_fruit", - "3": "command", - "4": "behavior" - } - } - ] - }, - { - "name": "source_entity_type", - "type": "LegacyEntityType" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_rider_jump": [ - "container", - [ - { - "name": "jump_strength", - "type": "zigzag32" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "direction", - "type": "zigzag32" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_tick_sync": [ - "container", - [ - { - "name": "request_time", - "type": "li64" - }, - { - "name": "response_time", - "type": "li64" - } - ] - ], - "packet_level_sound_event_old": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "zigzag32" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "1000": "sound_click", - "1001": "sound_click_fail", - "1002": "sound_shoot", - "1003": "sound_door", - "1004": "sound_fizz", - "1005": "sound_ignite", - "1007": "sound_ghast", - "1008": "sound_ghast_shoot", - "1009": "sound_blaze_shoot", - "1010": "sound_door_bump", - "1012": "sound_door_crash", - "1018": "sound_enderman_teleport", - "1020": "sound_anvil_break", - "1021": "sound_anvil_use", - "1022": "sound_anvil_fall", - "1030": "sound_pop", - "1032": "sound_portal", - "1040": "sound_itemframe_add_item", - "1041": "sound_itemframe_remove", - "1042": "sound_itemframe_place", - "1043": "sound_itemframe_remove_item", - "1044": "sound_itemframe_rotate_item", - "1050": "sound_camera", - "1051": "sound_orb", - "1052": "sound_totem", - "1060": "sound_armor_stand_break", - "1061": "sound_armor_stand_hit", - "1062": "sound_armor_stand_fall", - "1063": "sound_armor_stand_place", - "2000": "particle_shoot", - "2001": "particle_destroy", - "2002": "particle_splash", - "2003": "particle_eye_despawn", - "2004": "particle_spawn", - "2006": "guardian_curse", - "2008": "particle_block_force_field", - "2009": "particle_projectile_hit", - "2013": "particle_enderman_teleport", - "2014": "particle_punch_block", - "3001": "start_rain", - "3002": "start_thunder", - "3003": "stop_rain", - "3004": "stop_thunder", - "3005": "pause_game", - "3006": "pause_game_no_screen", - "3007": "set_game_speed", - "3500": "redstone_trigger", - "3501": "cauldron_explode", - "3502": "cauldron_dye_armor", - "3503": "cauldron_clean_armor", - "3504": "cauldron_fill_potion", - "3505": "cauldron_take_potion", - "3506": "cauldron_fill_water", - "3507": "cauldron_take_water", - "3508": "cauldron_add_dye", - "3509": "cauldron_clean_banner", - "3600": "block_start_break", - "3601": "block_stop_break", - "4000": "set_data", - "9800": "players_sleeping", - "16384": "add_particle_mask" - } - } - ] - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "sound", - "1": "change_state" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "jump", - "2": "hurt_animation", - "3": "death_animation", - "4": "arm_swing", - "5": "stop_attack", - "6": "tame_fail", - "7": "tame_success", - "8": "shake_wet", - "9": "use_item", - "10": "eat_grass_animation", - "11": "fish_hook_bubble", - "12": "fish_hook_position", - "13": "fish_hook_hook", - "14": "fish_hook_tease", - "15": "squid_ink_cloud", - "16": "zombie_villager_cure", - "18": "respawn", - "19": "iron_golem_offer_flower", - "20": "iron_golem_withdraw_flower", - "21": "love_particles", - "22": "villager_angry", - "23": "villager_happy", - "24": "witch_spell_particles", - "25": "firework_particles", - "26": "in_love_particles", - "27": "silverfish_spawn_animation", - "28": "guardian_attack", - "29": "witch_drink_potion", - "30": "witch_throw_potion", - "31": "minecart_tnt_prime_fuse", - "32": "creeper_prime_fuse", - "33": "air_supply_expired", - "34": "player_add_xp_levels", - "35": "elder_guardian_curse", - "36": "agent_arm_swing", - "37": "ender_dragon_death", - "38": "dust_particles", - "39": "arrow_shake", - "57": "eating_item", - "60": "baby_animal_feed", - "61": "death_smoke_cloud", - "62": "complete_trade", - "63": "remove_leash", - "65": "consume_totem", - "66": "player_check_treasure_hunter_achievement", - "67": "entity_spawn", - "68": "dragon_puke", - "69": "item_entity_merge", - "70": "start_swim", - "71": "balloon_pop", - "72": "treasure_hunt", - "73": "agent_summon", - "74": "charged_crossbow", - "75": "fall" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "zigzag32" - }, - { - "name": "amplifier", - "type": "zigzag32" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "zigzag32" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "attributes", - "type": "PlayerAttributes" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_inventory_transaction": [ - "container", - [ - { - "name": "transaction", - "type": "Transaction" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "window_id", - "type": "WindowID" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "helmet", - "type": "Item" - }, - { - "name": "chestplate", - "type": "Item" - }, - { - "name": "leggings", - "type": "Item" - }, - { - "name": "boots", - "type": "Item" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "3": "leave_vehicle", - "4": "mouse_over_entity", - "6": "open_inventory" - } - } - ] - }, - { - "name": "target_entity_id", - "type": "varint64" - }, - { - "name": "position", - "type": [ - "switch", - { - "compareTo": "action_id", - "fields": { - "mouse_over_entity": "vec3f", - "leave_vehicle": "vec3f" - }, - "default": "void" - } - ] - } - ] - ], - "packet_block_pick_request": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "add_user_data", - "type": "bool" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_entity_pick_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "lu64" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "action", - "type": "Action" - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "tick", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "link", - "type": "Link" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "spawn_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "player", - "1": "world" - } - } - ] - }, - { - "name": "player_position", - "type": "BlockCoordinates" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "world_position", - "type": "BlockCoordinates" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": "zigzag32" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - }, - { - "name": "state", - "type": "u8" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "runtime_entity_id", - "type": "zigzag64" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "server", - "type": "bool" - } - ] - ], - "packet_player_hotbar": [ - "container", - [ - { - "name": "selected_slot", - "type": "varint" - }, - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "select_slot", - "type": "bool" - } - ] - ], - "packet_inventory_content": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "input", - "type": "ItemStacks" - } - ] - ], - "packet_inventory_slot": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "ItemStack" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "property", - "type": "zigzag32" - }, - { - "name": "value", - "type": "zigzag32" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "Recipes" - }, - { - "name": "potion_type_recipes", - "type": "PotionTypeRecipes" - }, - { - "name": "potion_container_recipes", - "type": "PotionContainerChangeRecipes" - }, - { - "name": "is_clean", - "type": "bool" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "recipe_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "inventory", - "1": "crafting", - "2": "workbench" - } - } - ] - }, - { - "name": "recipe_id", - "type": "uuid" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "result", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - } - ] - ], - "packet_gui_data_pick_item": [ - "container", - [ - { - "name": "item_name", - "type": "string" - }, - { - "name": "item_effects", - "type": "string" - }, - { - "name": "hotbar_slot", - "type": "li32" - } - ] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "AdventureFlags" - }, - { - "name": "command_permission", - "type": [ - "mapper", - { - "type": "varint32", - "mappings": { - "0": "normal", - "1": "operator", - "2": "host", - "3": "automation", - "4": "admin" - } - } - ] - }, - { - "name": "action_permissions", - "type": "ActionPermissions" - }, - { - "name": "permission_level", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "visitor", - "1": "member", - "2": "operator", - "3": "custom" - } - } - ] - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "jumping", - "type": "bool" - }, - { - "name": "sneaking", - "type": "bool" - } - ] - ], - "packet_level_chunk": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "sub_chunk_count", - "type": "varint" - }, - { - "name": "cache_enabled", - "type": "bool" - }, - { - "name": "blobs", - "type": [ - "switch", - { - "compareTo": "cache_enabled", - "fields": { - "true": [ - "container", - [ - { - "name": "hashes", - "type": [ - "array", - { - "countType": "varint", - "type": "lu64" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "respawn", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "PlayerRecords" - } - ] - ], - "packet_simple_event": [ - "container", - [ - { - "name": "event_type", - "type": "lu16" - } - ] - ], - "packet_event": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint64" - }, - { - "name": "event_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "achievement_awarded", - "1": "entity_interact", - "2": "portal_built", - "3": "portal_used", - "4": "mob_killed", - "5": "cauldron_used", - "6": "player_death", - "7": "boss_killed", - "8": "agent_command", - "9": "agent_created", - "10": "banner_pattern_removed", - "11": "commaned_executed", - "12": "fish_bucketed", - "13": "mob_born", - "14": "pet_died", - "15": "cauldron_block_used", - "16": "composter_block_used", - "17": "bell_block_used", - "18": "actor_definition", - "19": "raid_update", - "20": "player_movement_anomaly", - "21": "player_moement_corrected", - "22": "honey_harvested", - "23": "target_block_hit", - "24": "piglin_barter" - } - } - ] - }, - { - "name": "use_player_id", - "type": "u8" - }, - { - "name": "event_data", - "type": "restBuffer" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ], - "packet_clientbound_map_item_data": [ - "container", - [ - { - "name": "mapinfo", - "type": "MapInfo" - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_item_frame_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - } - ] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "GameRules" - } - ] - ], - "packet_camera": [ - "container", - [ - { - "name": "camera_entity_unique_id", - "type": "zigzag64" - }, - { - "name": "target_player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_boss_event": [ - "container", - [ - { - "name": "boss_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "show_bar", - "1": "register_player", - "2": "hide_bar", - "3": "unregister_player", - "4": "set_bar_progress", - "5": "set_bar_title", - "6": "update_properties", - "7": "texture" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "register_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "unregister_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "show": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "bar_progress", - "type": "lf32" - } - ] - ], - "update_properties": [ - "container", - [ - { - "name": "darkness_factor", - "type": "li16" - } - ] - ], - "texture": [ - "container", - [ - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "set_bar_progress": [ - "container", - [ - { - "name": "bar_progress", - "type": "lf32" - } - ] - ], - "set_bar_title": [ - "container", - [ - { - "name": "title", - "type": "string" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_show_credits": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "status", - "type": "zigzag32" - } - ] - ], - "packet_available_commands": [ - "container", - [ - { - "name": "values_len", - "type": "varint" - }, - { - "name": "_enum_type", - "type": [ - "enum_size_based_on_values_len" - ] - }, - { - "name": "enum_values", - "type": [ - "array", - { - "count": "values_len", - "type": "string" - } - ] - }, - { - "name": "suffixes", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - }, - { - "name": "enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "switch", - { - "compareTo": "../_enum_type", - "fields": { - "byte": "u8", - "short": "lu16", - "int": "lu32" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "command_data", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "description", - "type": "string" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "permission_level", - "type": "u8" - }, - { - "name": "alias", - "type": "li32" - }, - { - "name": "overloads", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "paramater_name", - "type": "string" - }, - { - "name": "value_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "1": "int", - "2": "float", - "3": "value", - "4": "wildcard_int", - "5": "operator", - "6": "target", - "16": "file_path", - "32": "string", - "40": "position", - "44": "message", - "46": "raw_text", - "50": "json", - "63": "command" - } - } - ] - }, - { - "name": "enum_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "16": "valid", - "32": "enum", - "256": "suffixed", - "1024": "soft_enum" - } - } - ] - }, - { - "name": "optional", - "type": "bool" - }, - { - "name": "options", - "type": "CommandFlags" - } - ] - ] - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "dynamic_enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "enum_constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "value_index", - "type": "li32" - }, - { - "name": "enum_index", - "type": "li32" - }, - { - "name": "constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "constraint", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "cheats_enabled" - } - } - ] - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_command_request": [ - "container", - [ - { - "name": "command", - "type": "string" - }, - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "interval", - "type": "bool" - } - ] - ], - "packet_command_block_update": [ - "container", - [ - { - "name": "is_block", - "type": "bool" - } - ] - ], - "packet_command_output": [ - "container", - [ - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "output_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "last", - "2": "silent", - "3": "all", - "4": "data_set" - } - } - ] - }, - { - "name": "success_count", - "type": "varint" - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "success", - "type": "bool" - }, - { - "name": "message_id", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "data_set", - "type": [ - "switch", - { - "compareTo": "output_type", - "fields": { - "data_set": "string" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_trade": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "varint" - }, - { - "name": "trade_tier", - "type": "varint" - }, - { - "name": "villager_unique_id", - "type": "varint64" - }, - { - "name": "entity_unique_id", - "type": "varint64" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "new_trading_ui", - "type": "bool" - }, - { - "name": "economic_trades", - "type": "bool" - }, - { - "name": "offers", - "type": "nbt" - } - ] - ], - "packet_update_equipment": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "inventory", - "type": "nbt" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "max_chunk_size", - "type": "lu32" - }, - { - "name": "chunk_count", - "type": "lu32" - }, - { - "name": "compressed_package_size", - "type": "lu64" - }, - { - "name": "hash", - "type": "ByteArray" - }, - { - "name": "is_premium", - "type": "bool" - }, - { - "name": "pack_type", - "type": "u8" - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - }, - { - "name": "progress", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "package_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "server_address", - "type": "string" - }, - { - "name": "port", - "type": "lu16" - } - ] - ], - "packet_play_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "volume", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - } - ] - ], - "packet_stop_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "stop_all", - "type": "bool" - } - ] - ], - "packet_set_title": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "clear", - "1": "reset", - "2": "set_title", - "3": "set_subtitle", - "4": "action_bar_message", - "5": "set_durations", - "6": "set_title_json", - "7": "set_subtitle_json", - "8": "action_bar_message_json" - } - } - ] - }, - { - "name": "text", - "type": "string" - }, - { - "name": "fade_in_time", - "type": "zigzag32" - }, - { - "name": "stay_time", - "type": "zigzag32" - }, - { - "name": "fade_out_time", - "type": "zigzag32" - } - ] - ], - "packet_add_behavior_tree": [ - "container", - [ - { - "name": "behaviortree", - "type": "string" - } - ] - ], - "packet_structure_block_update": [ - "container", - [] - ], - "packet_show_store_offer": [ - "container", - [ - { - "name": "unknown0", - "type": "string" - }, - { - "name": "unknown1", - "type": "bool" - } - ] - ], - "packet_purchase_receipt": [ - "container", - [] - ], - "packet_player_skin": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "skin", - "type": "Skin" - }, - { - "name": "skin_name", - "type": "string" - }, - { - "name": "old_skin_name", - "type": "string" - }, - { - "name": "is_verified", - "type": "bool" - } - ] - ], - "packet_sub_client_login": [ - "container", - [] - ], - "packet_initiate_web_socket_connection": [ - "container", - [ - { - "name": "server", - "type": "string" - } - ] - ], - "packet_set_last_hurt_by": [ - "container", - [ - { - "name": "unknown", - "type": "varint" - } - ] - ], - "packet_book_edit": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "replace_page", - "1": "add_page", - "2": "delete_page", - "3": "swap_pages", - "4": "sign" - } - } - ] - }, - { - "name": "slot", - "type": "u8" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "replace_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "add_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "delete_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - } - ] - ], - "swap_pages": [ - "container", - [ - { - "name": "page1", - "type": "u8" - }, - { - "name": "page2", - "type": "u8" - } - ] - ], - "sign": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "author", - "type": "string" - }, - { - "name": "xuid", - "type": "string" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_npc_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "unknown0", - "type": "u8" - }, - { - "name": "unknown1", - "type": "string" - }, - { - "name": "unknown2", - "type": "u8" - } - ] - ], - "packet_photo_transfer": [ - "container", - [ - { - "name": "file_name", - "type": "string" - }, - { - "name": "image_data", - "type": "string" - }, - { - "name": "unknown2", - "type": "string" - } - ] - ], - "packet_modal_form_request": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_modal_form_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_server_settings_request": [ - "container", - [] - ], - "packet_server_settings_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_show_profile": [ - "container", - [ - { - "name": "xuid", - "type": "string" - } - ] - ], - "packet_set_default_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_remove_objective": [ - "container", - [ - { - "name": "objective_name", - "type": "string" - } - ] - ], - "packet_set_display_objective": [ - "container", - [ - { - "name": "display_slot", - "type": "string" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "criteria_name", - "type": "string" - }, - { - "name": "sort_order", - "type": "zigzag32" - } - ] - ], - "packet_set_score": [ - "container", - [ - { - "name": "entries", - "type": "ScoreEntries" - } - ] - ], - "packet_lab_table": [ - "container", - [ - { - "name": "useless_byte", - "type": "u8" - }, - { - "name": "lab_table_x", - "type": "varint" - }, - { - "name": "lab_table_y", - "type": "varint" - }, - { - "name": "lab_table_z", - "type": "varint" - }, - { - "name": "reaction_type", - "type": "u8" - } - ] - ], - "packet_update_block_synced": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "transition_type", - "type": [ - "mapper", - { - "type": "varint64", - "mappings": { - "0": "entity", - "1": "create", - "2": "destroy" - } - } - ] - } - ] - ], - "packet_move_entity_delta": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "DeltaMoveFlags" - }, - { - "name": "x", - "type": [ - "switch", - { - "compareTo": "flags.has_x", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "y", - "type": [ - "switch", - { - "compareTo": "flags.has_y", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "z", - "type": [ - "switch", - { - "compareTo": "flags.has_z", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "rot_x", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_x", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_y", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_y", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_z", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_z", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_scoreboard_identity": [ - "container", - [ - { - "name": "entries", - "type": "ScoreboardIdentityEntries" - } - ] - ], - "packet_set_local_player_as_initialized": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_update_soft_enum": [ - "container", - [] - ], - "packet_network_stack_latency": [ - "container", - [ - { - "name": "timestamp", - "type": "lu64" - }, - { - "name": "unknown_flag", - "type": "u8" - } - ] - ], - "packet_script_custom_event": [ - "container", - [ - { - "name": "event_name", - "type": "string" - }, - { - "name": "event_data", - "type": "string" - } - ] - ], - "packet_spawn_particle_effect": [ - "container", - [ - { - "name": "dimension_id", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "particle_name", - "type": "string" - } - ] - ], - "packet_available_entity_identifiers": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event_v2": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_network_chunk_publisher_update": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "radius", - "type": "varint" - } - ] - ], - "packet_biome_definition_list": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "varint" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event_generic": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "nbt", - "type": "nbtLoop" - } - ] - ], - "packet_lectern_update": [ - "container", - [ - { - "name": "page", - "type": "u8" - }, - { - "name": "page_count", - "type": "u8" - }, - { - "name": "position", - "type": "vec3i" - }, - { - "name": "drop_book", - "type": "bool" - } - ] - ], - "packet_video_stream_connect": [ - "container", - [ - { - "name": "server_uri", - "type": "string" - }, - { - "name": "frame_send_frequency", - "type": "lf32" - }, - { - "name": "action", - "type": "u8" - }, - { - "name": "resolution_x", - "type": "li32" - }, - { - "name": "resolution_y", - "type": "li32" - } - ] - ], - "packet_add_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_remove_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_client_cache_status": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_on_screen_texture_animation": [ - "container", - [] - ], - "packet_map_create_locked_copy": [ - "container", - [] - ], - "packet_structure_template_data_export_request": [ - "container", - [] - ], - "packet_structure_template_data_export_response": [ - "container", - [] - ], - "packet_update_block_properties": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_client_cache_blob_status": [ - "container", - [ - { - "name": "misses", - "type": "varint" - }, - { - "name": "haves", - "type": "varint" - }, - { - "name": "missing", - "type": [ - "array", - { - "count": "misses", - "type": "lu64" - } - ] - }, - { - "name": "have", - "type": [ - "array", - { - "count": "haves", - "type": "lu64" - } - ] - } - ] - ], - "packet_client_cache_miss_response": [ - "container", - [ - { - "name": "blobs", - "type": [ - "array", - { - "countType": "varint", - "type": "Blob" - } - ] - } - ] - ], - "packet_education_settings": [ - "container", - [ - { - "name": "CodeBuilderDefaultURI", - "type": "string" - }, - { - "name": "CodeBuilderTitle", - "type": "string" - }, - { - "name": "CanResizeCodeBuilder", - "type": "bool" - }, - { - "name": "HasOverrideURI", - "type": "bool" - }, - { - "name": "OverrideURI", - "type": [ - "switch", - { - "compareTo": "HasOverrideURI", - "fields": { - "true": "string" - }, - "default": "void" - } - ] - }, - { - "name": "HasQuiz", - "type": "bool" - } - ] - ], - "packet_multiplayer_settings": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "enable_multiplayer", - "1": "disable_multiplayer", - "2": "refresh_join_code" - } - } - ] - } - ] - ], - "packet_settings_command": [ - "container", - [ - { - "name": "command_line", - "type": "string" - }, - { - "name": "suppress_output", - "type": "bool" - } - ] - ], - "packet_anvil_damage": [ - "container", - [ - { - "name": "damage", - "type": "u8" - }, - { - "name": "position", - "type": "BlockCoordinates" - } - ] - ], - "packet_completed_using_item": [ - "container", - [ - { - "name": "used_item_id", - "type": "li16" - }, - { - "name": "use_method", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "equip_armor", - "1": "eat", - "2": "attack", - "3": "consume", - "4": "throw", - "5": "shoot", - "6": "place", - "7": "fill_bottle", - "8": "fill_bucket", - "9": "pour_bucket", - "10": "use_tool", - "11": "interact", - "12": "retrieved", - "13": "dyed", - "14": "traded" - } - } - ] - } - ] - ], - "packet_network_settings": [ - "container", - [ - { - "name": "compression_threshold", - "type": "u16" - } - ] - ], - "packet_player_auth_input": [ - "container", - [ - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "move_vector", - "type": "vec2f" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "input_data", - "type": "InputFlag" - }, - { - "name": "input_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "unknown", - "1": "mouse", - "2": "touch", - "3": "game_pad", - "4": "motion_controller" - } - } - ] - }, - { - "name": "play_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "teaser", - "2": "screen", - "3": "viewer", - "4": "reality", - "5": "placement", - "6": "living_room", - "7": "exit_level", - "8": "exit_level_living_room", - "9": "num_modes" - } - } - ] - }, - { - "name": "gaze_direction", - "type": [ - "switch", - { - "compareTo": "play_mode", - "fields": { - "reality": "vec3f" - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "transaction", - "type": [ - "switch", - { - "compareTo": "input_data.item_interact", - "fields": { - "true": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "data", - "type": "TransactionUseItem" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "item_stack_request", - "type": [ - "switch", - { - "compareTo": "input_data.item_stack_request", - "fields": { - "true": "ItemStackRequest" - }, - "default": "void" - } - ] - }, - { - "name": "block_action", - "type": [ - "switch", - { - "compareTo": "input_data.block_action", - "fields": { - "true": [ - "array", - { - "countType": "zigzag32", - "type": [ - "container", - [ - { - "name": "action", - "type": "Action" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "action", - "fields": { - "start_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "abort_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "crack_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "predict_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "continue_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_creative_content": [ - "container", - [ - { - "name": "items", - "type": "ItemStacks" - } - ] - ], - "packet_player_enchant_options": [ - "container", - [ - { - "name": "enchant_options", - "type": "EnchantOptions" - } - ] - ], - "packet_item_stack_request": [ - "container", - [ - { - "name": "requests", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemStackRequest" - } - ] - } - ] - ], - "packet_item_stack_response": [ - "container", - [ - { - "name": "responses", - "type": "ItemStackResponses" - } - ] - ], - "packet_player_armor_damage": [ - "container", - [ - { - "name": "type", - "type": "ArmorDamageType" - }, - { - "name": "helmet_damage", - "type": [ - "switch", - { - "compareTo": "type.head", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "chestplate_damage", - "type": [ - "switch", - { - "compareTo": "type.chest", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "leggings_damage", - "type": [ - "switch", - { - "compareTo": "type.legs", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "boots_damage", - "type": [ - "switch", - { - "compareTo": "type.feet", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - }, - { - "name": "player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_position_tracking_db_request": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "query" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - } - ] - ], - "packet_position_tracking_db_broadcast": [ - "container", - [ - { - "name": "broadcast_action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "update", - "1": "destory", - "2": "not_found" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_packet_violation_warning": [ - "container", - [ - { - "name": "violation_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "malformed" - } - } - ] - }, - { - "name": "severity", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "warning", - "1": "final_warning", - "2": "terminating" - } - } - ] - }, - { - "name": "packet_id", - "type": "zigzag32" - }, - { - "name": "reason", - "type": "string" - } - ] - ], - "packet_motion_prediction_hints": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - } - ] - ], - "packet_animate_entity": [ - "container", - [ - { - "name": "animation", - "type": "string" - }, - { - "name": "next_state", - "type": "string" - }, - { - "name": "stop_condition", - "type": "string" - }, - { - "name": "controller", - "type": "string" - }, - { - "name": "blend_out_time", - "type": "lf32" - }, - { - "name": "runtime_entity_ids", - "type": [ - "array", - { - "countType": "varint", - "type": "varint64" - } - ] - } - ] - ], - "packet_camera_shake": [ - "container", - [ - { - "name": "intensity", - "type": "lf32" - }, - { - "name": "duration", - "type": "lf32" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "stop" - } - } - ] - } - ] - ], - "packet_player_fog": [ - "container", - [ - { - "name": "stack", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_correct_player_move_prediction": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_item_component": [ - "container", - [ - { - "name": "entries", - "type": "ItemComponentList" - } - ] - ], - "packet_filter_text_packet": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "from_server", - "type": "bool" - } - ] - ], - "packet_debug_renderer": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "1": "clear", - "2": "add_cube" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "clear": "void", - "add_cube": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "red", - "type": "lf32" - }, - { - "name": "green", - "type": "lf32" - }, - { - "name": "blue", - "type": "lf32" - }, - { - "name": "alpha", - "type": "lf32" - }, - { - "name": "duration", - "type": "li64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "string": [ - "pstring", - { - "countType": "varint" - } - ], - "ByteArray": [ - "buffer", - { - "countType": "varint" - } - ], - "SignedByteArray": [ - "buffer", - { - "countType": "zigzag32" - } - ], - "LittleString": [ - "pstring", - { - "countType": "li32" - } - ], - "MetadataFlags1": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "onfire", - "sneaking", - "riding", - "sprinting", - "action", - "invisible", - "tempted", - "inlove", - "saddled", - "powered", - "ignited", - "baby", - "converting", - "critical", - "can_show_nametag", - "always_show_nametag", - "no_ai", - "silent", - "wallclimbing", - "can_climb", - "swimmer", - "can_fly", - "walker", - "resting", - "sitting", - "angry", - "interested", - "charged", - "tamed", - "orphaned", - "leashed", - "sheared", - "gliding", - "elder", - "moving", - "breathing", - "chested", - "stackable", - "showbase", - "rearing", - "vibrating", - "idling", - "evoker_spell", - "charge_attack", - "wasd_controlled", - "can_power_jump", - "linger", - "has_collision", - "affected_by_gravity", - "fire_immune", - "dancing", - "enchanted", - "show_trident_rope", - "container_private", - "transforming", - "spin_attack", - "swimming", - "bribed", - "pregnant", - "laying_egg", - "rider_can_pick", - "transition_sitting", - "eating", - "laying_down" - ] - } - ], - "MetadataFlags2": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "sneezing", - "trusting", - "rolling", - "scared", - "in_scaffolding", - "over_scaffolding", - "fall_through_scaffolding", - "blocking", - "transition_blocking", - "blocked_using_shield", - "blocked_using_damaged_shield", - "sleeping", - "wants_to_wake", - "trade_interest", - "door_breaker", - "breaking_obstruction", - "door_opener", - "illager_captain", - "stunned", - "roaring", - "delayed_attacking", - "avoiding_mobs", - "avoiding_block", - "facing_target_to_range_attack", - "hidden_when_invisible", - "is_in_ui", - "stalking", - "emoting", - "celebrating", - "admiring", - "celebrating_special" - ] - } - ], - "UpdateBlockFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "neighbors": 1, - "network": 2, - "no_graphic": 4, - "unused": 8, - "priority": 16 - } - } - ], - "AdventureFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "world_immutable": 1, - "no_pvp": 2, - "auto_jump": 32, - "allow_flight": 64, - "no_clip": 128, - "world_builder": 256, - "flying": 512, - "muted": 1024 - } - } - ], - "ActionPermissions": [ - "bitflags", - { - "type": "varint", - "flags": { - "mine": 65537, - "doors_and_switches": 65538, - "open_containers": 65540, - "attack_players": 65544, - "attack_mobs": 65552, - "operator": 65568, - "teleport": 65664, - "build": 65792, - "default": 66048 - } - } - ], - "CommandFlags": [ - "bitfield", - [ - { - "name": "unused", - "size": 6, - "signed": false - }, - { - "name": "has_semantic_constraint", - "size": 1, - "signed": false - }, - { - "name": "collapse_enum", - "size": 1, - "signed": false - } - ] - ], - "DeltaMoveFlags": [ - "bitflags", - { - "type": "lu16", - "flags": { - "has_x": 1, - "has_y": 2, - "has_z": 4, - "has_rot_x": 8, - "has_rot_y": 16, - "has_rot_z": 32, - "on_ground": 64, - "teleport": 128, - "force_move": 256 - } - } - ], - "InputFlag": [ - "bitflags", - { - "type": "varint64", - "big": true, - "flags": [ - "ascend", - "descend", - "north_jump", - "jump_down", - "sprint_down", - "change_height", - "jumping", - "auto_jumping_in_water", - "sneaking", - "sneak_down", - "up", - "down", - "left", - "right", - "up_left", - "up_right", - "want_up", - "want_down", - "want_down_slow", - "want_up_slow", - "sprinting", - "ascend_scaffolding", - "descend_scaffolding", - "sneak_toggle_down", - "persist_sneak", - "start_sprinting", - "stop_sprinting", - "start_sneaking", - "stop_sneaking", - "start_swimming", - "stop_swimming", - "start_jumping", - "start_gliding", - "stop_gliding", - "item_interact", - "block_action", - "item_stack_request" - ] - } - ], - "ArmorDamageType": [ - "bitflags", - { - "type": "u8", - "flags": { - "head": 1, - "chest": 2, - "legs": 4, - "feet": 8 - } - } - ] - } -} \ No newline at end of file diff --git a/data/1.16.220/protocol.json b/data/1.16.220/protocol.json deleted file mode 100644 index eaebb08..0000000 --- a/data/1.16.220/protocol.json +++ /dev/null @@ -1,8795 +0,0 @@ -{ - "types": { - "varint32": "varint", - "varint64": "native", - "zigzag32": "native", - "zigzag64": "native", - "uuid": "native", - "byterot": "native", - "bitflags": "native", - "restBuffer": "native", - "encapsulated": "native", - "nbt": "native", - "lnbt": "native", - "nbtLoop": "native", - "enum_size_based_on_values_len": "native", - "MapInfo": "native", - "BehaviourPackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - } - ] - ] - } - ], - "TexturePackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "rtx_enabled", - "type": "bool" - } - ] - ] - } - ], - "ResourcePackIdVersions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "ResourcePackIds": [ - "array", - { - "countType": "li16", - "type": "string" - } - ], - "Experiment": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "enabled", - "type": "bool" - } - ] - ], - "Experiments": [ - "array", - { - "countType": "li32", - "type": "Experiment" - } - ], - "GameMode": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "survival", - "1": "creative", - "2": "adventure", - "3": "survival_spectator", - "4": "creative_spectator", - "5": "fallback" - } - } - ], - "GameRule": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "bool", - "2": "int", - "3": "float" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "bool": "bool", - "int": "zigzag32", - "float": "lf32" - }, - "default": "void" - } - ] - } - ] - ], - "GameRules": [ - "array", - { - "countType": "varint", - "type": "GameRule" - } - ], - "Blob": [ - "container", - [ - { - "name": "hash", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "BlockProperties": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "state", - "type": "nbt" - } - ] - ] - } - ], - "Itemstates": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "runtime_id", - "type": "li16" - }, - { - "name": "component_based", - "type": "bool" - } - ] - ] - } - ], - "ItemExtraDataWithBlockingTick": [ - "container", - [ - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "lnbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "blocking_tick", - "type": "li64" - } - ] - ], - "ItemExtraDataWithoutBlockingTick": [ - "container", - [ - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "lnbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - } - ] - ], - "ItemLegacy": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "count", - "type": "lu16" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "block_runtime_id", - "type": "zigzag32" - }, - { - "name": "extra", - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "/ShieldItemID": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithBlockingTick" - } - ] - }, - "default": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithoutBlockingTick" - } - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "Item": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "count", - "type": "lu16" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "has_stack_id", - "type": "u8" - }, - { - "name": "stack_id", - "type": [ - "switch", - { - "compareTo": "has_stack_id", - "fields": { - "0": "void" - }, - "default": "zigzag32" - } - ] - }, - { - "name": "block_runtime_id", - "type": "zigzag32" - }, - { - "name": "extra", - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "/ShieldItemID": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithBlockingTick" - } - ] - }, - "default": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithoutBlockingTick" - } - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "vec3i": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "vec3u": [ - "container", - [ - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - } - ] - ], - "vec3f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vec2f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "MetadataDictionary": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "key", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "flags", - "1": "health", - "2": "variant", - "3": "color", - "4": "nametag", - "5": "owner_eid", - "6": "target_eid", - "7": "air", - "8": "potion_color", - "9": "potion_ambient", - "10": "jump_duration", - "11": "hurt_time", - "12": "hurt_direction", - "13": "paddle_time_left", - "14": "paddle_time_right", - "15": "experience_value", - "16": "minecart_display_block", - "17": "minecart_display_offset", - "18": "minecart_has_display", - "20": "old_swell", - "21": "swell_dir", - "22": "charge_amount", - "23": "enderman_held_runtime_id", - "24": "entity_age", - "26": "player_flags", - "27": "player_index", - "28": "player_bed_position", - "29": "fireball_power_x", - "30": "fireball_power_y", - "31": "fireball_power_z", - "32": "aux_power", - "33": "fish_x", - "34": "fish_z", - "35": "fish_angle", - "36": "potion_aux_value", - "37": "lead_holder_eid", - "38": "scale", - "39": "interactive_tag", - "40": "npc_skin_id", - "41": "url_tag", - "42": "max_airdata_max_air", - "43": "mark_variant", - "44": "container_type", - "45": "container_base_size", - "46": "container_extra_slots_per_strength", - "47": "block_target", - "48": "wither_invulnerable_ticks", - "49": "wither_target_1", - "50": "wither_target_2", - "51": "wither_target_3", - "52": "aerial_attack", - "53": "boundingbox_width", - "54": "boundingbox_height", - "55": "fuse_length", - "56": "rider_seat_position", - "57": "rider_rotation_locked", - "58": "rider_max_rotation", - "59": "rider_min_rotation", - "60": "rider_rotation_offset", - "61": "area_effect_cloud_radius", - "62": "area_effect_cloud_waiting", - "63": "area_effect_cloud_particle_id", - "64": "shulker_peek_id", - "65": "shulker_attach_face", - "66": "shulker_attached", - "67": "shulker_attach_pos", - "68": "trading_player_eid", - "69": "trading_career", - "70": "has_command_block", - "71": "command_block_command", - "72": "command_block_last_output", - "73": "command_block_track_output", - "74": "controlling_rider_seat_number", - "75": "strength", - "76": "max_strength", - "77": "spell_casting_color", - "78": "limited_life", - "79": "armor_stand_pose_index", - "80": "ender_crystal_time_offset", - "81": "always_show_nametag", - "82": "color_2", - "83": "name_author", - "84": "score_tag", - "85": "balloon_attached_entity", - "86": "pufferfish_size", - "87": "bubble_time", - "88": "agent", - "89": "sitting_amount", - "90": "sitting_amount_previous", - "91": "eating_counter", - "92": "flags_extended", - "93": "laying_amount", - "94": "laying_amount_previous", - "95": "duration", - "96": "spawn_time", - "97": "change_rate", - "98": "change_on_pickup", - "99": "pickup_count", - "100": "interact_text", - "101": "trade_tier", - "102": "max_trade_tier", - "103": "trade_experience", - "104": "skin_id", - "105": "spawning_frames", - "106": "command_block_tick_delay", - "107": "command_block_execute_on_first_tick", - "108": "ambient_sound_interval", - "109": "ambient_sound_interval_range", - "110": "ambient_sound_event_name", - "111": "fall_damage_multiplier", - "112": "name_raw_text", - "113": "can_ride_target", - "114": "low_tier_cured_discount", - "115": "high_tier_cured_discount", - "116": "nearby_cured_discount", - "117": "nearby_cured_discount_timestamp", - "118": "hitbox", - "119": "is_buoyant", - "120": "freezing_effect_strength", - "121": "buoyancy_data", - "122": "goat_horn_count", - "123": "base_runtime_id", - "124": "define_properties", - "125": "update_properties" - } - } - ] - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "byte", - "1": "short", - "2": "int", - "3": "float", - "4": "string", - "5": "compound", - "6": "vec3i", - "7": "long", - "8": "vec3f" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "key", - "fields": { - "flags": "MetadataFlags1", - "flags_extended": "MetadataFlags2" - }, - "default": [ - "switch", - { - "compareTo": "type", - "fields": { - "byte": "i8", - "short": "li16", - "int": "zigzag32", - "float": "lf32", - "string": "string", - "compound": "nbt", - "vec3i": "vec3i", - "long": "zigzag64", - "vec3f": "vec3f" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ], - "Link": [ - "container", - [ - { - "name": "ridden_entity_id", - "type": "zigzag64" - }, - { - "name": "rider_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "immediate", - "type": "bool" - }, - { - "name": "rider_initiated", - "type": "bool" - } - ] - ], - "Links": [ - "array", - { - "countType": "varint", - "type": "Link" - } - ], - "EntityAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "min", - "type": "lf32" - }, - { - "name": "value", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - } - ] - ] - } - ], - "Rotation": [ - "container", - [ - { - "name": "yaw", - "type": "byterot" - }, - { - "name": "pitch", - "type": "byterot" - }, - { - "name": "head_yaw", - "type": "byterot" - } - ] - ], - "BlockCoordinates": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "PlayerAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "min", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - }, - { - "name": "current", - "type": "lf32" - }, - { - "name": "default", - "type": "lf32" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "TransactionUseItem": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "click_block", - "1": "click_air", - "2": "break_block" - } - } - ] - }, - { - "name": "block_position", - "type": "vec3i" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "hotbar_slot", - "type": "varint" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - }, - { - "name": "block_runtime_id", - "type": "varint" - } - ] - ], - "TransactionActions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "container", - "1": "global", - "2": "world_interaction", - "3": "creative", - "100": "craft_slot", - "99999": "craft" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "container": [ - "container", - [ - { - "name": "inventory_id", - "type": "WindowIDVarint" - } - ] - ], - "craft": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "world_interaction": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "craft_slot": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - } - ] - ] - } - ], - "TransactionLegacy": [ - "container", - [ - { - "name": "legacy_request_id", - "type": "zigzag32" - }, - { - "name": "legacy_transactions", - "type": [ - "switch", - { - "compareTo": "legacy_request_id", - "fields": { - "0": "void" - }, - "default": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "changed_slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_id", - "type": "u8" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - } - ] - ], - "Transaction": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "transaction_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "inventory_mismatch", - "2": "item_use", - "3": "item_use_on_entity", - "4": "item_release" - } - } - ] - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "transaction_data", - "type": [ - "switch", - { - "compareTo": "transaction_type", - "fields": { - "normal": "void", - "inventory_mismatch": "void", - "item_use": "TransactionUseItem", - "item_use_on_entity": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "interact", - "1": "attack" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - } - ] - ], - "item_release": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "release", - "1": "consume" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "head_pos", - "type": "vec3f" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "ItemStacks": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ], - "RecipeIngredient": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "network_data", - "type": "zigzag32" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ], - "PotionTypeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "input_item_meta", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "ingredient_meta", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - }, - { - "name": "output_item_meta", - "type": "zigzag32" - } - ] - ] - } - ], - "PotionContainerChangeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - } - ] - ] - } - ], - "Recipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "shapeless", - "1": "shaped", - "2": "furnace", - "3": "furnace_with_metadata", - "4": "multi", - "5": "shulker_box", - "6": "shapeless_chemistry", - "7": "shaped_chemistry" - } - } - ] - }, - { - "name": "recipe", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "shapeless": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shulker_box": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shapeless_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "furnace": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "output", - "type": "ItemLegacy" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "furnace_with_metadata": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "input_meta", - "type": "zigzag32" - }, - { - "name": "output", - "type": "ItemLegacy" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "multi": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "SkinImage": [ - "container", - [ - { - "name": "width", - "type": "li32" - }, - { - "name": "height", - "type": "li32" - }, - { - "name": "data", - "type": "ByteArray" - } - ] - ], - "Skin": [ - "container", - [ - { - "name": "skin_id", - "type": "string" - }, - { - "name": "play_fab_id", - "type": "string" - }, - { - "name": "skin_resource_pack", - "type": "string" - }, - { - "name": "skin_data", - "type": "SkinImage" - }, - { - "name": "animations", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "skin_image", - "type": "SkinImage" - }, - { - "name": "animation_type", - "type": "li32" - }, - { - "name": "animation_frames", - "type": "lf32" - }, - { - "name": "expression_type", - "type": "lf32" - } - ] - ] - } - ] - }, - { - "name": "cape_data", - "type": "SkinImage" - }, - { - "name": "geometry_data", - "type": "string" - }, - { - "name": "animation_data", - "type": "string" - }, - { - "name": "premium", - "type": "bool" - }, - { - "name": "persona", - "type": "bool" - }, - { - "name": "cape_on_classic", - "type": "bool" - }, - { - "name": "cape_id", - "type": "string" - }, - { - "name": "full_skin_id", - "type": "string" - }, - { - "name": "arm_size", - "type": "string" - }, - { - "name": "skin_color", - "type": "string" - }, - { - "name": "personal_pieces", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_id", - "type": "string" - }, - { - "name": "piece_type", - "type": "string" - }, - { - "name": "pack_id", - "type": "string" - }, - { - "name": "is_default_piece", - "type": "bool" - }, - { - "name": "product_id", - "type": "string" - } - ] - ] - } - ] - }, - { - "name": "piece_tint_colors", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_type", - "type": "string" - }, - { - "name": "colors", - "type": [ - "array", - { - "countType": "li32", - "type": "string" - } - ] - } - ] - ] - } - ] - } - ] - ], - "PlayerRecords": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "remove" - } - } - ] - }, - { - "name": "records_count", - "type": "varint" - }, - { - "name": "records", - "type": [ - "array", - { - "count": "records_count", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "xbox_user_id", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "build_platform", - "type": "li32" - }, - { - "name": "skin_data", - "type": "Skin" - }, - { - "name": "is_teacher", - "type": "bool" - }, - { - "name": "is_host", - "type": "bool" - } - ] - ], - "remove": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - }, - { - "name": "verified", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "array", - { - "count": "records_count", - "type": "bool" - } - ] - }, - "default": "void" - } - ] - } - ] - ], - "Enchant": [ - "container", - [ - { - "name": "id", - "type": "u8" - }, - { - "name": "level", - "type": "u8" - } - ] - ], - "EnchantOption": [ - "container", - [ - { - "name": "cost", - "type": "varint" - }, - { - "name": "slot_flags", - "type": "li32" - }, - { - "name": "equip_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "held_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "self_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "name", - "type": "string" - }, - { - "name": "option_id", - "type": "zigzag32" - } - ] - ], - "Action": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "start_break", - "1": "abort_break", - "2": "stop_break", - "3": "get_updated_block", - "4": "drop_item", - "5": "start_sleeping", - "6": "stop_sleeping", - "7": "respawn", - "8": "jump", - "9": "start_sprint", - "10": "stop_sprint", - "11": "start_sneak", - "12": "stop_sneak", - "13": "creative_player_destroy_block", - "14": "dimension_change_ack", - "15": "start_glide", - "16": "stop_glide", - "17": "build_denied", - "18": "crack_break", - "19": "change_skin", - "20": "set_enchatnment_seed", - "21": "swimming", - "22": "stop_swimming", - "23": "start_spin_attack", - "24": "stop_spin_attack", - "25": "interact_block", - "26": "predict_break", - "27": "continue_break" - } - } - ], - "StackRequestSlotInfo": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "stack_id", - "type": "zigzag32" - } - ] - ], - "ItemStackRequest": [ - "container", - [ - { - "name": "request_id", - "type": "varint" - }, - { - "name": "actions", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "take", - "1": "place", - "2": "swap", - "3": "drop", - "4": "destroy", - "5": "consume", - "6": "create", - "7": "lab_table_combine", - "8": "beacon_payment", - "9": "mine_block", - "10": "craft_recipe", - "11": "craft_recipe_auto", - "12": "craft_creative", - "13": "optional", - "14": "non_implemented", - "15": "results_deprecated" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type_id", - "fields": { - "take": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "place": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "swap": [ - "container", - [ - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "drop": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "randomly", - "type": "bool" - } - ] - ], - "destroy": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "consume": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "create": [ - "container", - [ - { - "name": "result_slot_id", - "type": "u8" - } - ] - ], - "beacon_payment": [ - "container", - [ - { - "name": "primary_effect", - "type": "zigzag32" - }, - { - "name": "secondary_effect", - "type": "zigzag32" - } - ] - ], - "mine_block": [ - "container", - [ - { - "name": "unknown1", - "type": "zigzag32" - }, - { - "name": "predicted_durability", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "craft_recipe": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_recipe_auto": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_creative": [ - "container", - [ - { - "name": "item_id", - "type": "varint32" - } - ] - ], - "optional": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - }, - { - "name": "filtered_string_index", - "type": "li32" - } - ] - ], - "non_implemented": "void", - "results_deprecated": [ - "container", - [ - { - "name": "result_items", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "times_crafted", - "type": "u8" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - { - "name": "custom_names", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "ItemStackResponses": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "ok", - "1": "error" - } - } - ] - }, - { - "name": "request_id", - "type": "varint32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "status", - "fields": { - "ok": [ - "container", - [ - { - "name": "containers", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot", - "type": "u8" - }, - { - "name": "hotbar_slot", - "type": "u8" - }, - { - "name": "count", - "type": "u8" - }, - { - "name": "item_stack_id", - "type": "varint32" - }, - { - "name": "custom_name", - "type": "string" - }, - { - "name": "durability_correction", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "ItemComponentList": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ] - } - ], - "CommandOrigin": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "player", - "1": "block", - "2": "minecart_block", - "3": "dev_console", - "4": "test", - "5": "automation_player", - "6": "client_automation", - "7": "dedicated_server", - "8": "entity", - "9": "virtual", - "10": "game_argument", - "11": "entity_server", - "12": "precompiled", - "13": "game_director_entity_server", - "14": "script" - } - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "player_entity_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "dev_console": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ], - "test": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "TrackedObject": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "entity", - "1": "block" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "block_position", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "block": "BlockCoordinates" - }, - "default": "void" - } - ] - } - ] - ], - "MapDecoration": [ - "container", - [ - { - "name": "type", - "type": "u8" - }, - { - "name": "rotation", - "type": "u8" - }, - { - "name": "x", - "type": "u8" - }, - { - "name": "y", - "type": "u8" - }, - { - "name": "label", - "type": "string" - }, - { - "name": "color_abgr", - "type": "varint" - } - ] - ], - "StructureBlockSettings": [ - "container", - [ - { - "name": "palette_name", - "type": "string" - }, - { - "name": "ignore_entities", - "type": "bool" - }, - { - "name": "ignore_blocks", - "type": "bool" - }, - { - "name": "size", - "type": "BlockCoordinates" - }, - { - "name": "structure_offset", - "type": "BlockCoordinates" - }, - { - "name": "last_editing_player_unique_id", - "type": "zigzag64" - }, - { - "name": "rotation", - "type": "u8" - }, - { - "name": "mirror", - "type": "u8" - }, - { - "name": "integrity", - "type": "lf32" - }, - { - "name": "seed", - "type": "lu32" - }, - { - "name": "pivot", - "type": "vec3f" - } - ] - ], - "WindowID": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowIDVarint": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowType": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "container", - "1": "workbench", - "2": "furnace", - "3": "enchantment", - "4": "brewing_stand", - "5": "anvil", - "6": "dispenser", - "7": "dropper", - "8": "hopper", - "9": "cauldron", - "10": "minecart_chest", - "11": "minecart_hopper", - "12": "horse", - "13": "beacon", - "14": "structure_editor", - "15": "trading", - "16": "command_block", - "17": "jukebox", - "18": "armor", - "19": "hand", - "20": "compound_creator", - "21": "element_constructor", - "22": "material_reducer", - "23": "lab_table", - "24": "loom", - "25": "lectern", - "26": "grindstone", - "27": "blast_furnace", - "28": "smoker", - "29": "stonecutter", - "30": "cartography", - "31": "hud", - "32": "jigsaw_editor", - "33": "smithing_table", - "-9": "none", - "-1": "inventory" - } - } - ], - "ContainerSlotType": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "anvil_input", - "1": "anvil_material", - "2": "anvil_result", - "3": "smithing_table_input", - "4": "smithing_table_material", - "5": "smithing_table_result", - "6": "armor", - "7": "container", - "8": "beacon_payment", - "9": "brewing_input", - "10": "brewing_result", - "11": "brewing_fuel", - "12": "hotbar_and_inventory", - "13": "crafting_input", - "14": "crafting_output", - "15": "recipe_construction", - "16": "recipe_nature", - "17": "recipe_items", - "18": "recipe_search", - "19": "recipe_search_bar", - "20": "recipe_equipment", - "21": "enchanting_input", - "22": "enchanting_lapis", - "23": "furnace_fuel", - "24": "furnace_ingredient", - "25": "furnace_output", - "26": "horse_equip", - "27": "hotbar", - "28": "inventory", - "29": "shulker", - "30": "trade_ingredient1", - "31": "trade_ingredient2", - "32": "trade_result", - "33": "offhand", - "34": "compcreate_input", - "35": "compcreate_output", - "36": "elemconstruct_output", - "37": "matreduce_input", - "38": "matreduce_output", - "39": "labtable_input", - "40": "loom_input", - "41": "loom_dye", - "42": "loom_material", - "43": "loom_result", - "44": "blast_furnace_ingredient", - "45": "smoker_ingredient", - "46": "trade2_ingredient1", - "47": "trade2_ingredient2", - "48": "trade2_result", - "49": "grindstone_input", - "50": "grindstone_additional", - "51": "grindstone_result", - "52": "stonecutter_input", - "53": "stonecutter_result", - "54": "cartography_input", - "55": "cartography_additional", - "56": "cartography_result", - "57": "barrel", - "58": "cursor", - "59": "creative_output" - } - } - ], - "SoundType": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "ItemUseOn", - "1": "Hit", - "2": "Step", - "3": "Fly", - "4": "Jump", - "5": "Break", - "6": "Place", - "7": "HeavyStep", - "8": "Gallop", - "9": "Fall", - "10": "Ambient", - "11": "AmbientBaby", - "12": "AmbientInWater", - "13": "Breathe", - "14": "Death", - "15": "DeathInWater", - "16": "DeathToZombie", - "17": "Hurt", - "18": "HurtInWater", - "19": "Mad", - "20": "Boost", - "21": "Bow", - "22": "SquishBig", - "23": "SquishSmall", - "24": "FallBig", - "25": "FallSmall", - "26": "Splash", - "27": "Fizz", - "28": "Flap", - "29": "Swim", - "30": "Drink", - "31": "Eat", - "32": "Takeoff", - "33": "Shake", - "34": "Plop", - "35": "Land", - "36": "Saddle", - "37": "Armor", - "38": "MobArmorStandPlace", - "39": "AddChest", - "40": "Throw", - "41": "Attack", - "42": "AttackNoDamage", - "43": "AttackStrong", - "44": "Warn", - "45": "Shear", - "46": "Milk", - "47": "Thunder", - "48": "Explode", - "49": "Fire", - "50": "Ignite", - "51": "Fuse", - "52": "Stare", - "53": "Spawn", - "54": "Shoot", - "55": "BreakBlock", - "56": "Launch", - "57": "Blast", - "58": "LargeBlast", - "59": "Twinkle", - "60": "Remedy", - "61": "Infect", - "62": "LevelUp", - "63": "BowHit", - "64": "BulletHit", - "65": "ExtinguishFire", - "66": "ItemFizz", - "67": "ChestOpen", - "68": "ChestClosed", - "69": "ShulkerBoxOpen", - "70": "ShulkerBoxClosed", - "71": "EnderChestOpen", - "72": "EnderChestClosed", - "73": "PowerOn", - "74": "PowerOff", - "75": "Attach", - "76": "Detach", - "77": "Deny", - "78": "Tripod", - "79": "Pop", - "80": "DropSlot", - "81": "Note", - "82": "Thorns", - "83": "PistonIn", - "84": "PistonOut", - "85": "Portal", - "86": "Water", - "87": "LavaPop", - "88": "Lava", - "89": "Burp", - "90": "BucketFillWater", - "91": "BucketFillLava", - "92": "BucketEmptyWater", - "93": "BucketEmptyLava", - "94": "ArmorEquipChain", - "95": "ArmorEquipDiamond", - "96": "ArmorEquipGeneric", - "97": "ArmorEquipGold", - "98": "ArmorEquipIron", - "99": "ArmorEquipLeather", - "100": "ArmorEquipElytra", - "101": "Record13", - "102": "RecordCat", - "103": "RecordBlocks", - "104": "RecordChirp", - "105": "RecordFar", - "106": "RecordMall", - "107": "RecordMellohi", - "108": "RecordStal", - "109": "RecordStrad", - "110": "RecordWard", - "111": "Record11", - "112": "RecordWait", - "113": "unknown1", - "114": "Flop", - "115": "ElderGuardianCurse", - "116": "MobWarning", - "117": "MobWarningBaby", - "118": "Teleport", - "119": "ShulkerOpen", - "120": "ShulkerClose", - "121": "Haggle", - "122": "HaggleYes", - "123": "HaggleNo", - "124": "HaggleIdle", - "125": "ChorusGrow", - "126": "ChorusDeath", - "127": "Glass", - "128": "PotionBrewed", - "129": "CastSpell", - "130": "PrepareAttack", - "131": "PrepareSummon", - "132": "PrepareWololo", - "133": "Fang", - "134": "Charge", - "135": "CameraTakePicture", - "136": "LeashKnotPlace", - "137": "LeashKnotBreak", - "138": "Growl", - "139": "Whine", - "140": "Pant", - "141": "Purr", - "142": "Purreow", - "143": "DeathMinVolume", - "144": "DeathMidVolume", - "145": "unknown2", - "146": "ImitateCaveSpider", - "147": "ImitateCreeper", - "148": "ImitateElderGuardian", - "149": "ImitateEnderDragon", - "150": "ImitateEnderman", - "151": "unknown3", - "152": "ImitateEvocationIllager", - "153": "ImitateGhast", - "154": "ImitateHusk", - "155": "ImitateIllusionIllager", - "156": "ImitateMagmaCube", - "157": "ImitatePolarBear", - "158": "ImitateShulker", - "159": "ImitateSilverfish", - "160": "ImitateSkeleton", - "161": "ImitateSlime", - "162": "ImitateSpider", - "163": "ImitateStray", - "164": "ImitateVex", - "165": "ImitateVindicationIllager", - "166": "ImitateWitch", - "167": "ImitateWither", - "168": "ImitateWitherSkeleton", - "169": "ImitateWolf", - "170": "ImitateZombie", - "171": "ImitateZombiePigman", - "172": "ImitateZombieVillager", - "173": "BlockEndPortalFrameFill", - "174": "BlockEndPortalSpawn", - "175": "RandomAnvilUse", - "176": "BottleDragonBreath", - "177": "PortalTravel", - "178": "ItemTridentHit", - "179": "ItemTridentReturn", - "180": "ItemTridentRiptide1", - "181": "ItemTridentRiptide2", - "182": "ItemTridentRiptide3", - "183": "ItemTridentThrow", - "184": "ItemTridentThunder", - "185": "ItemTridentHitGround", - "186": "Default", - "187": "BlockFletchingTableUse", - "188": "ElemConstructOpen", - "189": "IceBombHit", - "190": "BalloonPop", - "191": "LtReactionIceBomb", - "192": "LtReactionBleach", - "193": "LtReactionEPaste", - "194": "LtReactionEPaste2", - "195": "LtReactionFertilizer", - "196": "LtReactionFireball", - "197": "LtReactionMgsalt", - "198": "LtReactionMiscfire", - "199": "LtReactionFire", - "200": "LtReactionMiscexplosion", - "201": "LtReactionMiscmystical", - "202": "LtReactionMiscmystical2", - "203": "LtReactionProduct", - "204": "SparklerUse", - "205": "GlowstickUse", - "206": "SparklerActive", - "207": "ConvertToDrowned", - "208": "BucketFillFish", - "209": "BucketEmptyFish", - "210": "BubbleUp", - "211": "BubbleDown", - "212": "BubblePop", - "213": "BubbleUpInside", - "214": "BubbleDownInside", - "215": "HurtBaby", - "216": "DeathBaby", - "217": "StepBaby", - "218": "BabySpawn", - "219": "Born", - "220": "BlockTurtleEggBreak", - "221": "BlockTurtleEggCrack", - "222": "BlockTurtleEggHatch", - "223": "TurtleLayEgg", - "224": "BlockTurtleEggAttack", - "225": "BeaconActivate", - "226": "BeaconAmbient", - "227": "BeaconDeactivate", - "228": "BeaconPower", - "229": "ConduitActivate", - "230": "ConduitAmbient", - "231": "ConduitAttack", - "232": "ConduitDeactivate", - "233": "ConduitShort", - "234": "Swoop", - "235": "BlockBambooSaplingPlace", - "236": "PreSneeze", - "237": "Sneeze", - "238": "AmbientTame", - "239": "Scared", - "240": "BlockScaffoldingClimb", - "241": "CrossbowLoadingStart", - "242": "CrossbowLoadingMiddle", - "243": "CrossbowLoadingEnd", - "244": "CrossbowShoot", - "245": "CrossbowQuickChargeStart", - "246": "CrossbowQuickChargeMiddle", - "247": "CrossbowQuickChargeEnd", - "248": "AmbientAggressive", - "249": "AmbientWorried", - "250": "CantBreed", - "251": "ItemShieldBlock", - "252": "ItemBookPut", - "253": "BlockGrindstoneUse", - "254": "BlockBellHit", - "255": "BlockCampfireCrackle", - "256": "Roar", - "257": "Stun", - "258": "BlockSweetBerryBushHurt", - "259": "BlockSweetBerryBushPick", - "260": "UICartographyTableTakeResult", - "261": "UIStoneCutterTakeResult", - "262": "BlockComposterEmpty", - "263": "BlockComposterFill", - "264": "BlockComposterFillSuccess", - "265": "BlockComposterReady", - "266": "BlockBarrelOpen", - "267": "BlockBarrelClose", - "268": "RaidHorn", - "269": "BlockLoomUse", - "270": "AmbientRaid", - "271": "UICartographyTableUse", - "272": "UIStoneCutterUse", - "273": "UILoomUse", - "274": "SmokerUse", - "275": "BlastFurnaceUse", - "276": "SmithingTableUse", - "277": "Screech", - "278": "Sleep", - "279": "FurnaceUse", - "280": "MooshroomConvert", - "281": "MilkSuspiciously", - "282": "Celebrate", - "283": "JumpPrevent", - "284": "AmbientPollinate", - "285": "BeeHiveDrip", - "286": "BeeHiveEnter", - "287": "BeeHiveExit", - "288": "BeeHiveWork", - "289": "BeeHiveShear", - "290": "HoneyBottleDrink", - "291": "AmbientCave", - "292": "Retreat", - "293": "ConvertToZombified", - "294": "Admire", - "295": "StepLava", - "296": "Tempt", - "297": "Panic", - "298": "Angry", - "299": "AmbientWarpedForest", - "300": "AmbientSoulsandValley", - "301": "AmbientNetherWastes", - "302": "AmbientBasaltDeltas", - "303": "AmbientCrimsonForest", - "304": "RespawnAnchorCharge", - "305": "RespawnAnchorDeplete", - "306": "RespawnAnchorSetSpawn", - "307": "RespawnAnchorAmbient", - "308": "SoulEscapeQuiet", - "309": "SoulEscapeLoud", - "310": "RecordPigstep", - "311": "LinkCompassToLodestone", - "312": "BlockSmithingTableUse", - "313": "EquipNetherite", - "314": "AmbientLoopWarpedForest", - "315": "AmbientLoopSoulsandValley", - "316": "AmbientLoopNetherWastes", - "317": "AmbientLoopBasaltDeltas", - "318": "AmbientLoopCrimsonForest", - "319": "AmbientAdditionWarpedForest", - "320": "AmbientAdditionSoulsandValley", - "321": "AmbientAdditionNetherWastes", - "322": "AmbientAdditionBasaltDeltas", - "323": "AmbientAdditionCrimsonForest", - "324": "SculkSensorPowerOn", - "325": "SculkSensorPowerOff", - "326": "BucketFillPowderSnow", - "327": "BucketEmptyPowderSnow", - "328": "PointedDripstoneCauldronDripWater", - "329": "PointedDripstoneCauldronDripLava", - "330": "PointedDripstoneDripWater", - "331": "PointedDripstoneDripLava", - "332": "CaveVinesPickBerries", - "333": "BigDripleafTiltDown", - "334": "BigDripleafTiltUp", - "335": "Undefined" - } - } - ], - "LegacyEntityType": [ - "mapper", - { - "type": "li32", - "mappings": { - "10": "chicken", - "11": "cow", - "12": "pig", - "13": "sheep", - "14": "wolf", - "15": "villager", - "16": "mooshroom", - "17": "squid", - "18": "rabbit", - "19": "bat", - "20": "iron_golem", - "21": "snow_golem", - "22": "ocelot", - "23": "horse", - "24": "donkey", - "25": "mule", - "26": "skeleton_horse", - "27": "zombie_horse", - "28": "polar_bear", - "29": "llama", - "30": "parrot", - "31": "dolphin", - "32": "zombie", - "33": "creeper", - "34": "skeleton", - "35": "spider", - "36": "zombie_pigman", - "37": "slime", - "38": "enderman", - "39": "silverfish", - "40": "cave_spider", - "41": "ghast", - "42": "magma_cube", - "43": "blaze", - "44": "zombie_villager", - "45": "witch", - "46": "stray", - "47": "husk", - "48": "wither_skeleton", - "49": "guardian", - "50": "elder_guardian", - "51": "npc", - "52": "wither", - "53": "ender_dragon", - "54": "shulker", - "55": "endermite", - "56": "agent", - "57": "vindicator", - "58": "phantom", - "61": "armor_stand", - "62": "tripod_camera", - "63": "player", - "64": "item", - "65": "tnt", - "66": "falling_block", - "67": "moving_block", - "68": "xp_bottle", - "69": "xp_orb", - "70": "eye_of_ender_signal", - "71": "ender_crystal", - "72": "fireworks_rocket", - "73": "thrown_trident", - "74": "turtle", - "75": "cat", - "76": "shulker_bullet", - "77": "fishing_hook", - "78": "chalkboard", - "79": "dragon_fireball", - "80": "arrow", - "81": "snowball", - "82": "egg", - "83": "painting", - "84": "minecart", - "85": "fireball", - "86": "splash_potion", - "87": "ender_pearl", - "88": "leash_knot", - "89": "wither_skull", - "90": "boat", - "91": "wither_skull_dangerous", - "93": "lightning_bolt", - "94": "small_fireball", - "95": "area_effect_cloud", - "96": "hopper_minecart", - "97": "tnt_minecart", - "98": "chest_minecart", - "100": "command_block_minecart", - "101": "lingering_potion", - "102": "llama_spit", - "103": "evocation_fang", - "104": "evocation_illager", - "105": "vex", - "106": "ice_bomb", - "107": "balloon", - "108": "pufferfish", - "109": "salmon", - "110": "drowned", - "111": "tropicalfish", - "112": "cod", - "113": "panda" - } - } - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "login", - "2": "play_status", - "3": "server_to_client_handshake", - "4": "client_to_server_handshake", - "5": "disconnect", - "6": "resource_packs_info", - "7": "resource_pack_stack", - "8": "resource_pack_client_response", - "9": "text", - "10": "set_time", - "11": "start_game", - "12": "add_player", - "13": "add_entity", - "14": "remove_entity", - "15": "add_item_entity", - "17": "take_item_entity", - "18": "move_entity", - "19": "move_player", - "20": "rider_jump", - "21": "update_block", - "22": "add_painting", - "23": "tick_sync", - "24": "level_sound_event_old", - "25": "level_event", - "26": "block_event", - "27": "entity_event", - "28": "mob_effect", - "29": "update_attributes", - "30": "inventory_transaction", - "31": "mob_equipment", - "32": "mob_armor_equipment", - "33": "interact", - "34": "block_pick_request", - "35": "entity_pick_request", - "36": "player_action", - "38": "hurt_armor", - "39": "set_entity_data", - "40": "set_entity_motion", - "41": "set_entity_link", - "42": "set_health", - "43": "set_spawn_position", - "44": "animate", - "45": "respawn", - "46": "container_open", - "47": "container_close", - "48": "player_hotbar", - "49": "inventory_content", - "50": "inventory_slot", - "51": "container_set_data", - "52": "crafting_data", - "53": "crafting_event", - "54": "gui_data_pick_item", - "55": "adventure_settings", - "56": "block_entity_data", - "57": "player_input", - "58": "level_chunk", - "59": "set_commands_enabled", - "60": "set_difficulty", - "61": "change_dimension", - "62": "set_player_game_type", - "63": "player_list", - "64": "simple_event", - "65": "event", - "66": "spawn_experience_orb", - "67": "clientbound_map_item_data", - "68": "map_info_request", - "69": "request_chunk_radius", - "70": "chunk_radius_update", - "71": "item_frame_drop_item", - "72": "game_rules_changed", - "73": "camera", - "74": "boss_event", - "75": "show_credits", - "76": "available_commands", - "77": "command_request", - "78": "command_block_update", - "79": "command_output", - "80": "update_trade", - "81": "update_equipment", - "82": "resource_pack_data_info", - "83": "resource_pack_chunk_data", - "84": "resource_pack_chunk_request", - "85": "transfer", - "86": "play_sound", - "87": "stop_sound", - "88": "set_title", - "89": "add_behavior_tree", - "90": "structure_block_update", - "91": "show_store_offer", - "92": "purchase_receipt", - "93": "player_skin", - "94": "sub_client_login", - "95": "initiate_web_socket_connection", - "96": "set_last_hurt_by", - "97": "book_edit", - "98": "npc_request", - "99": "photo_transfer", - "100": "modal_form_request", - "101": "modal_form_response", - "102": "server_settings_request", - "103": "server_settings_response", - "104": "show_profile", - "105": "set_default_game_type", - "106": "remove_objective", - "107": "set_display_objective", - "108": "set_score", - "109": "lab_table", - "110": "update_block_synced", - "111": "move_entity_delta", - "112": "set_scoreboard_identity", - "113": "set_local_player_as_initialized", - "114": "update_soft_enum", - "115": "network_stack_latency", - "117": "script_custom_event", - "118": "spawn_particle_effect", - "119": "available_entity_identifiers", - "120": "level_sound_event_v2", - "121": "network_chunk_publisher_update", - "122": "biome_definition_list", - "123": "level_sound_event", - "124": "level_event_generic", - "125": "lectern_update", - "126": "video_stream_connect", - "127": "add_ecs_entity", - "128": "remove_ecs_entity", - "129": "client_cache_status", - "130": "on_screen_texture_animation", - "131": "map_create_locked_copy", - "132": "structure_template_data_export_request", - "133": "structure_template_data_export_response", - "134": "update_block_properties", - "135": "client_cache_blob_status", - "136": "client_cache_miss_response", - "137": "education_settings", - "139": "multiplayer_settings", - "140": "settings_command", - "141": "anvil_damage", - "142": "completed_using_item", - "143": "network_settings", - "144": "player_auth_input", - "145": "creative_content", - "146": "player_enchant_options", - "147": "item_stack_request", - "148": "item_stack_response", - "149": "player_armor_damage", - "151": "update_player_game_type", - "153": "position_tracking_db_broadcast", - "154": "position_tracking_db_request", - "156": "packet_violation_warning", - "157": "motion_prediction_hints", - "158": "animate_entity", - "159": "camera_shake", - "160": "player_fog", - "161": "correct_player_move_prediction", - "162": "item_component", - "163": "filter_text_packet", - "164": "debug_renderer" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "login": "packet_login", - "play_status": "packet_play_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "tick_sync": "packet_tick_sync", - "level_sound_event_old": "packet_level_sound_event_old", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "inventory_transaction": "packet_inventory_transaction", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "block_pick_request": "packet_block_pick_request", - "entity_pick_request": "packet_entity_pick_request", - "player_action": "packet_player_action", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "player_hotbar": "packet_player_hotbar", - "inventory_content": "packet_inventory_content", - "inventory_slot": "packet_inventory_slot", - "container_set_data": "packet_container_set_data", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "gui_data_pick_item": "packet_gui_data_pick_item", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "level_chunk": "packet_level_chunk", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "simple_event": "packet_simple_event", - "event": "packet_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data": "packet_clientbound_map_item_data", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_frame_drop_item": "packet_item_frame_drop_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "boss_event": "packet_boss_event", - "show_credits": "packet_show_credits", - "available_commands": "packet_available_commands", - "command_request": "packet_command_request", - "command_block_update": "packet_command_block_update", - "command_output": "packet_command_output", - "update_trade": "packet_update_trade", - "update_equipment": "packet_update_equipment", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request", - "transfer": "packet_transfer", - "play_sound": "packet_play_sound", - "stop_sound": "packet_stop_sound", - "set_title": "packet_set_title", - "add_behavior_tree": "packet_add_behavior_tree", - "structure_block_update": "packet_structure_block_update", - "show_store_offer": "packet_show_store_offer", - "purchase_receipt": "packet_purchase_receipt", - "player_skin": "packet_player_skin", - "sub_client_login": "packet_sub_client_login", - "initiate_web_socket_connection": "packet_initiate_web_socket_connection", - "set_last_hurt_by": "packet_set_last_hurt_by", - "book_edit": "packet_book_edit", - "npc_request": "packet_npc_request", - "photo_transfer": "packet_photo_transfer", - "modal_form_request": "packet_modal_form_request", - "modal_form_response": "packet_modal_form_response", - "server_settings_request": "packet_server_settings_request", - "server_settings_response": "packet_server_settings_response", - "show_profile": "packet_show_profile", - "set_default_game_type": "packet_set_default_game_type", - "remove_objective": "packet_remove_objective", - "set_display_objective": "packet_set_display_objective", - "set_score": "packet_set_score", - "lab_table": "packet_lab_table", - "update_block_synced": "packet_update_block_synced", - "move_entity_delta": "packet_move_entity_delta", - "set_scoreboard_identity": "packet_set_scoreboard_identity", - "set_local_player_as_initialized": "packet_set_local_player_as_initialized", - "update_soft_enum": "packet_update_soft_enum", - "network_stack_latency": "packet_network_stack_latency", - "script_custom_event": "packet_script_custom_event", - "spawn_particle_effect": "packet_spawn_particle_effect", - "available_entity_identifiers": "packet_available_entity_identifiers", - "level_sound_event_v2": "packet_level_sound_event_v2", - "network_chunk_publisher_update": "packet_network_chunk_publisher_update", - "biome_definition_list": "packet_biome_definition_list", - "level_sound_event": "packet_level_sound_event", - "level_event_generic": "packet_level_event_generic", - "lectern_update": "packet_lectern_update", - "video_stream_connect": "packet_video_stream_connect", - "add_ecs_entity": "packet_add_ecs_entity", - "remove_ecs_entity": "packet_remove_ecs_entity", - "client_cache_status": "packet_client_cache_status", - "on_screen_texture_animation": "packet_on_screen_texture_animation", - "map_create_locked_copy": "packet_map_create_locked_copy", - "structure_template_data_export_request": "packet_structure_template_data_export_request", - "structure_template_data_export_response": "packet_structure_template_data_export_response", - "update_block_properties": "packet_update_block_properties", - "client_cache_blob_status": "packet_client_cache_blob_status", - "client_cache_miss_response": "packet_client_cache_miss_response", - "education_settings": "packet_education_settings", - "multiplayer_settings": "packet_multiplayer_settings", - "settings_command": "packet_settings_command", - "anvil_damage": "packet_anvil_damage", - "completed_using_item": "packet_completed_using_item", - "network_settings": "packet_network_settings", - "player_auth_input": "packet_player_auth_input", - "creative_content": "packet_creative_content", - "player_enchant_options": "packet_player_enchant_options", - "item_stack_request": "packet_item_stack_request", - "item_stack_response": "packet_item_stack_response", - "player_armor_damage": "packet_player_armor_damage", - "update_player_game_type": "packet_update_player_game_type", - "position_tracking_db_request": "packet_position_tracking_db_request", - "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", - "packet_violation_warning": "packet_packet_violation_warning", - "motion_prediction_hints": "packet_motion_prediction_hints", - "animate_entity": "packet_animate_entity", - "camera_shake": "packet_camera_shake", - "player_fog": "packet_player_fog", - "correct_player_move_prediction": "packet_correct_player_move_prediction", - "item_component": "packet_item_component", - "filter_text_packet": "packet_filter_text_packet", - "debug_renderer": "packet_debug_renderer" - }, - "default": "void" - } - ] - } - ] - ], - "packet_login": [ - "container", - [ - { - "name": "protocol_version", - "type": "i32" - }, - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "LoginTokens": [ - "container", - [ - { - "name": "identity", - "type": "LittleString" - }, - { - "name": "client", - "type": "LittleString" - } - ] - ], - "packet_play_status": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "i32", - "mappings": { - "0": "login_success", - "1": "failed_client", - "2": "failed_spawn", - "3": "player_spawn", - "4": "failed_invalid_tenant", - "5": "failed_vanilla_edu", - "6": "failed_edu_vanilla", - "7": "failed_server_full" - } - } - ] - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "token", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "behaviour_packs", - "type": "BehaviourPackInfos" - }, - { - "name": "texture_packs", - "type": "TexturePackInfos" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behavior_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "resource_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "refused", - "2": "send_packs", - "3": "have_all_packs", - "4": "completed" - } - } - ] - }, - { - "name": "resourcepackids", - "type": "ResourcePackIds" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "raw", - "1": "chat", - "2": "translation", - "3": "popup", - "4": "jukebox_popup", - "5": "tip", - "6": "system", - "7": "whisper", - "8": "announcement", - "9": "json_whisper", - "10": "json" - } - } - ] - }, - { - "name": "needs_translation", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "chat": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "whisper": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "announcement": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "raw": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "tip": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "system": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json_whisper": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "translation": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "jukebox_popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "xuid", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "zigzag32" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "player_gamemode", - "type": "GameMode" - }, - { - "name": "player_position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "vec2f" - }, - { - "name": "seed", - "type": "zigzag32" - }, - { - "name": "biome_type", - "type": "li16" - }, - { - "name": "biome_name", - "type": "string" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "generator", - "type": "zigzag32" - }, - { - "name": "world_gamemode", - "type": "GameMode" - }, - { - "name": "difficulty", - "type": "zigzag32" - }, - { - "name": "spawn_position", - "type": "BlockCoordinates" - }, - { - "name": "achievements_disabled", - "type": "bool" - }, - { - "name": "day_cycle_stop_time", - "type": "zigzag32" - }, - { - "name": "edu_offer", - "type": "zigzag32" - }, - { - "name": "edu_features_enabled", - "type": "bool" - }, - { - "name": "edu_product_uuid", - "type": "string" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightning_level", - "type": "lf32" - }, - { - "name": "has_confirmed_platform_locked_content", - "type": "bool" - }, - { - "name": "is_multiplayer", - "type": "bool" - }, - { - "name": "broadcast_to_lan", - "type": "bool" - }, - { - "name": "xbox_live_broadcast_mode", - "type": "varint" - }, - { - "name": "platform_broadcast_mode", - "type": "varint" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - { - "name": "gamerules", - "type": "GameRules" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - }, - { - "name": "bonus_chest", - "type": "bool" - }, - { - "name": "map_enabled", - "type": "bool" - }, - { - "name": "permission_level", - "type": "zigzag32" - }, - { - "name": "server_chunk_tick_range", - "type": "li32" - }, - { - "name": "has_locked_behavior_pack", - "type": "bool" - }, - { - "name": "has_locked_resource_pack", - "type": "bool" - }, - { - "name": "is_from_locked_world_template", - "type": "bool" - }, - { - "name": "msa_gamertags_only", - "type": "bool" - }, - { - "name": "is_from_world_template", - "type": "bool" - }, - { - "name": "is_world_template_option_locked", - "type": "bool" - }, - { - "name": "only_spawn_v1_villagers", - "type": "bool" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "limited_world_width", - "type": "li32" - }, - { - "name": "limited_world_length", - "type": "li32" - }, - { - "name": "is_new_nether", - "type": "bool" - }, - { - "name": "experimental_gameplay_override", - "type": "bool" - }, - { - "name": "level_id", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - }, - { - "name": "premium_world_template_id", - "type": "string" - }, - { - "name": "is_trial", - "type": "bool" - }, - { - "name": "movement_authority", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "client", - "1": "server", - "2": "server_with_rewind" - } - } - ] - }, - { - "name": "rewind_history_size", - "type": "zigzag32" - }, - { - "name": "server_authoritative_block_breaking", - "type": "bool" - }, - { - "name": "current_tick", - "type": "li64" - }, - { - "name": "enchantment_seed", - "type": "zigzag32" - }, - { - "name": "block_properties", - "type": "BlockProperties" - }, - { - "name": "itemstates", - "type": "Itemstates" - }, - { - "name": "multiplayer_correlation_id", - "type": "string" - }, - { - "name": "server_authoritative_inventory", - "type": "bool" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - }, - { - "name": "links", - "type": "Links" - }, - { - "name": "device_id", - "type": "string" - }, - { - "name": "device_os", - "type": "li32" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "attributes", - "type": "EntityAttributes" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "links", - "type": "Links" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "is_from_fishing", - "type": "bool" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "target", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "Rotation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "normal", - "1": "reset", - "2": "teleport", - "3": "rotation" - } - } - ] - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "ridden_runtime_id", - "type": "varint" - }, - { - "name": "teleport", - "type": [ - "switch", - { - "compareTo": "mode", - "fields": { - "teleport": [ - "container", - [ - { - "name": "cause", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "unknown", - "1": "projectile", - "2": "chorus_fruit", - "3": "command", - "4": "behavior" - } - } - ] - }, - { - "name": "source_entity_type", - "type": "LegacyEntityType" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_rider_jump": [ - "container", - [ - { - "name": "jump_strength", - "type": "zigzag32" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "coordinates", - "type": "vec3f" - }, - { - "name": "direction", - "type": "zigzag32" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_tick_sync": [ - "container", - [ - { - "name": "request_time", - "type": "li64" - }, - { - "name": "response_time", - "type": "li64" - } - ] - ], - "packet_level_sound_event_old": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "zigzag32" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "1000": "sound_click", - "1001": "sound_click_fail", - "1002": "sound_shoot", - "1003": "sound_door", - "1004": "sound_fizz", - "1005": "sound_ignite", - "1007": "sound_ghast", - "1008": "sound_ghast_shoot", - "1009": "sound_blaze_shoot", - "1010": "sound_door_bump", - "1012": "sound_door_crash", - "1018": "sound_enderman_teleport", - "1020": "sound_anvil_break", - "1021": "sound_anvil_use", - "1022": "sound_anvil_fall", - "1030": "sound_pop", - "1032": "sound_portal", - "1040": "sound_itemframe_add_item", - "1041": "sound_itemframe_remove", - "1042": "sound_itemframe_place", - "1043": "sound_itemframe_remove_item", - "1044": "sound_itemframe_rotate_item", - "1050": "sound_camera", - "1051": "sound_orb", - "1052": "sound_totem", - "1060": "sound_armor_stand_break", - "1061": "sound_armor_stand_hit", - "1062": "sound_armor_stand_fall", - "1063": "sound_armor_stand_place", - "1064": "pointed_dripstone_land", - "1065": "dye_used", - "1066": "ink_sack_used", - "2000": "particle_shoot", - "2001": "particle_destroy", - "2002": "particle_splash", - "2003": "particle_eye_despawn", - "2004": "particle_spawn", - "2005": "particle_crop_growth", - "2006": "particle_guardian_curse", - "2007": "particle_death_smoke", - "2008": "particle_block_force_field", - "2009": "particle_projectile_hit", - "2010": "particle_dragon_egg_teleport", - "2011": "particle_crop_eaten", - "2012": "particle_critical", - "2013": "particle_enderman_teleport", - "2014": "particle_punch_block", - "2015": "particle_bubble", - "2016": "particle_evaporate", - "2017": "particle_destroy_armor_stand", - "2018": "particle_breaking_egg", - "2019": "particle_destroy_egg", - "2020": "particle_evaporate_water", - "2021": "particle_destroy_block_no_sound", - "2022": "particle_knockback_roar", - "2023": "particle_teleport_trail", - "2024": "particle_point_cloud", - "2025": "particle_explosion", - "2026": "particle_block_explosion", - "2027": "particle_vibration_signal", - "2028": "particle_dripstone_drip", - "2029": "particle_fizz_effect", - "2030": "particle_wax_on", - "2031": "particle_wax_off", - "2032": "particle_scrape", - "2033": "particle_electric_spark", - "3001": "start_rain", - "3002": "start_thunder", - "3003": "stop_rain", - "3004": "stop_thunder", - "3005": "pause_game", - "3006": "pause_game_no_screen", - "3007": "set_game_speed", - "3500": "redstone_trigger", - "3501": "cauldron_explode", - "3502": "cauldron_dye_armor", - "3503": "cauldron_clean_armor", - "3504": "cauldron_fill_potion", - "3505": "cauldron_take_potion", - "3506": "cauldron_fill_water", - "3507": "cauldron_take_water", - "3508": "cauldron_add_dye", - "3509": "cauldron_clean_banner", - "3600": "block_start_break", - "3601": "block_stop_break", - "4000": "set_data", - "9800": "players_sleeping", - "16384": "add_particle_mask" - } - } - ] - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "sound", - "1": "change_state" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "jump", - "2": "hurt_animation", - "3": "death_animation", - "4": "arm_swing", - "5": "stop_attack", - "6": "tame_fail", - "7": "tame_success", - "8": "shake_wet", - "9": "use_item", - "10": "eat_grass_animation", - "11": "fish_hook_bubble", - "12": "fish_hook_position", - "13": "fish_hook_hook", - "14": "fish_hook_tease", - "15": "squid_ink_cloud", - "16": "zombie_villager_cure", - "18": "respawn", - "19": "iron_golem_offer_flower", - "20": "iron_golem_withdraw_flower", - "21": "love_particles", - "22": "villager_angry", - "23": "villager_happy", - "24": "witch_spell_particles", - "25": "firework_particles", - "26": "in_love_particles", - "27": "silverfish_spawn_animation", - "28": "guardian_attack", - "29": "witch_drink_potion", - "30": "witch_throw_potion", - "31": "minecart_tnt_prime_fuse", - "32": "creeper_prime_fuse", - "33": "air_supply_expired", - "34": "player_add_xp_levels", - "35": "elder_guardian_curse", - "36": "agent_arm_swing", - "37": "ender_dragon_death", - "38": "dust_particles", - "39": "arrow_shake", - "57": "eating_item", - "60": "baby_animal_feed", - "61": "death_smoke_cloud", - "62": "complete_trade", - "63": "remove_leash", - "65": "consume_totem", - "66": "player_check_treasure_hunter_achievement", - "67": "entity_spawn", - "68": "dragon_puke", - "69": "item_entity_merge", - "70": "start_swim", - "71": "balloon_pop", - "72": "treasure_hunt", - "73": "agent_summon", - "74": "charged_crossbow", - "75": "fall" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "zigzag32" - }, - { - "name": "amplifier", - "type": "zigzag32" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "zigzag32" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "attributes", - "type": "PlayerAttributes" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_inventory_transaction": [ - "container", - [ - { - "name": "transaction", - "type": "Transaction" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "window_id", - "type": "WindowID" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "helmet", - "type": "Item" - }, - { - "name": "chestplate", - "type": "Item" - }, - { - "name": "leggings", - "type": "Item" - }, - { - "name": "boots", - "type": "Item" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "3": "leave_vehicle", - "4": "mouse_over_entity", - "6": "open_inventory" - } - } - ] - }, - { - "name": "target_entity_id", - "type": "varint64" - }, - { - "name": "position", - "type": [ - "switch", - { - "compareTo": "action_id", - "fields": { - "mouse_over_entity": "vec3f", - "leave_vehicle": "vec3f" - }, - "default": "void" - } - ] - } - ] - ], - "packet_block_pick_request": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "add_user_data", - "type": "bool" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_entity_pick_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "lu64" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "action", - "type": "Action" - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "tick", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "link", - "type": "Link" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "spawn_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "player", - "1": "world" - } - } - ] - }, - { - "name": "player_position", - "type": "BlockCoordinates" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "world_position", - "type": "BlockCoordinates" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "none", - "1": "swing_arm", - "2": "unknown", - "3": "wake_up", - "4": "critical_hit", - "5": "magic_critical_hit", - "6": "row_right", - "7": "row_left" - } - } - ] - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "state", - "type": "u8" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "runtime_entity_id", - "type": "zigzag64" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "server", - "type": "bool" - } - ] - ], - "packet_player_hotbar": [ - "container", - [ - { - "name": "selected_slot", - "type": "varint" - }, - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "select_slot", - "type": "bool" - } - ] - ], - "packet_inventory_content": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "input", - "type": "ItemStacks" - } - ] - ], - "packet_inventory_slot": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "Item" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "property", - "type": "zigzag32" - }, - { - "name": "value", - "type": "zigzag32" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "Recipes" - }, - { - "name": "potion_type_recipes", - "type": "PotionTypeRecipes" - }, - { - "name": "potion_container_recipes", - "type": "PotionContainerChangeRecipes" - }, - { - "name": "is_clean", - "type": "bool" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "recipe_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "inventory", - "1": "crafting", - "2": "workbench" - } - } - ] - }, - { - "name": "recipe_id", - "type": "uuid" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "result", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - } - ] - ], - "packet_gui_data_pick_item": [ - "container", - [ - { - "name": "item_name", - "type": "string" - }, - { - "name": "item_effects", - "type": "string" - }, - { - "name": "hotbar_slot", - "type": "li32" - } - ] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "AdventureFlags" - }, - { - "name": "command_permission", - "type": [ - "mapper", - { - "type": "varint32", - "mappings": { - "0": "normal", - "1": "operator", - "2": "host", - "3": "automation", - "4": "admin" - } - } - ] - }, - { - "name": "action_permissions", - "type": "ActionPermissions" - }, - { - "name": "permission_level", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "visitor", - "1": "member", - "2": "operator", - "3": "custom" - } - } - ] - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "jumping", - "type": "bool" - }, - { - "name": "sneaking", - "type": "bool" - } - ] - ], - "packet_level_chunk": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "sub_chunk_count", - "type": "varint" - }, - { - "name": "cache_enabled", - "type": "bool" - }, - { - "name": "blobs", - "type": [ - "switch", - { - "compareTo": "cache_enabled", - "fields": { - "true": [ - "container", - [ - { - "name": "hashes", - "type": [ - "array", - { - "countType": "varint", - "type": "lu64" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "respawn", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "PlayerRecords" - } - ] - ], - "packet_simple_event": [ - "container", - [ - { - "name": "event_type", - "type": "lu16" - } - ] - ], - "packet_event": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint64" - }, - { - "name": "event_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "achievement_awarded", - "1": "entity_interact", - "2": "portal_built", - "3": "portal_used", - "4": "mob_killed", - "5": "cauldron_used", - "6": "player_death", - "7": "boss_killed", - "8": "agent_command", - "9": "agent_created", - "10": "banner_pattern_removed", - "11": "commaned_executed", - "12": "fish_bucketed", - "13": "mob_born", - "14": "pet_died", - "15": "cauldron_block_used", - "16": "composter_block_used", - "17": "bell_block_used", - "18": "actor_definition", - "19": "raid_update", - "20": "player_movement_anomaly", - "21": "player_moement_corrected", - "22": "honey_harvested", - "23": "target_block_hit", - "24": "piglin_barter" - } - } - ] - }, - { - "name": "use_player_id", - "type": "u8" - }, - { - "name": "event_data", - "type": "restBuffer" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ], - "packet_clientbound_map_item_data": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - }, - { - "name": "update_flags", - "type": "UpdateMapFlags" - }, - { - "name": "dimension", - "type": "u8" - }, - { - "name": "locked", - "type": "bool" - }, - { - "name": "included_in", - "type": [ - "switch", - { - "compareTo": "update_flags.initialisation", - "fields": { - "true": [ - "array", - { - "countType": "varint", - "type": "zigzag64" - } - ] - }, - "default": "void" - } - ] - }, - { - "name": "scale", - "type": [ - "switch", - { - "compareTo": "update_flags.initialisation || update_flags.decoration || update_flags.texture", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "tracked", - "type": [ - "switch", - { - "compareTo": "update_flags.decoration", - "fields": { - "true": [ - "container", - [ - { - "name": "objects", - "type": [ - "array", - { - "countType": "varint", - "type": "TrackedObject" - } - ] - }, - { - "name": "decorations", - "type": [ - "array", - { - "countType": "varint", - "type": "MapDecoration" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "texture", - "type": [ - "switch", - { - "compareTo": "update_flags.texture", - "fields": { - "true": [ - "container", - [ - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "x_offset", - "type": "zigzag32" - }, - { - "name": "y_offset", - "type": "zigzag32" - }, - { - "name": "pixels", - "type": [ - "array", - { - "countType": "varint", - "type": "varint" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_item_frame_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - } - ] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "GameRules" - } - ] - ], - "packet_camera": [ - "container", - [ - { - "name": "camera_entity_unique_id", - "type": "zigzag64" - }, - { - "name": "target_player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_boss_event": [ - "container", - [ - { - "name": "boss_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "show_bar", - "1": "register_player", - "2": "hide_bar", - "3": "unregister_player", - "4": "set_bar_progress", - "5": "set_bar_title", - "6": "update_properties", - "7": "texture" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "show_bar": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "progress", - "type": "lf32" - }, - { - "name": "screen_darkening", - "type": "li16" - }, - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "register_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "unregister_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "set_bar_progress": [ - "container", - [ - { - "name": "progress", - "type": "lf32" - } - ] - ], - "set_bar_title": [ - "container", - [ - { - "name": "title", - "type": "string" - } - ] - ], - "update_properties": [ - "container", - [ - { - "name": "screen_darkening", - "type": "li16" - }, - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "texture": [ - "container", - [ - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_show_credits": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "status", - "type": "zigzag32" - } - ] - ], - "packet_available_commands": [ - "container", - [ - { - "name": "values_len", - "type": "varint" - }, - { - "name": "_enum_type", - "type": [ - "enum_size_based_on_values_len" - ] - }, - { - "name": "enum_values", - "type": [ - "array", - { - "count": "values_len", - "type": "string" - } - ] - }, - { - "name": "suffixes", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - }, - { - "name": "enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "switch", - { - "compareTo": "../_enum_type", - "fields": { - "byte": "u8", - "short": "lu16", - "int": "lu32" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "command_data", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "description", - "type": "string" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "permission_level", - "type": "u8" - }, - { - "name": "alias", - "type": "li32" - }, - { - "name": "overloads", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "paramater_name", - "type": "string" - }, - { - "name": "value_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "1": "int", - "2": "float", - "3": "value", - "4": "wildcard_int", - "5": "operator", - "6": "target", - "16": "file_path", - "32": "string", - "40": "position", - "44": "message", - "46": "raw_text", - "50": "json", - "63": "command" - } - } - ] - }, - { - "name": "enum_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "16": "valid", - "32": "enum", - "256": "suffixed", - "1024": "soft_enum" - } - } - ] - }, - { - "name": "optional", - "type": "bool" - }, - { - "name": "options", - "type": "CommandFlags" - } - ] - ] - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "dynamic_enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "enum_constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "value_index", - "type": "li32" - }, - { - "name": "enum_index", - "type": "li32" - }, - { - "name": "constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "constraint", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "cheats_enabled", - "1": "operator_permissions", - "2": "host_permissions" - } - } - ] - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_command_request": [ - "container", - [ - { - "name": "command", - "type": "string" - }, - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "interval", - "type": "bool" - } - ] - ], - "packet_command_block_update": [ - "container", - [ - { - "name": "is_block", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "is_block", - "fields": { - "true": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "impulse", - "1": "repeat", - "2": "chain" - } - } - ] - }, - { - "name": "needs_redstone", - "type": "bool" - }, - { - "name": "conditional", - "type": "bool" - } - ] - ] - }, - "default": [ - "container", - [ - { - "name": "minecart_entity_runtime_id", - "type": "varint64" - } - ] - ] - } - ] - }, - { - "name": "command", - "type": "string" - }, - { - "name": "last_output", - "type": "string" - }, - { - "name": "name", - "type": "string" - }, - { - "name": "should_track_output", - "type": "bool" - }, - { - "name": "tick_delay", - "type": "li32" - }, - { - "name": "execute_on_first_tick", - "type": "bool" - } - ] - ], - "packet_command_output": [ - "container", - [ - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "output_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "last", - "2": "silent", - "3": "all", - "4": "data_set" - } - } - ] - }, - { - "name": "success_count", - "type": "varint" - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "success", - "type": "bool" - }, - { - "name": "message_id", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "data_set", - "type": [ - "switch", - { - "compareTo": "output_type", - "fields": { - "data_set": "string" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_trade": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "varint" - }, - { - "name": "trade_tier", - "type": "varint" - }, - { - "name": "villager_unique_id", - "type": "varint64" - }, - { - "name": "entity_unique_id", - "type": "varint64" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "new_trading_ui", - "type": "bool" - }, - { - "name": "economic_trades", - "type": "bool" - }, - { - "name": "offers", - "type": "nbt" - } - ] - ], - "packet_update_equipment": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "inventory", - "type": "nbt" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "max_chunk_size", - "type": "lu32" - }, - { - "name": "chunk_count", - "type": "lu32" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "hash", - "type": "ByteArray" - }, - { - "name": "is_premium", - "type": "bool" - }, - { - "name": "pack_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "addon", - "2": "cached", - "3": "copy_protected", - "4": "behavior", - "5": "persona_piece", - "6": "resources", - "7": "skins", - "8": "world_template" - } - } - ] - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - }, - { - "name": "progress", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "server_address", - "type": "string" - }, - { - "name": "port", - "type": "lu16" - } - ] - ], - "packet_play_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "volume", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - } - ] - ], - "packet_stop_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "stop_all", - "type": "bool" - } - ] - ], - "packet_set_title": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "clear", - "1": "reset", - "2": "set_title", - "3": "set_subtitle", - "4": "action_bar_message", - "5": "set_durations", - "6": "set_title_json", - "7": "set_subtitle_json", - "8": "action_bar_message_json" - } - } - ] - }, - { - "name": "text", - "type": "string" - }, - { - "name": "fade_in_time", - "type": "zigzag32" - }, - { - "name": "stay_time", - "type": "zigzag32" - }, - { - "name": "fade_out_time", - "type": "zigzag32" - } - ] - ], - "packet_add_behavior_tree": [ - "container", - [ - { - "name": "behaviortree", - "type": "string" - } - ] - ], - "packet_structure_block_update": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "structure_name", - "type": "string" - }, - { - "name": "data_field", - "type": "string" - }, - { - "name": "include_players", - "type": "bool" - }, - { - "name": "show_bounding_box", - "type": "bool" - }, - { - "name": "structure_block_type", - "type": "zigzag32" - }, - { - "name": "settings", - "type": "StructureBlockSettings" - }, - { - "name": "redstone_save_mode", - "type": "zigzag32" - }, - { - "name": "should_trigger", - "type": "bool" - } - ] - ], - "packet_show_store_offer": [ - "container", - [ - { - "name": "offer_id", - "type": "string" - }, - { - "name": "show_all", - "type": "bool" - } - ] - ], - "packet_purchase_receipt": [ - "container", - [ - { - "name": "receipts", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_player_skin": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "skin", - "type": "Skin" - }, - { - "name": "skin_name", - "type": "string" - }, - { - "name": "old_skin_name", - "type": "string" - }, - { - "name": "is_verified", - "type": "bool" - } - ] - ], - "packet_sub_client_login": [ - "container", - [ - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "packet_initiate_web_socket_connection": [ - "container", - [ - { - "name": "server", - "type": "string" - } - ] - ], - "packet_set_last_hurt_by": [ - "container", - [ - { - "name": "entity_type", - "type": "varint" - } - ] - ], - "packet_book_edit": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "replace_page", - "1": "add_page", - "2": "delete_page", - "3": "swap_pages", - "4": "sign" - } - } - ] - }, - { - "name": "slot", - "type": "u8" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "replace_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "add_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "delete_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - } - ] - ], - "swap_pages": [ - "container", - [ - { - "name": "page1", - "type": "u8" - }, - { - "name": "page2", - "type": "u8" - } - ] - ], - "sign": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "author", - "type": "string" - }, - { - "name": "xuid", - "type": "string" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_npc_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "request_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "set_actions", - "1": "execute_action", - "2": "execute_closing_commands", - "3": "set_name", - "4": "set_skin", - "5": "set_interaction_text" - } - } - ] - }, - { - "name": "command", - "type": "string" - }, - { - "name": "action_type", - "type": "u8" - } - ] - ], - "packet_photo_transfer": [ - "container", - [ - { - "name": "image_name", - "type": "string" - }, - { - "name": "image_data", - "type": "string" - }, - { - "name": "book_id", - "type": "string" - } - ] - ], - "packet_modal_form_request": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_modal_form_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_server_settings_request": [ - "container", - [] - ], - "packet_server_settings_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_show_profile": [ - "container", - [ - { - "name": "xuid", - "type": "string" - } - ] - ], - "packet_set_default_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_remove_objective": [ - "container", - [ - { - "name": "objective_name", - "type": "string" - } - ] - ], - "packet_set_display_objective": [ - "container", - [ - { - "name": "display_slot", - "type": "string" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "criteria_name", - "type": "string" - }, - { - "name": "sort_order", - "type": "zigzag32" - } - ] - ], - "packet_set_score": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "change", - "1": "remove" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "../action", - "fields": { - "change": [ - "container", - [ - { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": "zigzag64", - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "custom_name", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "fake_player": "string" - }, - "default": "void" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_lab_table": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "combine", - "1": "react" - } - } - ] - }, - { - "name": "position", - "type": "vec3u" - }, - { - "name": "reaction_type", - "type": "u8" - } - ] - ], - "packet_update_block_synced": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "transition_type", - "type": [ - "mapper", - { - "type": "varint64", - "mappings": { - "0": "entity", - "1": "create", - "2": "destroy" - } - } - ] - } - ] - ], - "packet_move_entity_delta": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "DeltaMoveFlags" - }, - { - "name": "x", - "type": [ - "switch", - { - "compareTo": "flags.has_x", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "y", - "type": [ - "switch", - { - "compareTo": "flags.has_y", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "z", - "type": [ - "switch", - { - "compareTo": "flags.has_z", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "rot_x", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_x", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_y", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_y", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_z", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_z", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_scoreboard_identity": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "register_identity", - "1": "clear_identity" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "../action", - "fields": { - "register_identity": "zigzag64" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_set_local_player_as_initialized": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_update_soft_enum": [ - "container", - [] - ], - "packet_network_stack_latency": [ - "container", - [ - { - "name": "timestamp", - "type": "lu64" - }, - { - "name": "needs_response", - "type": "u8" - } - ] - ], - "packet_script_custom_event": [ - "container", - [ - { - "name": "event_name", - "type": "string" - }, - { - "name": "event_data", - "type": "string" - } - ] - ], - "packet_spawn_particle_effect": [ - "container", - [ - { - "name": "dimension", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "particle_name", - "type": "string" - } - ] - ], - "packet_available_entity_identifiers": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event_v2": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_network_chunk_publisher_update": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "radius", - "type": "varint" - } - ] - ], - "packet_biome_definition_list": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "SoundType" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "extra_data", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event_generic": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "nbt", - "type": "nbtLoop" - } - ] - ], - "packet_lectern_update": [ - "container", - [ - { - "name": "page", - "type": "u8" - }, - { - "name": "page_count", - "type": "u8" - }, - { - "name": "position", - "type": "vec3i" - }, - { - "name": "drop_book", - "type": "bool" - } - ] - ], - "packet_video_stream_connect": [ - "container", - [ - { - "name": "server_uri", - "type": "string" - }, - { - "name": "frame_send_frequency", - "type": "lf32" - }, - { - "name": "action", - "type": "u8" - }, - { - "name": "resolution_x", - "type": "li32" - }, - { - "name": "resolution_y", - "type": "li32" - } - ] - ], - "packet_add_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_remove_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_client_cache_status": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_on_screen_texture_animation": [ - "container", - [ - { - "name": "animation_type", - "type": "lu32" - } - ] - ], - "packet_map_create_locked_copy": [ - "container", - [ - { - "name": "original_map_id", - "type": "zigzag64" - }, - { - "name": "new_map_id", - "type": "zigzag64" - } - ] - ], - "packet_structure_template_data_export_request": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "settings", - "type": "StructureBlockSettings" - }, - { - "name": "request_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "export_from_save", - "2": "export_from_load", - "3": "query_saved_structure" - } - } - ] - } - ] - ], - "packet_structure_template_data_export_response": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "success", - "type": "bool" - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "success", - "fields": { - "true": "nbt" - }, - "default": "void" - } - ] - }, - { - "name": "response_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "export", - "2": "query" - } - } - ] - } - ] - ], - "packet_update_block_properties": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_client_cache_blob_status": [ - "container", - [ - { - "name": "misses", - "type": "varint" - }, - { - "name": "haves", - "type": "varint" - }, - { - "name": "missing", - "type": [ - "array", - { - "count": "misses", - "type": "lu64" - } - ] - }, - { - "name": "have", - "type": [ - "array", - { - "count": "haves", - "type": "lu64" - } - ] - } - ] - ], - "packet_client_cache_miss_response": [ - "container", - [ - { - "name": "blobs", - "type": [ - "array", - { - "countType": "varint", - "type": "Blob" - } - ] - } - ] - ], - "packet_education_settings": [ - "container", - [ - { - "name": "CodeBuilderDefaultURI", - "type": "string" - }, - { - "name": "CodeBuilderTitle", - "type": "string" - }, - { - "name": "CanResizeCodeBuilder", - "type": "bool" - }, - { - "name": "HasOverrideURI", - "type": "bool" - }, - { - "name": "OverrideURI", - "type": [ - "switch", - { - "compareTo": "HasOverrideURI", - "fields": { - "true": "string" - }, - "default": "void" - } - ] - }, - { - "name": "HasQuiz", - "type": "bool" - } - ] - ], - "packet_multiplayer_settings": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "enable_multiplayer", - "1": "disable_multiplayer", - "2": "refresh_join_code" - } - } - ] - } - ] - ], - "packet_settings_command": [ - "container", - [ - { - "name": "command_line", - "type": "string" - }, - { - "name": "suppress_output", - "type": "bool" - } - ] - ], - "packet_anvil_damage": [ - "container", - [ - { - "name": "damage", - "type": "u8" - }, - { - "name": "position", - "type": "BlockCoordinates" - } - ] - ], - "packet_completed_using_item": [ - "container", - [ - { - "name": "used_item_id", - "type": "li16" - }, - { - "name": "use_method", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "equip_armor", - "1": "eat", - "2": "attack", - "3": "consume", - "4": "throw", - "5": "shoot", - "6": "place", - "7": "fill_bottle", - "8": "fill_bucket", - "9": "pour_bucket", - "10": "use_tool", - "11": "interact", - "12": "retrieved", - "13": "dyed", - "14": "traded" - } - } - ] - } - ] - ], - "packet_network_settings": [ - "container", - [ - { - "name": "compression_threshold", - "type": "u16" - } - ] - ], - "packet_player_auth_input": [ - "container", - [ - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "move_vector", - "type": "vec2f" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "input_data", - "type": "InputFlag" - }, - { - "name": "input_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "unknown", - "1": "mouse", - "2": "touch", - "3": "game_pad", - "4": "motion_controller" - } - } - ] - }, - { - "name": "play_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "teaser", - "2": "screen", - "3": "viewer", - "4": "reality", - "5": "placement", - "6": "living_room", - "7": "exit_level", - "8": "exit_level_living_room", - "9": "num_modes" - } - } - ] - }, - { - "name": "gaze_direction", - "type": [ - "switch", - { - "compareTo": "play_mode", - "fields": { - "reality": "vec3f" - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "transaction", - "type": [ - "switch", - { - "compareTo": "input_data.item_interact", - "fields": { - "true": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "data", - "type": "TransactionUseItem" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "item_stack_request", - "type": [ - "switch", - { - "compareTo": "input_data.item_stack_request", - "fields": { - "true": "ItemStackRequest" - }, - "default": "void" - } - ] - }, - { - "name": "block_action", - "type": [ - "switch", - { - "compareTo": "input_data.block_action", - "fields": { - "true": [ - "array", - { - "countType": "zigzag32", - "type": [ - "container", - [ - { - "name": "action", - "type": "Action" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "action", - "fields": { - "start_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "abort_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "crack_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "predict_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "continue_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_creative_content": [ - "container", - [ - { - "name": "items", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "entry_id", - "type": "varint" - }, - { - "name": "item", - "type": "ItemLegacy" - } - ] - ] - } - ] - } - ] - ], - "packet_player_enchant_options": [ - "container", - [ - { - "name": "options", - "type": [ - "array", - { - "countType": "varint", - "type": "EnchantOption" - } - ] - } - ] - ], - "packet_item_stack_request": [ - "container", - [ - { - "name": "requests", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemStackRequest" - } - ] - } - ] - ], - "packet_item_stack_response": [ - "container", - [ - { - "name": "responses", - "type": "ItemStackResponses" - } - ] - ], - "packet_player_armor_damage": [ - "container", - [ - { - "name": "type", - "type": "ArmorDamageType" - }, - { - "name": "helmet_damage", - "type": [ - "switch", - { - "compareTo": "type.head", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "chestplate_damage", - "type": [ - "switch", - { - "compareTo": "type.chest", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "leggings_damage", - "type": [ - "switch", - { - "compareTo": "type.legs", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "boots_damage", - "type": [ - "switch", - { - "compareTo": "type.feet", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - }, - { - "name": "player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_position_tracking_db_request": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "query" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - } - ] - ], - "packet_position_tracking_db_broadcast": [ - "container", - [ - { - "name": "broadcast_action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "update", - "1": "destory", - "2": "not_found" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_packet_violation_warning": [ - "container", - [ - { - "name": "violation_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "malformed" - } - } - ] - }, - { - "name": "severity", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "warning", - "1": "final_warning", - "2": "terminating" - } - } - ] - }, - { - "name": "packet_id", - "type": "zigzag32" - }, - { - "name": "reason", - "type": "string" - } - ] - ], - "packet_motion_prediction_hints": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - } - ] - ], - "packet_animate_entity": [ - "container", - [ - { - "name": "animation", - "type": "string" - }, - { - "name": "next_state", - "type": "string" - }, - { - "name": "stop_condition", - "type": "string" - }, - { - "name": "controller", - "type": "string" - }, - { - "name": "blend_out_time", - "type": "lf32" - }, - { - "name": "runtime_entity_ids", - "type": [ - "array", - { - "countType": "varint", - "type": "varint64" - } - ] - } - ] - ], - "packet_camera_shake": [ - "container", - [ - { - "name": "intensity", - "type": "lf32" - }, - { - "name": "duration", - "type": "lf32" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "stop" - } - } - ] - } - ] - ], - "packet_player_fog": [ - "container", - [ - { - "name": "stack", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_correct_player_move_prediction": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_item_component": [ - "container", - [ - { - "name": "entries", - "type": "ItemComponentList" - } - ] - ], - "packet_filter_text_packet": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "from_server", - "type": "bool" - } - ] - ], - "packet_debug_renderer": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "1": "clear", - "2": "add_cube" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "clear": "void", - "add_cube": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "red", - "type": "lf32" - }, - { - "name": "green", - "type": "lf32" - }, - { - "name": "blue", - "type": "lf32" - }, - { - "name": "alpha", - "type": "lf32" - }, - { - "name": "duration", - "type": "li64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "string": [ - "pstring", - { - "countType": "varint" - } - ], - "ByteArray": [ - "buffer", - { - "countType": "varint" - } - ], - "SignedByteArray": [ - "buffer", - { - "countType": "zigzag32" - } - ], - "LittleString": [ - "pstring", - { - "countType": "li32" - } - ], - "ShortArray": [ - "buffer", - { - "countType": "li16" - } - ], - "MetadataFlags1": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "onfire", - "sneaking", - "riding", - "sprinting", - "action", - "invisible", - "tempted", - "inlove", - "saddled", - "powered", - "ignited", - "baby", - "converting", - "critical", - "can_show_nametag", - "always_show_nametag", - "no_ai", - "silent", - "wallclimbing", - "can_climb", - "swimmer", - "can_fly", - "walker", - "resting", - "sitting", - "angry", - "interested", - "charged", - "tamed", - "orphaned", - "leashed", - "sheared", - "gliding", - "elder", - "moving", - "breathing", - "chested", - "stackable", - "showbase", - "rearing", - "vibrating", - "idling", - "evoker_spell", - "charge_attack", - "wasd_controlled", - "can_power_jump", - "linger", - "has_collision", - "affected_by_gravity", - "fire_immune", - "dancing", - "enchanted", - "show_trident_rope", - "container_private", - "transforming", - "spin_attack", - "swimming", - "bribed", - "pregnant", - "laying_egg", - "rider_can_pick", - "transition_sitting", - "eating", - "laying_down" - ] - } - ], - "MetadataFlags2": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "sneezing", - "trusting", - "rolling", - "scared", - "in_scaffolding", - "over_scaffolding", - "fall_through_scaffolding", - "blocking", - "transition_blocking", - "blocked_using_shield", - "blocked_using_damaged_shield", - "sleeping", - "wants_to_wake", - "trade_interest", - "door_breaker", - "breaking_obstruction", - "door_opener", - "illager_captain", - "stunned", - "roaring", - "delayed_attacking", - "avoiding_mobs", - "avoiding_block", - "facing_target_to_range_attack", - "hidden_when_invisible", - "is_in_ui", - "stalking", - "emoting", - "celebrating", - "admiring", - "celebrating_special" - ] - } - ], - "UpdateBlockFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "neighbors": 1, - "network": 2, - "no_graphic": 4, - "unused": 8, - "priority": 16 - } - } - ], - "AdventureFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "world_immutable": 1, - "no_pvp": 2, - "auto_jump": 32, - "allow_flight": 64, - "no_clip": 128, - "world_builder": 256, - "flying": 512, - "muted": 1024 - } - } - ], - "ActionPermissions": [ - "bitflags", - { - "type": "varint", - "flags": { - "mine": 65537, - "doors_and_switches": 65538, - "open_containers": 65540, - "attack_players": 65544, - "attack_mobs": 65552, - "operator": 65568, - "teleport": 65664, - "build": 65792, - "default": 66048 - } - } - ], - "UpdateMapFlags": [ - "bitflags", - { - "type": "varint", - "flags": [ - "void", - "texture", - "decoration", - "initialisation" - ] - } - ], - "CommandFlags": [ - "bitfield", - [ - { - "name": "unused", - "size": 6, - "signed": false - }, - { - "name": "has_semantic_constraint", - "size": 1, - "signed": false - }, - { - "name": "collapse_enum", - "size": 1, - "signed": false - } - ] - ], - "DeltaMoveFlags": [ - "bitflags", - { - "type": "lu16", - "flags": { - "has_x": 1, - "has_y": 2, - "has_z": 4, - "has_rot_x": 8, - "has_rot_y": 16, - "has_rot_z": 32, - "on_ground": 64, - "teleport": 128, - "force_move": 256 - } - } - ], - "InputFlag": [ - "bitflags", - { - "type": "varint64", - "big": true, - "flags": [ - "ascend", - "descend", - "north_jump", - "jump_down", - "sprint_down", - "change_height", - "jumping", - "auto_jumping_in_water", - "sneaking", - "sneak_down", - "up", - "down", - "left", - "right", - "up_left", - "up_right", - "want_up", - "want_down", - "want_down_slow", - "want_up_slow", - "sprinting", - "ascend_scaffolding", - "descend_scaffolding", - "sneak_toggle_down", - "persist_sneak", - "start_sprinting", - "stop_sprinting", - "start_sneaking", - "stop_sneaking", - "start_swimming", - "stop_swimming", - "start_jumping", - "start_gliding", - "stop_gliding", - "item_interact", - "block_action", - "item_stack_request" - ] - } - ], - "ArmorDamageType": [ - "bitflags", - { - "type": "u8", - "flags": { - "head": 1, - "chest": 2, - "legs": 4, - "feet": 8 - } - } - ] - } -} \ No newline at end of file diff --git a/data/1.17.0/protocol.json b/data/1.17.0/protocol.json deleted file mode 100644 index 68efe51..0000000 --- a/data/1.17.0/protocol.json +++ /dev/null @@ -1,8907 +0,0 @@ -{ - "types": { - "varint64": "native", - "zigzag32": "native", - "zigzag64": "native", - "uuid": "native", - "byterot": "native", - "bitflags": "native", - "restBuffer": "native", - "encapsulated": "native", - "nbt": "native", - "lnbt": "native", - "nbtLoop": "native", - "enum_size_based_on_values_len": "native", - "MapInfo": "native", - "BehaviourPackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - } - ] - ] - } - ], - "TexturePackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "rtx_enabled", - "type": "bool" - } - ] - ] - } - ], - "ResourcePackIdVersions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "ResourcePackIds": [ - "array", - { - "countType": "li16", - "type": "string" - } - ], - "Experiment": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "enabled", - "type": "bool" - } - ] - ], - "Experiments": [ - "array", - { - "countType": "li32", - "type": "Experiment" - } - ], - "GameMode": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "survival", - "1": "creative", - "2": "adventure", - "3": "survival_spectator", - "4": "creative_spectator", - "5": "fallback" - } - } - ], - "GameRule": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "editable", - "type": "bool" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "bool", - "2": "int", - "3": "float" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "bool": "bool", - "int": "zigzag32", - "float": "lf32" - }, - "default": "void" - } - ] - } - ] - ], - "GameRules": [ - "array", - { - "countType": "varint", - "type": "GameRule" - } - ], - "Blob": [ - "container", - [ - { - "name": "hash", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "BlockProperties": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "state", - "type": "nbt" - } - ] - ] - } - ], - "Itemstates": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "runtime_id", - "type": "li16" - }, - { - "name": "component_based", - "type": "bool" - } - ] - ] - } - ], - "ItemExtraDataWithBlockingTick": [ - "container", - [ - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "lnbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "blocking_tick", - "type": "li64" - } - ] - ], - "ItemExtraDataWithoutBlockingTick": [ - "container", - [ - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "lnbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - } - ] - ], - "ItemLegacy": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "count", - "type": "lu16" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "block_runtime_id", - "type": "zigzag32" - }, - { - "name": "extra", - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "/ShieldItemID": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithBlockingTick" - } - ] - }, - "default": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithoutBlockingTick" - } - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "Item": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "count", - "type": "lu16" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "has_stack_id", - "type": "u8" - }, - { - "name": "stack_id", - "type": [ - "switch", - { - "compareTo": "has_stack_id", - "fields": { - "0": "void" - }, - "default": "zigzag32" - } - ] - }, - { - "name": "block_runtime_id", - "type": "zigzag32" - }, - { - "name": "extra", - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "/ShieldItemID": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithBlockingTick" - } - ] - }, - "default": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithoutBlockingTick" - } - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "vec3i": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "vec3u": [ - "container", - [ - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - } - ] - ], - "vec3f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vec2f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "MetadataDictionary": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "key", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "flags", - "1": "health", - "2": "variant", - "3": "color", - "4": "nametag", - "5": "owner_eid", - "6": "target_eid", - "7": "air", - "8": "potion_color", - "9": "potion_ambient", - "10": "jump_duration", - "11": "hurt_time", - "12": "hurt_direction", - "13": "paddle_time_left", - "14": "paddle_time_right", - "15": "experience_value", - "16": "minecart_display_block", - "17": "minecart_display_offset", - "18": "minecart_has_display", - "20": "old_swell", - "21": "swell_dir", - "22": "charge_amount", - "23": "enderman_held_runtime_id", - "24": "entity_age", - "26": "player_flags", - "27": "player_index", - "28": "player_bed_position", - "29": "fireball_power_x", - "30": "fireball_power_y", - "31": "fireball_power_z", - "32": "aux_power", - "33": "fish_x", - "34": "fish_z", - "35": "fish_angle", - "36": "potion_aux_value", - "37": "lead_holder_eid", - "38": "scale", - "39": "interactive_tag", - "40": "npc_skin_id", - "41": "url_tag", - "42": "max_airdata_max_air", - "43": "mark_variant", - "44": "container_type", - "45": "container_base_size", - "46": "container_extra_slots_per_strength", - "47": "block_target", - "48": "wither_invulnerable_ticks", - "49": "wither_target_1", - "50": "wither_target_2", - "51": "wither_target_3", - "52": "aerial_attack", - "53": "boundingbox_width", - "54": "boundingbox_height", - "55": "fuse_length", - "56": "rider_seat_position", - "57": "rider_rotation_locked", - "58": "rider_max_rotation", - "59": "rider_min_rotation", - "60": "rider_rotation_offset", - "61": "area_effect_cloud_radius", - "62": "area_effect_cloud_waiting", - "63": "area_effect_cloud_particle_id", - "64": "shulker_peek_id", - "65": "shulker_attach_face", - "66": "shulker_attached", - "67": "shulker_attach_pos", - "68": "trading_player_eid", - "69": "trading_career", - "70": "has_command_block", - "71": "command_block_command", - "72": "command_block_last_output", - "73": "command_block_track_output", - "74": "controlling_rider_seat_number", - "75": "strength", - "76": "max_strength", - "77": "spell_casting_color", - "78": "limited_life", - "79": "armor_stand_pose_index", - "80": "ender_crystal_time_offset", - "81": "always_show_nametag", - "82": "color_2", - "83": "name_author", - "84": "score_tag", - "85": "balloon_attached_entity", - "86": "pufferfish_size", - "87": "bubble_time", - "88": "agent", - "89": "sitting_amount", - "90": "sitting_amount_previous", - "91": "eating_counter", - "92": "flags_extended", - "93": "laying_amount", - "94": "laying_amount_previous", - "95": "duration", - "96": "spawn_time", - "97": "change_rate", - "98": "change_on_pickup", - "99": "pickup_count", - "100": "interact_text", - "101": "trade_tier", - "102": "max_trade_tier", - "103": "trade_experience", - "104": "skin_id", - "105": "spawning_frames", - "106": "command_block_tick_delay", - "107": "command_block_execute_on_first_tick", - "108": "ambient_sound_interval", - "109": "ambient_sound_interval_range", - "110": "ambient_sound_event_name", - "111": "fall_damage_multiplier", - "112": "name_raw_text", - "113": "can_ride_target", - "114": "low_tier_cured_discount", - "115": "high_tier_cured_discount", - "116": "nearby_cured_discount", - "117": "nearby_cured_discount_timestamp", - "118": "hitbox", - "119": "is_buoyant", - "120": "base_runtime_id", - "121": "freezing_effect_strength", - "122": "buoyancy_data", - "123": "goat_horn_count", - "124": "update_properties" - } - } - ] - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "byte", - "1": "short", - "2": "int", - "3": "float", - "4": "string", - "5": "compound", - "6": "vec3i", - "7": "long", - "8": "vec3f" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "key", - "fields": { - "flags": "MetadataFlags1", - "flags_extended": "MetadataFlags2" - }, - "default": [ - "switch", - { - "compareTo": "type", - "fields": { - "byte": "i8", - "short": "li16", - "int": "zigzag32", - "float": "lf32", - "string": "string", - "compound": "nbt", - "vec3i": "vec3i", - "long": "zigzag64", - "vec3f": "vec3f" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ], - "Link": [ - "container", - [ - { - "name": "ridden_entity_id", - "type": "zigzag64" - }, - { - "name": "rider_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "immediate", - "type": "bool" - }, - { - "name": "rider_initiated", - "type": "bool" - } - ] - ], - "Links": [ - "array", - { - "countType": "varint", - "type": "Link" - } - ], - "EntityAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "min", - "type": "lf32" - }, - { - "name": "value", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - } - ] - ] - } - ], - "Rotation": [ - "container", - [ - { - "name": "yaw", - "type": "byterot" - }, - { - "name": "pitch", - "type": "byterot" - }, - { - "name": "head_yaw", - "type": "byterot" - } - ] - ], - "BlockCoordinates": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "PlayerAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "min", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - }, - { - "name": "current", - "type": "lf32" - }, - { - "name": "default", - "type": "lf32" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "TransactionUseItem": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "click_block", - "1": "click_air", - "2": "break_block" - } - } - ] - }, - { - "name": "block_position", - "type": "vec3i" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "hotbar_slot", - "type": "varint" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - }, - { - "name": "block_runtime_id", - "type": "varint" - } - ] - ], - "TransactionActions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "container", - "1": "global", - "2": "world_interaction", - "3": "creative", - "100": "craft_slot", - "99999": "craft" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "container": [ - "container", - [ - { - "name": "inventory_id", - "type": "WindowIDVarint" - } - ] - ], - "craft": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "world_interaction": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "craft_slot": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - } - ] - ] - } - ], - "TransactionLegacy": [ - "container", - [ - { - "name": "legacy_request_id", - "type": "zigzag32" - }, - { - "name": "legacy_transactions", - "type": [ - "switch", - { - "compareTo": "legacy_request_id", - "fields": { - "0": "void" - }, - "default": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "changed_slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_id", - "type": "u8" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - } - ] - ], - "Transaction": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "transaction_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "inventory_mismatch", - "2": "item_use", - "3": "item_use_on_entity", - "4": "item_release" - } - } - ] - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "transaction_data", - "type": [ - "switch", - { - "compareTo": "transaction_type", - "fields": { - "normal": "void", - "inventory_mismatch": "void", - "item_use": "TransactionUseItem", - "item_use_on_entity": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "interact", - "1": "attack" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - } - ] - ], - "item_release": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "release", - "1": "consume" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "head_pos", - "type": "vec3f" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "ItemStacks": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ], - "RecipeIngredient": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "network_data", - "type": "zigzag32" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ], - "PotionTypeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "input_item_meta", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "ingredient_meta", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - }, - { - "name": "output_item_meta", - "type": "zigzag32" - } - ] - ] - } - ], - "PotionContainerChangeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - } - ] - ] - } - ], - "Recipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "shapeless", - "1": "shaped", - "2": "furnace", - "3": "furnace_with_metadata", - "4": "multi", - "5": "shulker_box", - "6": "shapeless_chemistry", - "7": "shaped_chemistry" - } - } - ] - }, - { - "name": "recipe", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "shapeless": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shulker_box": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shapeless_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "furnace": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "output", - "type": "ItemLegacy" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "furnace_with_metadata": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "input_meta", - "type": "zigzag32" - }, - { - "name": "output", - "type": "ItemLegacy" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "multi": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "SkinImage": [ - "container", - [ - { - "name": "width", - "type": "li32" - }, - { - "name": "height", - "type": "li32" - }, - { - "name": "data", - "type": "ByteArray" - } - ] - ], - "Skin": [ - "container", - [ - { - "name": "skin_id", - "type": "string" - }, - { - "name": "play_fab_id", - "type": "string" - }, - { - "name": "skin_resource_pack", - "type": "string" - }, - { - "name": "skin_data", - "type": "SkinImage" - }, - { - "name": "animations", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "skin_image", - "type": "SkinImage" - }, - { - "name": "animation_type", - "type": "li32" - }, - { - "name": "animation_frames", - "type": "lf32" - }, - { - "name": "expression_type", - "type": "lf32" - } - ] - ] - } - ] - }, - { - "name": "cape_data", - "type": "SkinImage" - }, - { - "name": "geometry_data", - "type": "string" - }, - { - "name": "animation_data", - "type": "string" - }, - { - "name": "premium", - "type": "bool" - }, - { - "name": "persona", - "type": "bool" - }, - { - "name": "cape_on_classic", - "type": "bool" - }, - { - "name": "cape_id", - "type": "string" - }, - { - "name": "full_skin_id", - "type": "string" - }, - { - "name": "arm_size", - "type": "string" - }, - { - "name": "skin_color", - "type": "string" - }, - { - "name": "personal_pieces", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_id", - "type": "string" - }, - { - "name": "piece_type", - "type": "string" - }, - { - "name": "pack_id", - "type": "string" - }, - { - "name": "is_default_piece", - "type": "bool" - }, - { - "name": "product_id", - "type": "string" - } - ] - ] - } - ] - }, - { - "name": "piece_tint_colors", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_type", - "type": "string" - }, - { - "name": "colors", - "type": [ - "array", - { - "countType": "li32", - "type": "string" - } - ] - } - ] - ] - } - ] - } - ] - ], - "PlayerRecords": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "remove" - } - } - ] - }, - { - "name": "records_count", - "type": "varint" - }, - { - "name": "records", - "type": [ - "array", - { - "count": "records_count", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "xbox_user_id", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "build_platform", - "type": "li32" - }, - { - "name": "skin_data", - "type": "Skin" - }, - { - "name": "is_teacher", - "type": "bool" - }, - { - "name": "is_host", - "type": "bool" - } - ] - ], - "remove": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - }, - { - "name": "verified", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "array", - { - "count": "records_count", - "type": "bool" - } - ] - }, - "default": "void" - } - ] - } - ] - ], - "Enchant": [ - "container", - [ - { - "name": "id", - "type": "u8" - }, - { - "name": "level", - "type": "u8" - } - ] - ], - "EnchantOption": [ - "container", - [ - { - "name": "cost", - "type": "varint" - }, - { - "name": "slot_flags", - "type": "li32" - }, - { - "name": "equip_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "held_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "self_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "name", - "type": "string" - }, - { - "name": "option_id", - "type": "zigzag32" - } - ] - ], - "Action": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "start_break", - "1": "abort_break", - "2": "stop_break", - "3": "get_updated_block", - "4": "drop_item", - "5": "start_sleeping", - "6": "stop_sleeping", - "7": "respawn", - "8": "jump", - "9": "start_sprint", - "10": "stop_sprint", - "11": "start_sneak", - "12": "stop_sneak", - "13": "creative_player_destroy_block", - "14": "dimension_change_ack", - "15": "start_glide", - "16": "stop_glide", - "17": "build_denied", - "18": "crack_break", - "19": "change_skin", - "20": "set_enchatnment_seed", - "21": "swimming", - "22": "stop_swimming", - "23": "start_spin_attack", - "24": "stop_spin_attack", - "25": "interact_block", - "26": "predict_break", - "27": "continue_break" - } - } - ], - "StackRequestSlotInfo": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "stack_id", - "type": "zigzag32" - } - ] - ], - "ItemStackRequest": [ - "container", - [ - { - "name": "request_id", - "type": "varint" - }, - { - "name": "actions", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "take", - "1": "place", - "2": "swap", - "3": "drop", - "4": "destroy", - "5": "consume", - "6": "create", - "7": "lab_table_combine", - "8": "beacon_payment", - "9": "mine_block", - "10": "craft_recipe", - "11": "craft_recipe_auto", - "12": "craft_creative", - "13": "optional", - "14": "non_implemented", - "15": "results_deprecated" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type_id", - "fields": { - "take": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "place": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "swap": [ - "container", - [ - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "drop": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "randomly", - "type": "bool" - } - ] - ], - "destroy": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "consume": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "create": [ - "container", - [ - { - "name": "result_slot_id", - "type": "u8" - } - ] - ], - "beacon_payment": [ - "container", - [ - { - "name": "primary_effect", - "type": "zigzag32" - }, - { - "name": "secondary_effect", - "type": "zigzag32" - } - ] - ], - "mine_block": [ - "container", - [ - { - "name": "unknown1", - "type": "zigzag32" - }, - { - "name": "predicted_durability", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "craft_recipe": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_recipe_auto": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_creative": [ - "container", - [ - { - "name": "item_id", - "type": "varint" - } - ] - ], - "optional": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - }, - { - "name": "filtered_string_index", - "type": "li32" - } - ] - ], - "non_implemented": "void", - "results_deprecated": [ - "container", - [ - { - "name": "result_items", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "times_crafted", - "type": "u8" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - { - "name": "custom_names", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "ItemStackResponses": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "ok", - "1": "error" - } - } - ] - }, - { - "name": "request_id", - "type": "varint" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "status", - "fields": { - "ok": [ - "container", - [ - { - "name": "containers", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot", - "type": "u8" - }, - { - "name": "hotbar_slot", - "type": "u8" - }, - { - "name": "count", - "type": "u8" - }, - { - "name": "item_stack_id", - "type": "varint" - }, - { - "name": "custom_name", - "type": "string" - }, - { - "name": "durability_correction", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "ItemComponentList": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ] - } - ], - "CommandOrigin": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "player", - "1": "block", - "2": "minecart_block", - "3": "dev_console", - "4": "test", - "5": "automation_player", - "6": "client_automation", - "7": "dedicated_server", - "8": "entity", - "9": "virtual", - "10": "game_argument", - "11": "entity_server", - "12": "precompiled", - "13": "game_director_entity_server", - "14": "script" - } - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "player_entity_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "dev_console": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ], - "test": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "TrackedObject": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "entity", - "1": "block" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "block_position", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "block": "BlockCoordinates" - }, - "default": "void" - } - ] - } - ] - ], - "MapDecoration": [ - "container", - [ - { - "name": "type", - "type": "u8" - }, - { - "name": "rotation", - "type": "u8" - }, - { - "name": "x", - "type": "u8" - }, - { - "name": "y", - "type": "u8" - }, - { - "name": "label", - "type": "string" - }, - { - "name": "color_abgr", - "type": "varint" - } - ] - ], - "StructureBlockSettings": [ - "container", - [ - { - "name": "palette_name", - "type": "string" - }, - { - "name": "ignore_entities", - "type": "bool" - }, - { - "name": "ignore_blocks", - "type": "bool" - }, - { - "name": "size", - "type": "BlockCoordinates" - }, - { - "name": "structure_offset", - "type": "BlockCoordinates" - }, - { - "name": "last_editing_player_unique_id", - "type": "zigzag64" - }, - { - "name": "rotation", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "90_deg", - "2": "180_deg", - "3": "270_deg" - } - } - ] - }, - { - "name": "mirror", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "x_axis", - "2": "z_axis", - "3": "both_axes" - } - } - ] - }, - { - "name": "animation_mode", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "layers", - "2": "blocks" - } - } - ] - }, - { - "name": "animation_duration", - "type": "lf32" - }, - { - "name": "integrity", - "type": "lf32" - }, - { - "name": "seed", - "type": "lu32" - }, - { - "name": "pivot", - "type": "vec3f" - } - ] - ], - "WindowID": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowIDVarint": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowType": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "container", - "1": "workbench", - "2": "furnace", - "3": "enchantment", - "4": "brewing_stand", - "5": "anvil", - "6": "dispenser", - "7": "dropper", - "8": "hopper", - "9": "cauldron", - "10": "minecart_chest", - "11": "minecart_hopper", - "12": "horse", - "13": "beacon", - "14": "structure_editor", - "15": "trading", - "16": "command_block", - "17": "jukebox", - "18": "armor", - "19": "hand", - "20": "compound_creator", - "21": "element_constructor", - "22": "material_reducer", - "23": "lab_table", - "24": "loom", - "25": "lectern", - "26": "grindstone", - "27": "blast_furnace", - "28": "smoker", - "29": "stonecutter", - "30": "cartography", - "31": "hud", - "32": "jigsaw_editor", - "33": "smithing_table", - "-9": "none", - "-1": "inventory" - } - } - ], - "ContainerSlotType": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "anvil_input", - "1": "anvil_material", - "2": "anvil_result", - "3": "smithing_table_input", - "4": "smithing_table_material", - "5": "smithing_table_result", - "6": "armor", - "7": "container", - "8": "beacon_payment", - "9": "brewing_input", - "10": "brewing_result", - "11": "brewing_fuel", - "12": "hotbar_and_inventory", - "13": "crafting_input", - "14": "crafting_output", - "15": "recipe_construction", - "16": "recipe_nature", - "17": "recipe_items", - "18": "recipe_search", - "19": "recipe_search_bar", - "20": "recipe_equipment", - "21": "enchanting_input", - "22": "enchanting_lapis", - "23": "furnace_fuel", - "24": "furnace_ingredient", - "25": "furnace_output", - "26": "horse_equip", - "27": "hotbar", - "28": "inventory", - "29": "shulker", - "30": "trade_ingredient1", - "31": "trade_ingredient2", - "32": "trade_result", - "33": "offhand", - "34": "compcreate_input", - "35": "compcreate_output", - "36": "elemconstruct_output", - "37": "matreduce_input", - "38": "matreduce_output", - "39": "labtable_input", - "40": "loom_input", - "41": "loom_dye", - "42": "loom_material", - "43": "loom_result", - "44": "blast_furnace_ingredient", - "45": "smoker_ingredient", - "46": "trade2_ingredient1", - "47": "trade2_ingredient2", - "48": "trade2_result", - "49": "grindstone_input", - "50": "grindstone_additional", - "51": "grindstone_result", - "52": "stonecutter_input", - "53": "stonecutter_result", - "54": "cartography_input", - "55": "cartography_additional", - "56": "cartography_result", - "57": "barrel", - "58": "cursor", - "59": "creative_output" - } - } - ], - "SoundType": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "ItemUseOn", - "1": "Hit", - "2": "Step", - "3": "Fly", - "4": "Jump", - "5": "Break", - "6": "Place", - "7": "HeavyStep", - "8": "Gallop", - "9": "Fall", - "10": "Ambient", - "11": "AmbientBaby", - "12": "AmbientInWater", - "13": "Breathe", - "14": "Death", - "15": "DeathInWater", - "16": "DeathToZombie", - "17": "Hurt", - "18": "HurtInWater", - "19": "Mad", - "20": "Boost", - "21": "Bow", - "22": "SquishBig", - "23": "SquishSmall", - "24": "FallBig", - "25": "FallSmall", - "26": "Splash", - "27": "Fizz", - "28": "Flap", - "29": "Swim", - "30": "Drink", - "31": "Eat", - "32": "Takeoff", - "33": "Shake", - "34": "Plop", - "35": "Land", - "36": "Saddle", - "37": "Armor", - "38": "MobArmorStandPlace", - "39": "AddChest", - "40": "Throw", - "41": "Attack", - "42": "AttackNoDamage", - "43": "AttackStrong", - "44": "Warn", - "45": "Shear", - "46": "Milk", - "47": "Thunder", - "48": "Explode", - "49": "Fire", - "50": "Ignite", - "51": "Fuse", - "52": "Stare", - "53": "Spawn", - "54": "Shoot", - "55": "BreakBlock", - "56": "Launch", - "57": "Blast", - "58": "LargeBlast", - "59": "Twinkle", - "60": "Remedy", - "61": "Infect", - "62": "LevelUp", - "63": "BowHit", - "64": "BulletHit", - "65": "ExtinguishFire", - "66": "ItemFizz", - "67": "ChestOpen", - "68": "ChestClosed", - "69": "ShulkerBoxOpen", - "70": "ShulkerBoxClosed", - "71": "EnderChestOpen", - "72": "EnderChestClosed", - "73": "PowerOn", - "74": "PowerOff", - "75": "Attach", - "76": "Detach", - "77": "Deny", - "78": "Tripod", - "79": "Pop", - "80": "DropSlot", - "81": "Note", - "82": "Thorns", - "83": "PistonIn", - "84": "PistonOut", - "85": "Portal", - "86": "Water", - "87": "LavaPop", - "88": "Lava", - "89": "Burp", - "90": "BucketFillWater", - "91": "BucketFillLava", - "92": "BucketEmptyWater", - "93": "BucketEmptyLava", - "94": "ArmorEquipChain", - "95": "ArmorEquipDiamond", - "96": "ArmorEquipGeneric", - "97": "ArmorEquipGold", - "98": "ArmorEquipIron", - "99": "ArmorEquipLeather", - "100": "ArmorEquipElytra", - "101": "Record13", - "102": "RecordCat", - "103": "RecordBlocks", - "104": "RecordChirp", - "105": "RecordFar", - "106": "RecordMall", - "107": "RecordMellohi", - "108": "RecordStal", - "109": "RecordStrad", - "110": "RecordWard", - "111": "Record11", - "112": "RecordWait", - "113": "unknown1", - "114": "Flop", - "115": "ElderGuardianCurse", - "116": "MobWarning", - "117": "MobWarningBaby", - "118": "Teleport", - "119": "ShulkerOpen", - "120": "ShulkerClose", - "121": "Haggle", - "122": "HaggleYes", - "123": "HaggleNo", - "124": "HaggleIdle", - "125": "ChorusGrow", - "126": "ChorusDeath", - "127": "Glass", - "128": "PotionBrewed", - "129": "CastSpell", - "130": "PrepareAttack", - "131": "PrepareSummon", - "132": "PrepareWololo", - "133": "Fang", - "134": "Charge", - "135": "CameraTakePicture", - "136": "LeashKnotPlace", - "137": "LeashKnotBreak", - "138": "Growl", - "139": "Whine", - "140": "Pant", - "141": "Purr", - "142": "Purreow", - "143": "DeathMinVolume", - "144": "DeathMidVolume", - "145": "unknown2", - "146": "ImitateCaveSpider", - "147": "ImitateCreeper", - "148": "ImitateElderGuardian", - "149": "ImitateEnderDragon", - "150": "ImitateEnderman", - "151": "unknown3", - "152": "ImitateEvocationIllager", - "153": "ImitateGhast", - "154": "ImitateHusk", - "155": "ImitateIllusionIllager", - "156": "ImitateMagmaCube", - "157": "ImitatePolarBear", - "158": "ImitateShulker", - "159": "ImitateSilverfish", - "160": "ImitateSkeleton", - "161": "ImitateSlime", - "162": "ImitateSpider", - "163": "ImitateStray", - "164": "ImitateVex", - "165": "ImitateVindicationIllager", - "166": "ImitateWitch", - "167": "ImitateWither", - "168": "ImitateWitherSkeleton", - "169": "ImitateWolf", - "170": "ImitateZombie", - "171": "ImitateZombiePigman", - "172": "ImitateZombieVillager", - "173": "BlockEndPortalFrameFill", - "174": "BlockEndPortalSpawn", - "175": "RandomAnvilUse", - "176": "BottleDragonBreath", - "177": "PortalTravel", - "178": "ItemTridentHit", - "179": "ItemTridentReturn", - "180": "ItemTridentRiptide1", - "181": "ItemTridentRiptide2", - "182": "ItemTridentRiptide3", - "183": "ItemTridentThrow", - "184": "ItemTridentThunder", - "185": "ItemTridentHitGround", - "186": "Default", - "187": "BlockFletchingTableUse", - "188": "ElemConstructOpen", - "189": "IceBombHit", - "190": "BalloonPop", - "191": "LtReactionIceBomb", - "192": "LtReactionBleach", - "193": "LtReactionEPaste", - "194": "LtReactionEPaste2", - "195": "LtReactionFertilizer", - "196": "LtReactionFireball", - "197": "LtReactionMgsalt", - "198": "LtReactionMiscfire", - "199": "LtReactionFire", - "200": "LtReactionMiscexplosion", - "201": "LtReactionMiscmystical", - "202": "LtReactionMiscmystical2", - "203": "LtReactionProduct", - "204": "SparklerUse", - "205": "GlowstickUse", - "206": "SparklerActive", - "207": "ConvertToDrowned", - "208": "BucketFillFish", - "209": "BucketEmptyFish", - "210": "BubbleUp", - "211": "BubbleDown", - "212": "BubblePop", - "213": "BubbleUpInside", - "214": "BubbleDownInside", - "215": "HurtBaby", - "216": "DeathBaby", - "217": "StepBaby", - "218": "BabySpawn", - "219": "Born", - "220": "BlockTurtleEggBreak", - "221": "BlockTurtleEggCrack", - "222": "BlockTurtleEggHatch", - "223": "TurtleLayEgg", - "224": "BlockTurtleEggAttack", - "225": "BeaconActivate", - "226": "BeaconAmbient", - "227": "BeaconDeactivate", - "228": "BeaconPower", - "229": "ConduitActivate", - "230": "ConduitAmbient", - "231": "ConduitAttack", - "232": "ConduitDeactivate", - "233": "ConduitShort", - "234": "Swoop", - "235": "BlockBambooSaplingPlace", - "236": "PreSneeze", - "237": "Sneeze", - "238": "AmbientTame", - "239": "Scared", - "240": "BlockScaffoldingClimb", - "241": "CrossbowLoadingStart", - "242": "CrossbowLoadingMiddle", - "243": "CrossbowLoadingEnd", - "244": "CrossbowShoot", - "245": "CrossbowQuickChargeStart", - "246": "CrossbowQuickChargeMiddle", - "247": "CrossbowQuickChargeEnd", - "248": "AmbientAggressive", - "249": "AmbientWorried", - "250": "CantBreed", - "251": "ItemShieldBlock", - "252": "ItemBookPut", - "253": "BlockGrindstoneUse", - "254": "BlockBellHit", - "255": "BlockCampfireCrackle", - "256": "Roar", - "257": "Stun", - "258": "BlockSweetBerryBushHurt", - "259": "BlockSweetBerryBushPick", - "260": "UICartographyTableTakeResult", - "261": "UIStoneCutterTakeResult", - "262": "BlockComposterEmpty", - "263": "BlockComposterFill", - "264": "BlockComposterFillSuccess", - "265": "BlockComposterReady", - "266": "BlockBarrelOpen", - "267": "BlockBarrelClose", - "268": "RaidHorn", - "269": "BlockLoomUse", - "270": "AmbientRaid", - "271": "UICartographyTableUse", - "272": "UIStoneCutterUse", - "273": "UILoomUse", - "274": "SmokerUse", - "275": "BlastFurnaceUse", - "276": "SmithingTableUse", - "277": "Screech", - "278": "Sleep", - "279": "FurnaceUse", - "280": "MooshroomConvert", - "281": "MilkSuspiciously", - "282": "Celebrate", - "283": "JumpPrevent", - "284": "AmbientPollinate", - "285": "BeeHiveDrip", - "286": "BeeHiveEnter", - "287": "BeeHiveExit", - "288": "BeeHiveWork", - "289": "BeeHiveShear", - "290": "HoneyBottleDrink", - "291": "AmbientCave", - "292": "Retreat", - "293": "ConvertToZombified", - "294": "Admire", - "295": "StepLava", - "296": "Tempt", - "297": "Panic", - "298": "Angry", - "299": "AmbientWarpedForest", - "300": "AmbientSoulsandValley", - "301": "AmbientNetherWastes", - "302": "AmbientBasaltDeltas", - "303": "AmbientCrimsonForest", - "304": "RespawnAnchorCharge", - "305": "RespawnAnchorDeplete", - "306": "RespawnAnchorSetSpawn", - "307": "RespawnAnchorAmbient", - "308": "SoulEscapeQuiet", - "309": "SoulEscapeLoud", - "310": "RecordPigstep", - "311": "LinkCompassToLodestone", - "312": "BlockSmithingTableUse", - "313": "EquipNetherite", - "314": "AmbientLoopWarpedForest", - "315": "AmbientLoopSoulsandValley", - "316": "AmbientLoopNetherWastes", - "317": "AmbientLoopBasaltDeltas", - "318": "AmbientLoopCrimsonForest", - "319": "AmbientAdditionWarpedForest", - "320": "AmbientAdditionSoulsandValley", - "321": "AmbientAdditionNetherWastes", - "322": "AmbientAdditionBasaltDeltas", - "323": "AmbientAdditionCrimsonForest", - "324": "SculkSensorPowerOn", - "325": "SculkSensorPowerOff", - "326": "BucketFillPowderSnow", - "327": "BucketEmptyPowderSnow", - "328": "PointedDripstoneCauldronDripWater", - "329": "PointedDripstoneCauldronDripLava", - "330": "PointedDripstoneDripWater", - "331": "PointedDripstoneDripLava", - "332": "CaveVinesPickBerries", - "333": "BigDripleafTiltDown", - "334": "BigDripleafTiltUp", - "335": "unknown335", - "336": "unknown336", - "337": "unknown337", - "338": "unknown338", - "339": "copper_wax_on", - "340": "copper_wax_off", - "341": "scrape", - "342": "player_hurt_drown", - "343": "player_hurt_on_fire", - "344": "player_hurt_freeze", - "345": "use_spyglass", - "346": "stop_using_spyglass", - "347": "amethyst_block_chime", - "348": "ambient_screamer", - "349": "hurt_screamer", - "350": "death_screamer", - "351": "milk_screamer", - "352": "jump_to_block", - "353": "pre_ram", - "354": "pre_ram_screamer", - "355": "ram_impact", - "356": "ram_impact_screamer", - "357": "squid_ink_squirt", - "358": "glow_squid_ink_squirt", - "359": "convert_to_stray", - "360": "Undefined" - } - } - ], - "LegacyEntityType": [ - "mapper", - { - "type": "li32", - "mappings": { - "10": "chicken", - "11": "cow", - "12": "pig", - "13": "sheep", - "14": "wolf", - "15": "villager", - "16": "mooshroom", - "17": "squid", - "18": "rabbit", - "19": "bat", - "20": "iron_golem", - "21": "snow_golem", - "22": "ocelot", - "23": "horse", - "24": "donkey", - "25": "mule", - "26": "skeleton_horse", - "27": "zombie_horse", - "28": "polar_bear", - "29": "llama", - "30": "parrot", - "31": "dolphin", - "32": "zombie", - "33": "creeper", - "34": "skeleton", - "35": "spider", - "36": "zombie_pigman", - "37": "slime", - "38": "enderman", - "39": "silverfish", - "40": "cave_spider", - "41": "ghast", - "42": "magma_cube", - "43": "blaze", - "44": "zombie_villager", - "45": "witch", - "46": "stray", - "47": "husk", - "48": "wither_skeleton", - "49": "guardian", - "50": "elder_guardian", - "51": "npc", - "52": "wither", - "53": "ender_dragon", - "54": "shulker", - "55": "endermite", - "56": "agent", - "57": "vindicator", - "58": "phantom", - "61": "armor_stand", - "62": "tripod_camera", - "63": "player", - "64": "item", - "65": "tnt", - "66": "falling_block", - "67": "moving_block", - "68": "xp_bottle", - "69": "xp_orb", - "70": "eye_of_ender_signal", - "71": "ender_crystal", - "72": "fireworks_rocket", - "73": "thrown_trident", - "74": "turtle", - "75": "cat", - "76": "shulker_bullet", - "77": "fishing_hook", - "78": "chalkboard", - "79": "dragon_fireball", - "80": "arrow", - "81": "snowball", - "82": "egg", - "83": "painting", - "84": "minecart", - "85": "fireball", - "86": "splash_potion", - "87": "ender_pearl", - "88": "leash_knot", - "89": "wither_skull", - "90": "boat", - "91": "wither_skull_dangerous", - "93": "lightning_bolt", - "94": "small_fireball", - "95": "area_effect_cloud", - "96": "hopper_minecart", - "97": "tnt_minecart", - "98": "chest_minecart", - "100": "command_block_minecart", - "101": "lingering_potion", - "102": "llama_spit", - "103": "evocation_fang", - "104": "evocation_illager", - "105": "vex", - "106": "ice_bomb", - "107": "balloon", - "108": "pufferfish", - "109": "salmon", - "110": "drowned", - "111": "tropicalfish", - "112": "cod", - "113": "panda" - } - } - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "login", - "2": "play_status", - "3": "server_to_client_handshake", - "4": "client_to_server_handshake", - "5": "disconnect", - "6": "resource_packs_info", - "7": "resource_pack_stack", - "8": "resource_pack_client_response", - "9": "text", - "10": "set_time", - "11": "start_game", - "12": "add_player", - "13": "add_entity", - "14": "remove_entity", - "15": "add_item_entity", - "17": "take_item_entity", - "18": "move_entity", - "19": "move_player", - "20": "rider_jump", - "21": "update_block", - "22": "add_painting", - "23": "tick_sync", - "24": "level_sound_event_old", - "25": "level_event", - "26": "block_event", - "27": "entity_event", - "28": "mob_effect", - "29": "update_attributes", - "30": "inventory_transaction", - "31": "mob_equipment", - "32": "mob_armor_equipment", - "33": "interact", - "34": "block_pick_request", - "35": "entity_pick_request", - "36": "player_action", - "38": "hurt_armor", - "39": "set_entity_data", - "40": "set_entity_motion", - "41": "set_entity_link", - "42": "set_health", - "43": "set_spawn_position", - "44": "animate", - "45": "respawn", - "46": "container_open", - "47": "container_close", - "48": "player_hotbar", - "49": "inventory_content", - "50": "inventory_slot", - "51": "container_set_data", - "52": "crafting_data", - "53": "crafting_event", - "54": "gui_data_pick_item", - "55": "adventure_settings", - "56": "block_entity_data", - "57": "player_input", - "58": "level_chunk", - "59": "set_commands_enabled", - "60": "set_difficulty", - "61": "change_dimension", - "62": "set_player_game_type", - "63": "player_list", - "64": "simple_event", - "65": "event", - "66": "spawn_experience_orb", - "67": "clientbound_map_item_data", - "68": "map_info_request", - "69": "request_chunk_radius", - "70": "chunk_radius_update", - "71": "item_frame_drop_item", - "72": "game_rules_changed", - "73": "camera", - "74": "boss_event", - "75": "show_credits", - "76": "available_commands", - "77": "command_request", - "78": "command_block_update", - "79": "command_output", - "80": "update_trade", - "81": "update_equipment", - "82": "resource_pack_data_info", - "83": "resource_pack_chunk_data", - "84": "resource_pack_chunk_request", - "85": "transfer", - "86": "play_sound", - "87": "stop_sound", - "88": "set_title", - "89": "add_behavior_tree", - "90": "structure_block_update", - "91": "show_store_offer", - "92": "purchase_receipt", - "93": "player_skin", - "94": "sub_client_login", - "95": "initiate_web_socket_connection", - "96": "set_last_hurt_by", - "97": "book_edit", - "98": "npc_request", - "99": "photo_transfer", - "100": "modal_form_request", - "101": "modal_form_response", - "102": "server_settings_request", - "103": "server_settings_response", - "104": "show_profile", - "105": "set_default_game_type", - "106": "remove_objective", - "107": "set_display_objective", - "108": "set_score", - "109": "lab_table", - "110": "update_block_synced", - "111": "move_entity_delta", - "112": "set_scoreboard_identity", - "113": "set_local_player_as_initialized", - "114": "update_soft_enum", - "115": "network_stack_latency", - "117": "script_custom_event", - "118": "spawn_particle_effect", - "119": "available_entity_identifiers", - "120": "level_sound_event_v2", - "121": "network_chunk_publisher_update", - "122": "biome_definition_list", - "123": "level_sound_event", - "124": "level_event_generic", - "125": "lectern_update", - "126": "video_stream_connect", - "127": "add_ecs_entity", - "128": "remove_ecs_entity", - "129": "client_cache_status", - "130": "on_screen_texture_animation", - "131": "map_create_locked_copy", - "132": "structure_template_data_export_request", - "133": "structure_template_data_export_response", - "134": "update_block_properties", - "135": "client_cache_blob_status", - "136": "client_cache_miss_response", - "137": "education_settings", - "139": "multiplayer_settings", - "140": "settings_command", - "141": "anvil_damage", - "142": "completed_using_item", - "143": "network_settings", - "144": "player_auth_input", - "145": "creative_content", - "146": "player_enchant_options", - "147": "item_stack_request", - "148": "item_stack_response", - "149": "player_armor_damage", - "151": "update_player_game_type", - "153": "position_tracking_db_broadcast", - "154": "position_tracking_db_request", - "156": "packet_violation_warning", - "157": "motion_prediction_hints", - "158": "animate_entity", - "159": "camera_shake", - "160": "player_fog", - "161": "correct_player_move_prediction", - "162": "item_component", - "163": "filter_text_packet", - "164": "debug_renderer", - "165": "sync_entity_property", - "166": "add_volume_entity", - "167": "remove_volume_entity" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "login": "packet_login", - "play_status": "packet_play_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "tick_sync": "packet_tick_sync", - "level_sound_event_old": "packet_level_sound_event_old", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "inventory_transaction": "packet_inventory_transaction", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "block_pick_request": "packet_block_pick_request", - "entity_pick_request": "packet_entity_pick_request", - "player_action": "packet_player_action", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "player_hotbar": "packet_player_hotbar", - "inventory_content": "packet_inventory_content", - "inventory_slot": "packet_inventory_slot", - "container_set_data": "packet_container_set_data", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "gui_data_pick_item": "packet_gui_data_pick_item", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "level_chunk": "packet_level_chunk", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "simple_event": "packet_simple_event", - "event": "packet_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data": "packet_clientbound_map_item_data", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_frame_drop_item": "packet_item_frame_drop_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "boss_event": "packet_boss_event", - "show_credits": "packet_show_credits", - "available_commands": "packet_available_commands", - "command_request": "packet_command_request", - "command_block_update": "packet_command_block_update", - "command_output": "packet_command_output", - "update_trade": "packet_update_trade", - "update_equipment": "packet_update_equipment", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request", - "transfer": "packet_transfer", - "play_sound": "packet_play_sound", - "stop_sound": "packet_stop_sound", - "set_title": "packet_set_title", - "add_behavior_tree": "packet_add_behavior_tree", - "structure_block_update": "packet_structure_block_update", - "show_store_offer": "packet_show_store_offer", - "purchase_receipt": "packet_purchase_receipt", - "player_skin": "packet_player_skin", - "sub_client_login": "packet_sub_client_login", - "initiate_web_socket_connection": "packet_initiate_web_socket_connection", - "set_last_hurt_by": "packet_set_last_hurt_by", - "book_edit": "packet_book_edit", - "npc_request": "packet_npc_request", - "photo_transfer": "packet_photo_transfer", - "modal_form_request": "packet_modal_form_request", - "modal_form_response": "packet_modal_form_response", - "server_settings_request": "packet_server_settings_request", - "server_settings_response": "packet_server_settings_response", - "show_profile": "packet_show_profile", - "set_default_game_type": "packet_set_default_game_type", - "remove_objective": "packet_remove_objective", - "set_display_objective": "packet_set_display_objective", - "set_score": "packet_set_score", - "lab_table": "packet_lab_table", - "update_block_synced": "packet_update_block_synced", - "move_entity_delta": "packet_move_entity_delta", - "set_scoreboard_identity": "packet_set_scoreboard_identity", - "set_local_player_as_initialized": "packet_set_local_player_as_initialized", - "update_soft_enum": "packet_update_soft_enum", - "network_stack_latency": "packet_network_stack_latency", - "script_custom_event": "packet_script_custom_event", - "spawn_particle_effect": "packet_spawn_particle_effect", - "available_entity_identifiers": "packet_available_entity_identifiers", - "level_sound_event_v2": "packet_level_sound_event_v2", - "network_chunk_publisher_update": "packet_network_chunk_publisher_update", - "biome_definition_list": "packet_biome_definition_list", - "level_sound_event": "packet_level_sound_event", - "level_event_generic": "packet_level_event_generic", - "lectern_update": "packet_lectern_update", - "video_stream_connect": "packet_video_stream_connect", - "add_ecs_entity": "packet_add_ecs_entity", - "remove_ecs_entity": "packet_remove_ecs_entity", - "client_cache_status": "packet_client_cache_status", - "on_screen_texture_animation": "packet_on_screen_texture_animation", - "map_create_locked_copy": "packet_map_create_locked_copy", - "structure_template_data_export_request": "packet_structure_template_data_export_request", - "structure_template_data_export_response": "packet_structure_template_data_export_response", - "update_block_properties": "packet_update_block_properties", - "client_cache_blob_status": "packet_client_cache_blob_status", - "client_cache_miss_response": "packet_client_cache_miss_response", - "education_settings": "packet_education_settings", - "multiplayer_settings": "packet_multiplayer_settings", - "settings_command": "packet_settings_command", - "anvil_damage": "packet_anvil_damage", - "completed_using_item": "packet_completed_using_item", - "network_settings": "packet_network_settings", - "player_auth_input": "packet_player_auth_input", - "creative_content": "packet_creative_content", - "player_enchant_options": "packet_player_enchant_options", - "item_stack_request": "packet_item_stack_request", - "item_stack_response": "packet_item_stack_response", - "player_armor_damage": "packet_player_armor_damage", - "update_player_game_type": "packet_update_player_game_type", - "position_tracking_db_request": "packet_position_tracking_db_request", - "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", - "packet_violation_warning": "packet_packet_violation_warning", - "motion_prediction_hints": "packet_motion_prediction_hints", - "animate_entity": "packet_animate_entity", - "camera_shake": "packet_camera_shake", - "player_fog": "packet_player_fog", - "correct_player_move_prediction": "packet_correct_player_move_prediction", - "item_component": "packet_item_component", - "filter_text_packet": "packet_filter_text_packet", - "debug_renderer": "packet_debug_renderer", - "sync_entity_property": "packet_sync_entity_property", - "add_volume_entity": "packet_add_volume_entity", - "remove_volume_entity": "packet_remove_volume_entity" - }, - "default": "void" - } - ] - } - ] - ], - "packet_login": [ - "container", - [ - { - "name": "protocol_version", - "type": "i32" - }, - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "LoginTokens": [ - "container", - [ - { - "name": "identity", - "type": "LittleString" - }, - { - "name": "client", - "type": "LittleString" - } - ] - ], - "packet_play_status": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "i32", - "mappings": { - "0": "login_success", - "1": "failed_client", - "2": "failed_spawn", - "3": "player_spawn", - "4": "failed_invalid_tenant", - "5": "failed_vanilla_edu", - "6": "failed_edu_vanilla", - "7": "failed_server_full" - } - } - ] - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "token", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "behaviour_packs", - "type": "BehaviourPackInfos" - }, - { - "name": "texture_packs", - "type": "TexturePackInfos" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behavior_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "resource_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "refused", - "2": "send_packs", - "3": "have_all_packs", - "4": "completed" - } - } - ] - }, - { - "name": "resourcepackids", - "type": "ResourcePackIds" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "raw", - "1": "chat", - "2": "translation", - "3": "popup", - "4": "jukebox_popup", - "5": "tip", - "6": "system", - "7": "whisper", - "8": "announcement", - "9": "json_whisper", - "10": "json" - } - } - ] - }, - { - "name": "needs_translation", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "chat": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "whisper": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "announcement": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "raw": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "tip": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "system": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json_whisper": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "translation": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "jukebox_popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "xuid", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "zigzag32" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "player_gamemode", - "type": "GameMode" - }, - { - "name": "player_position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "vec2f" - }, - { - "name": "seed", - "type": "zigzag32" - }, - { - "name": "biome_type", - "type": "li16" - }, - { - "name": "biome_name", - "type": "string" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "generator", - "type": "zigzag32" - }, - { - "name": "world_gamemode", - "type": "GameMode" - }, - { - "name": "difficulty", - "type": "zigzag32" - }, - { - "name": "spawn_position", - "type": "BlockCoordinates" - }, - { - "name": "achievements_disabled", - "type": "bool" - }, - { - "name": "day_cycle_stop_time", - "type": "zigzag32" - }, - { - "name": "edu_offer", - "type": "zigzag32" - }, - { - "name": "edu_features_enabled", - "type": "bool" - }, - { - "name": "edu_product_uuid", - "type": "string" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightning_level", - "type": "lf32" - }, - { - "name": "has_confirmed_platform_locked_content", - "type": "bool" - }, - { - "name": "is_multiplayer", - "type": "bool" - }, - { - "name": "broadcast_to_lan", - "type": "bool" - }, - { - "name": "xbox_live_broadcast_mode", - "type": "varint" - }, - { - "name": "platform_broadcast_mode", - "type": "varint" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - { - "name": "gamerules", - "type": "GameRules" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - }, - { - "name": "bonus_chest", - "type": "bool" - }, - { - "name": "map_enabled", - "type": "bool" - }, - { - "name": "permission_level", - "type": "zigzag32" - }, - { - "name": "server_chunk_tick_range", - "type": "li32" - }, - { - "name": "has_locked_behavior_pack", - "type": "bool" - }, - { - "name": "has_locked_resource_pack", - "type": "bool" - }, - { - "name": "is_from_locked_world_template", - "type": "bool" - }, - { - "name": "msa_gamertags_only", - "type": "bool" - }, - { - "name": "is_from_world_template", - "type": "bool" - }, - { - "name": "is_world_template_option_locked", - "type": "bool" - }, - { - "name": "only_spawn_v1_villagers", - "type": "bool" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "limited_world_width", - "type": "li32" - }, - { - "name": "limited_world_length", - "type": "li32" - }, - { - "name": "is_new_nether", - "type": "bool" - }, - { - "name": "experimental_gameplay_override", - "type": "bool" - }, - { - "name": "level_id", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - }, - { - "name": "premium_world_template_id", - "type": "string" - }, - { - "name": "is_trial", - "type": "bool" - }, - { - "name": "movement_authority", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "client", - "1": "server", - "2": "server_with_rewind" - } - } - ] - }, - { - "name": "rewind_history_size", - "type": "zigzag32" - }, - { - "name": "server_authoritative_block_breaking", - "type": "bool" - }, - { - "name": "current_tick", - "type": "li64" - }, - { - "name": "enchantment_seed", - "type": "zigzag32" - }, - { - "name": "block_properties", - "type": "BlockProperties" - }, - { - "name": "itemstates", - "type": "Itemstates" - }, - { - "name": "multiplayer_correlation_id", - "type": "string" - }, - { - "name": "server_authoritative_inventory", - "type": "bool" - }, - { - "name": "engine", - "type": "string" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - }, - { - "name": "links", - "type": "Links" - }, - { - "name": "device_id", - "type": "string" - }, - { - "name": "device_os", - "type": "li32" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "attributes", - "type": "EntityAttributes" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "links", - "type": "Links" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "is_from_fishing", - "type": "bool" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "target", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "Rotation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "normal", - "1": "reset", - "2": "teleport", - "3": "rotation" - } - } - ] - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "ridden_runtime_id", - "type": "varint" - }, - { - "name": "teleport", - "type": [ - "switch", - { - "compareTo": "mode", - "fields": { - "teleport": [ - "container", - [ - { - "name": "cause", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "unknown", - "1": "projectile", - "2": "chorus_fruit", - "3": "command", - "4": "behavior" - } - } - ] - }, - { - "name": "source_entity_type", - "type": "LegacyEntityType" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_rider_jump": [ - "container", - [ - { - "name": "jump_strength", - "type": "zigzag32" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "coordinates", - "type": "vec3f" - }, - { - "name": "direction", - "type": "zigzag32" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_tick_sync": [ - "container", - [ - { - "name": "request_time", - "type": "li64" - }, - { - "name": "response_time", - "type": "li64" - } - ] - ], - "packet_level_sound_event_old": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "zigzag32" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "1000": "sound_click", - "1001": "sound_click_fail", - "1002": "sound_shoot", - "1003": "sound_door", - "1004": "sound_fizz", - "1005": "sound_ignite", - "1007": "sound_ghast", - "1008": "sound_ghast_shoot", - "1009": "sound_blaze_shoot", - "1010": "sound_door_bump", - "1012": "sound_door_crash", - "1018": "sound_enderman_teleport", - "1020": "sound_anvil_break", - "1021": "sound_anvil_use", - "1022": "sound_anvil_fall", - "1030": "sound_pop", - "1032": "sound_portal", - "1040": "sound_itemframe_add_item", - "1041": "sound_itemframe_remove", - "1042": "sound_itemframe_place", - "1043": "sound_itemframe_remove_item", - "1044": "sound_itemframe_rotate_item", - "1050": "sound_camera", - "1051": "sound_orb", - "1052": "sound_totem", - "1060": "sound_armor_stand_break", - "1061": "sound_armor_stand_hit", - "1062": "sound_armor_stand_fall", - "1063": "sound_armor_stand_place", - "1064": "pointed_dripstone_land", - "1065": "dye_used", - "1066": "ink_sack_used", - "2000": "particle_shoot", - "2001": "particle_destroy", - "2002": "particle_splash", - "2003": "particle_eye_despawn", - "2004": "particle_spawn", - "2005": "particle_crop_growth", - "2006": "particle_guardian_curse", - "2007": "particle_death_smoke", - "2008": "particle_block_force_field", - "2009": "particle_projectile_hit", - "2010": "particle_dragon_egg_teleport", - "2011": "particle_crop_eaten", - "2012": "particle_critical", - "2013": "particle_enderman_teleport", - "2014": "particle_punch_block", - "2015": "particle_bubble", - "2016": "particle_evaporate", - "2017": "particle_destroy_armor_stand", - "2018": "particle_breaking_egg", - "2019": "particle_destroy_egg", - "2020": "particle_evaporate_water", - "2021": "particle_destroy_block_no_sound", - "2022": "particle_knockback_roar", - "2023": "particle_teleport_trail", - "2024": "particle_point_cloud", - "2025": "particle_explosion", - "2026": "particle_block_explosion", - "2027": "particle_vibration_signal", - "2028": "particle_dripstone_drip", - "2029": "particle_fizz_effect", - "2030": "particle_wax_on", - "2031": "particle_wax_off", - "2032": "particle_scrape", - "2033": "particle_electric_spark", - "3001": "start_rain", - "3002": "start_thunder", - "3003": "stop_rain", - "3004": "stop_thunder", - "3005": "pause_game", - "3006": "pause_game_no_screen", - "3007": "set_game_speed", - "3500": "redstone_trigger", - "3501": "cauldron_explode", - "3502": "cauldron_dye_armor", - "3503": "cauldron_clean_armor", - "3504": "cauldron_fill_potion", - "3505": "cauldron_take_potion", - "3506": "cauldron_fill_water", - "3507": "cauldron_take_water", - "3508": "cauldron_add_dye", - "3509": "cauldron_clean_banner", - "3600": "block_start_break", - "3601": "block_stop_break", - "4000": "set_data", - "9800": "players_sleeping", - "16384": "add_particle_mask" - } - } - ] - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "sound", - "1": "change_state" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "jump", - "2": "hurt_animation", - "3": "death_animation", - "4": "arm_swing", - "5": "stop_attack", - "6": "tame_fail", - "7": "tame_success", - "8": "shake_wet", - "9": "use_item", - "10": "eat_grass_animation", - "11": "fish_hook_bubble", - "12": "fish_hook_position", - "13": "fish_hook_hook", - "14": "fish_hook_tease", - "15": "squid_ink_cloud", - "16": "zombie_villager_cure", - "18": "respawn", - "19": "iron_golem_offer_flower", - "20": "iron_golem_withdraw_flower", - "21": "love_particles", - "22": "villager_angry", - "23": "villager_happy", - "24": "witch_spell_particles", - "25": "firework_particles", - "26": "in_love_particles", - "27": "silverfish_spawn_animation", - "28": "guardian_attack", - "29": "witch_drink_potion", - "30": "witch_throw_potion", - "31": "minecart_tnt_prime_fuse", - "32": "creeper_prime_fuse", - "33": "air_supply_expired", - "34": "player_add_xp_levels", - "35": "elder_guardian_curse", - "36": "agent_arm_swing", - "37": "ender_dragon_death", - "38": "dust_particles", - "39": "arrow_shake", - "57": "eating_item", - "60": "baby_animal_feed", - "61": "death_smoke_cloud", - "62": "complete_trade", - "63": "remove_leash", - "65": "consume_totem", - "66": "player_check_treasure_hunter_achievement", - "67": "entity_spawn", - "68": "dragon_puke", - "69": "item_entity_merge", - "70": "start_swim", - "71": "balloon_pop", - "72": "treasure_hunt", - "73": "agent_summon", - "74": "charged_crossbow", - "75": "fall" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "zigzag32" - }, - { - "name": "amplifier", - "type": "zigzag32" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "zigzag32" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "attributes", - "type": "PlayerAttributes" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_inventory_transaction": [ - "container", - [ - { - "name": "transaction", - "type": "Transaction" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "window_id", - "type": "WindowID" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "helmet", - "type": "Item" - }, - { - "name": "chestplate", - "type": "Item" - }, - { - "name": "leggings", - "type": "Item" - }, - { - "name": "boots", - "type": "Item" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "3": "leave_vehicle", - "4": "mouse_over_entity", - "6": "open_inventory" - } - } - ] - }, - { - "name": "target_entity_id", - "type": "varint64" - }, - { - "name": "position", - "type": [ - "switch", - { - "compareTo": "action_id", - "fields": { - "mouse_over_entity": "vec3f", - "leave_vehicle": "vec3f" - }, - "default": "void" - } - ] - } - ] - ], - "packet_block_pick_request": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "add_user_data", - "type": "bool" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_entity_pick_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "lu64" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "action", - "type": "Action" - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "tick", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "link", - "type": "Link" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "spawn_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "player", - "1": "world" - } - } - ] - }, - { - "name": "player_position", - "type": "BlockCoordinates" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "world_position", - "type": "BlockCoordinates" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "none", - "1": "swing_arm", - "2": "unknown", - "3": "wake_up", - "4": "critical_hit", - "5": "magic_critical_hit", - "6": "row_right", - "7": "row_left" - } - } - ] - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "state", - "type": "u8" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "runtime_entity_id", - "type": "zigzag64" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "server", - "type": "bool" - } - ] - ], - "packet_player_hotbar": [ - "container", - [ - { - "name": "selected_slot", - "type": "varint" - }, - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "select_slot", - "type": "bool" - } - ] - ], - "packet_inventory_content": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "input", - "type": "ItemStacks" - } - ] - ], - "packet_inventory_slot": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "Item" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "property", - "type": "zigzag32" - }, - { - "name": "value", - "type": "zigzag32" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "Recipes" - }, - { - "name": "potion_type_recipes", - "type": "PotionTypeRecipes" - }, - { - "name": "potion_container_recipes", - "type": "PotionContainerChangeRecipes" - }, - { - "name": "is_clean", - "type": "bool" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "recipe_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "inventory", - "1": "crafting", - "2": "workbench" - } - } - ] - }, - { - "name": "recipe_id", - "type": "uuid" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "result", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - } - ] - ], - "packet_gui_data_pick_item": [ - "container", - [ - { - "name": "item_name", - "type": "string" - }, - { - "name": "item_effects", - "type": "string" - }, - { - "name": "hotbar_slot", - "type": "li32" - } - ] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "AdventureFlags" - }, - { - "name": "command_permission", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "operator", - "2": "host", - "3": "automation", - "4": "admin" - } - } - ] - }, - { - "name": "action_permissions", - "type": "ActionPermissions" - }, - { - "name": "permission_level", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "visitor", - "1": "member", - "2": "operator", - "3": "custom" - } - } - ] - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "jumping", - "type": "bool" - }, - { - "name": "sneaking", - "type": "bool" - } - ] - ], - "packet_level_chunk": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "sub_chunk_count", - "type": "varint" - }, - { - "name": "cache_enabled", - "type": "bool" - }, - { - "name": "blobs", - "type": [ - "switch", - { - "compareTo": "cache_enabled", - "fields": { - "true": [ - "container", - [ - { - "name": "hashes", - "type": [ - "array", - { - "countType": "varint", - "type": "lu64" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "respawn", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "PlayerRecords" - } - ] - ], - "packet_simple_event": [ - "container", - [ - { - "name": "event_type", - "type": "lu16" - } - ] - ], - "packet_event": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint64" - }, - { - "name": "event_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "achievement_awarded", - "1": "entity_interact", - "2": "portal_built", - "3": "portal_used", - "4": "mob_killed", - "5": "cauldron_used", - "6": "player_death", - "7": "boss_killed", - "8": "agent_command", - "9": "agent_created", - "10": "banner_pattern_removed", - "11": "commaned_executed", - "12": "fish_bucketed", - "13": "mob_born", - "14": "pet_died", - "15": "cauldron_block_used", - "16": "composter_block_used", - "17": "bell_block_used", - "18": "actor_definition", - "19": "raid_update", - "20": "player_movement_anomaly", - "21": "player_moement_corrected", - "22": "honey_harvested", - "23": "target_block_hit", - "24": "piglin_barter", - "25": "waxed_or_unwaxed_copper" - } - } - ] - }, - { - "name": "use_player_id", - "type": "u8" - }, - { - "name": "event_data", - "type": "restBuffer" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ], - "packet_clientbound_map_item_data": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - }, - { - "name": "update_flags", - "type": "UpdateMapFlags" - }, - { - "name": "dimension", - "type": "u8" - }, - { - "name": "locked", - "type": "bool" - }, - { - "name": "included_in", - "type": [ - "switch", - { - "compareTo": "update_flags.initialisation", - "fields": { - "true": [ - "array", - { - "countType": "varint", - "type": "zigzag64" - } - ] - }, - "default": "void" - } - ] - }, - { - "name": "scale", - "type": [ - "switch", - { - "compareTo": "update_flags.initialisation || update_flags.decoration || update_flags.texture", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "tracked", - "type": [ - "switch", - { - "compareTo": "update_flags.decoration", - "fields": { - "true": [ - "container", - [ - { - "name": "objects", - "type": [ - "array", - { - "countType": "varint", - "type": "TrackedObject" - } - ] - }, - { - "name": "decorations", - "type": [ - "array", - { - "countType": "varint", - "type": "MapDecoration" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "texture", - "type": [ - "switch", - { - "compareTo": "update_flags.texture", - "fields": { - "true": [ - "container", - [ - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "x_offset", - "type": "zigzag32" - }, - { - "name": "y_offset", - "type": "zigzag32" - }, - { - "name": "pixels", - "type": [ - "array", - { - "countType": "varint", - "type": "varint" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_item_frame_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - } - ] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "GameRules" - } - ] - ], - "packet_camera": [ - "container", - [ - { - "name": "camera_entity_unique_id", - "type": "zigzag64" - }, - { - "name": "target_player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_boss_event": [ - "container", - [ - { - "name": "boss_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "show_bar", - "1": "register_player", - "2": "hide_bar", - "3": "unregister_player", - "4": "set_bar_progress", - "5": "set_bar_title", - "6": "update_properties", - "7": "texture" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "show_bar": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "progress", - "type": "lf32" - }, - { - "name": "screen_darkening", - "type": "li16" - }, - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "register_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "unregister_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "set_bar_progress": [ - "container", - [ - { - "name": "progress", - "type": "lf32" - } - ] - ], - "set_bar_title": [ - "container", - [ - { - "name": "title", - "type": "string" - } - ] - ], - "update_properties": [ - "container", - [ - { - "name": "screen_darkening", - "type": "li16" - }, - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "texture": [ - "container", - [ - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_show_credits": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "status", - "type": "zigzag32" - } - ] - ], - "packet_available_commands": [ - "container", - [ - { - "name": "values_len", - "type": "varint" - }, - { - "name": "_enum_type", - "type": [ - "enum_size_based_on_values_len" - ] - }, - { - "name": "enum_values", - "type": [ - "array", - { - "count": "values_len", - "type": "string" - } - ] - }, - { - "name": "suffixes", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - }, - { - "name": "enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "switch", - { - "compareTo": "../_enum_type", - "fields": { - "byte": "u8", - "short": "lu16", - "int": "lu32" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "command_data", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "description", - "type": "string" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "permission_level", - "type": "u8" - }, - { - "name": "alias", - "type": "li32" - }, - { - "name": "overloads", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "paramater_name", - "type": "string" - }, - { - "name": "value_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "1": "int", - "2": "float", - "3": "value", - "4": "wildcard_int", - "5": "operator", - "6": "target", - "16": "file_path", - "32": "string", - "40": "position", - "44": "message", - "46": "raw_text", - "50": "json", - "63": "command" - } - } - ] - }, - { - "name": "enum_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "16": "valid", - "32": "enum", - "256": "suffixed", - "1024": "soft_enum" - } - } - ] - }, - { - "name": "optional", - "type": "bool" - }, - { - "name": "options", - "type": "CommandFlags" - } - ] - ] - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "dynamic_enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "enum_constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "value_index", - "type": "li32" - }, - { - "name": "enum_index", - "type": "li32" - }, - { - "name": "constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "constraint", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "cheats_enabled", - "1": "operator_permissions", - "2": "host_permissions" - } - } - ] - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_command_request": [ - "container", - [ - { - "name": "command", - "type": "string" - }, - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "interval", - "type": "bool" - } - ] - ], - "packet_command_block_update": [ - "container", - [ - { - "name": "is_block", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "is_block", - "fields": { - "true": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "impulse", - "1": "repeat", - "2": "chain" - } - } - ] - }, - { - "name": "needs_redstone", - "type": "bool" - }, - { - "name": "conditional", - "type": "bool" - } - ] - ] - }, - "default": [ - "container", - [ - { - "name": "minecart_entity_runtime_id", - "type": "varint64" - } - ] - ] - } - ] - }, - { - "name": "command", - "type": "string" - }, - { - "name": "last_output", - "type": "string" - }, - { - "name": "name", - "type": "string" - }, - { - "name": "should_track_output", - "type": "bool" - }, - { - "name": "tick_delay", - "type": "li32" - }, - { - "name": "execute_on_first_tick", - "type": "bool" - } - ] - ], - "packet_command_output": [ - "container", - [ - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "output_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "last", - "2": "silent", - "3": "all", - "4": "data_set" - } - } - ] - }, - { - "name": "success_count", - "type": "varint" - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "success", - "type": "bool" - }, - { - "name": "message_id", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "data_set", - "type": [ - "switch", - { - "compareTo": "output_type", - "fields": { - "data_set": "string" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_trade": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "varint" - }, - { - "name": "trade_tier", - "type": "varint" - }, - { - "name": "villager_unique_id", - "type": "varint64" - }, - { - "name": "entity_unique_id", - "type": "varint64" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "new_trading_ui", - "type": "bool" - }, - { - "name": "economic_trades", - "type": "bool" - }, - { - "name": "offers", - "type": "nbt" - } - ] - ], - "packet_update_equipment": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "inventory", - "type": "nbt" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "max_chunk_size", - "type": "lu32" - }, - { - "name": "chunk_count", - "type": "lu32" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "hash", - "type": "ByteArray" - }, - { - "name": "is_premium", - "type": "bool" - }, - { - "name": "pack_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "addon", - "2": "cached", - "3": "copy_protected", - "4": "behavior", - "5": "persona_piece", - "6": "resources", - "7": "skins", - "8": "world_template" - } - } - ] - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - }, - { - "name": "progress", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "server_address", - "type": "string" - }, - { - "name": "port", - "type": "lu16" - } - ] - ], - "packet_play_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "volume", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - } - ] - ], - "packet_stop_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "stop_all", - "type": "bool" - } - ] - ], - "packet_set_title": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "clear", - "1": "reset", - "2": "set_title", - "3": "set_subtitle", - "4": "action_bar_message", - "5": "set_durations", - "6": "set_title_json", - "7": "set_subtitle_json", - "8": "action_bar_message_json" - } - } - ] - }, - { - "name": "text", - "type": "string" - }, - { - "name": "fade_in_time", - "type": "zigzag32" - }, - { - "name": "stay_time", - "type": "zigzag32" - }, - { - "name": "fade_out_time", - "type": "zigzag32" - } - ] - ], - "packet_add_behavior_tree": [ - "container", - [ - { - "name": "behaviortree", - "type": "string" - } - ] - ], - "packet_structure_block_update": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "structure_name", - "type": "string" - }, - { - "name": "data_field", - "type": "string" - }, - { - "name": "include_players", - "type": "bool" - }, - { - "name": "show_bounding_box", - "type": "bool" - }, - { - "name": "structure_block_type", - "type": "zigzag32" - }, - { - "name": "settings", - "type": "StructureBlockSettings" - }, - { - "name": "redstone_save_mode", - "type": "zigzag32" - }, - { - "name": "should_trigger", - "type": "bool" - } - ] - ], - "packet_show_store_offer": [ - "container", - [ - { - "name": "offer_id", - "type": "string" - }, - { - "name": "show_all", - "type": "bool" - } - ] - ], - "packet_purchase_receipt": [ - "container", - [ - { - "name": "receipts", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_player_skin": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "skin", - "type": "Skin" - }, - { - "name": "skin_name", - "type": "string" - }, - { - "name": "old_skin_name", - "type": "string" - }, - { - "name": "is_verified", - "type": "bool" - } - ] - ], - "packet_sub_client_login": [ - "container", - [ - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "packet_initiate_web_socket_connection": [ - "container", - [ - { - "name": "server", - "type": "string" - } - ] - ], - "packet_set_last_hurt_by": [ - "container", - [ - { - "name": "entity_type", - "type": "varint" - } - ] - ], - "packet_book_edit": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "replace_page", - "1": "add_page", - "2": "delete_page", - "3": "swap_pages", - "4": "sign" - } - } - ] - }, - { - "name": "slot", - "type": "u8" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "replace_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "add_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "delete_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - } - ] - ], - "swap_pages": [ - "container", - [ - { - "name": "page1", - "type": "u8" - }, - { - "name": "page2", - "type": "u8" - } - ] - ], - "sign": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "author", - "type": "string" - }, - { - "name": "xuid", - "type": "string" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_npc_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "request_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "set_actions", - "1": "execute_action", - "2": "execute_closing_commands", - "3": "set_name", - "4": "set_skin", - "5": "set_interaction_text" - } - } - ] - }, - { - "name": "command", - "type": "string" - }, - { - "name": "action_type", - "type": "u8" - } - ] - ], - "packet_photo_transfer": [ - "container", - [ - { - "name": "image_name", - "type": "string" - }, - { - "name": "image_data", - "type": "string" - }, - { - "name": "book_id", - "type": "string" - } - ] - ], - "packet_modal_form_request": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_modal_form_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_server_settings_request": [ - "container", - [] - ], - "packet_server_settings_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_show_profile": [ - "container", - [ - { - "name": "xuid", - "type": "string" - } - ] - ], - "packet_set_default_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_remove_objective": [ - "container", - [ - { - "name": "objective_name", - "type": "string" - } - ] - ], - "packet_set_display_objective": [ - "container", - [ - { - "name": "display_slot", - "type": "string" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "criteria_name", - "type": "string" - }, - { - "name": "sort_order", - "type": "zigzag32" - } - ] - ], - "packet_set_score": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "change", - "1": "remove" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "../action", - "fields": { - "change": [ - "container", - [ - { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": "zigzag64", - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "custom_name", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "fake_player": "string" - }, - "default": "void" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_lab_table": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "combine", - "1": "react" - } - } - ] - }, - { - "name": "position", - "type": "vec3u" - }, - { - "name": "reaction_type", - "type": "u8" - } - ] - ], - "packet_update_block_synced": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "transition_type", - "type": [ - "mapper", - { - "type": "varint64", - "mappings": { - "0": "entity", - "1": "create", - "2": "destroy" - } - } - ] - } - ] - ], - "packet_move_entity_delta": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "DeltaMoveFlags" - }, - { - "name": "x", - "type": [ - "switch", - { - "compareTo": "flags.has_x", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "y", - "type": [ - "switch", - { - "compareTo": "flags.has_y", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "z", - "type": [ - "switch", - { - "compareTo": "flags.has_z", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "rot_x", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_x", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_y", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_y", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_z", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_z", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_scoreboard_identity": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "register_identity", - "1": "clear_identity" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "../action", - "fields": { - "register_identity": "zigzag64" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_set_local_player_as_initialized": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_update_soft_enum": [ - "container", - [] - ], - "packet_network_stack_latency": [ - "container", - [ - { - "name": "timestamp", - "type": "lu64" - }, - { - "name": "needs_response", - "type": "u8" - } - ] - ], - "packet_script_custom_event": [ - "container", - [ - { - "name": "event_name", - "type": "string" - }, - { - "name": "event_data", - "type": "string" - } - ] - ], - "packet_spawn_particle_effect": [ - "container", - [ - { - "name": "dimension", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "particle_name", - "type": "string" - } - ] - ], - "packet_available_entity_identifiers": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event_v2": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_network_chunk_publisher_update": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "radius", - "type": "varint" - } - ] - ], - "packet_biome_definition_list": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "SoundType" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "extra_data", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event_generic": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "nbt", - "type": "nbtLoop" - } - ] - ], - "packet_lectern_update": [ - "container", - [ - { - "name": "page", - "type": "u8" - }, - { - "name": "page_count", - "type": "u8" - }, - { - "name": "position", - "type": "vec3i" - }, - { - "name": "drop_book", - "type": "bool" - } - ] - ], - "packet_video_stream_connect": [ - "container", - [ - { - "name": "server_uri", - "type": "string" - }, - { - "name": "frame_send_frequency", - "type": "lf32" - }, - { - "name": "action", - "type": "u8" - }, - { - "name": "resolution_x", - "type": "li32" - }, - { - "name": "resolution_y", - "type": "li32" - } - ] - ], - "packet_add_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_remove_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_client_cache_status": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_on_screen_texture_animation": [ - "container", - [ - { - "name": "animation_type", - "type": "lu32" - } - ] - ], - "packet_map_create_locked_copy": [ - "container", - [ - { - "name": "original_map_id", - "type": "zigzag64" - }, - { - "name": "new_map_id", - "type": "zigzag64" - } - ] - ], - "packet_structure_template_data_export_request": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "settings", - "type": "StructureBlockSettings" - }, - { - "name": "request_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "export_from_save", - "2": "export_from_load", - "3": "query_saved_structure" - } - } - ] - } - ] - ], - "packet_structure_template_data_export_response": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "success", - "type": "bool" - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "success", - "fields": { - "true": "nbt" - }, - "default": "void" - } - ] - }, - { - "name": "response_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "export", - "2": "query" - } - } - ] - } - ] - ], - "packet_update_block_properties": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_client_cache_blob_status": [ - "container", - [ - { - "name": "misses", - "type": "varint" - }, - { - "name": "haves", - "type": "varint" - }, - { - "name": "missing", - "type": [ - "array", - { - "count": "misses", - "type": "lu64" - } - ] - }, - { - "name": "have", - "type": [ - "array", - { - "count": "haves", - "type": "lu64" - } - ] - } - ] - ], - "packet_client_cache_miss_response": [ - "container", - [ - { - "name": "blobs", - "type": [ - "array", - { - "countType": "varint", - "type": "Blob" - } - ] - } - ] - ], - "packet_education_settings": [ - "container", - [ - { - "name": "CodeBuilderDefaultURI", - "type": "string" - }, - { - "name": "CodeBuilderTitle", - "type": "string" - }, - { - "name": "CanResizeCodeBuilder", - "type": "bool" - }, - { - "name": "HasOverrideURI", - "type": "bool" - }, - { - "name": "OverrideURI", - "type": [ - "switch", - { - "compareTo": "HasOverrideURI", - "fields": { - "true": "string" - }, - "default": "void" - } - ] - }, - { - "name": "HasQuiz", - "type": "bool" - } - ] - ], - "packet_multiplayer_settings": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "enable_multiplayer", - "1": "disable_multiplayer", - "2": "refresh_join_code" - } - } - ] - } - ] - ], - "packet_settings_command": [ - "container", - [ - { - "name": "command_line", - "type": "string" - }, - { - "name": "suppress_output", - "type": "bool" - } - ] - ], - "packet_anvil_damage": [ - "container", - [ - { - "name": "damage", - "type": "u8" - }, - { - "name": "position", - "type": "BlockCoordinates" - } - ] - ], - "packet_completed_using_item": [ - "container", - [ - { - "name": "used_item_id", - "type": "li16" - }, - { - "name": "use_method", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "equip_armor", - "1": "eat", - "2": "attack", - "3": "consume", - "4": "throw", - "5": "shoot", - "6": "place", - "7": "fill_bottle", - "8": "fill_bucket", - "9": "pour_bucket", - "10": "use_tool", - "11": "interact", - "12": "retrieved", - "13": "dyed", - "14": "traded" - } - } - ] - } - ] - ], - "packet_network_settings": [ - "container", - [ - { - "name": "compression_threshold", - "type": "u16" - } - ] - ], - "packet_player_auth_input": [ - "container", - [ - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "move_vector", - "type": "vec2f" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "input_data", - "type": "InputFlag" - }, - { - "name": "input_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "unknown", - "1": "mouse", - "2": "touch", - "3": "game_pad", - "4": "motion_controller" - } - } - ] - }, - { - "name": "play_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "teaser", - "2": "screen", - "3": "viewer", - "4": "reality", - "5": "placement", - "6": "living_room", - "7": "exit_level", - "8": "exit_level_living_room", - "9": "num_modes" - } - } - ] - }, - { - "name": "gaze_direction", - "type": [ - "switch", - { - "compareTo": "play_mode", - "fields": { - "reality": "vec3f" - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "transaction", - "type": [ - "switch", - { - "compareTo": "input_data.item_interact", - "fields": { - "true": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "data", - "type": "TransactionUseItem" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "item_stack_request", - "type": [ - "switch", - { - "compareTo": "input_data.item_stack_request", - "fields": { - "true": "ItemStackRequest" - }, - "default": "void" - } - ] - }, - { - "name": "block_action", - "type": [ - "switch", - { - "compareTo": "input_data.block_action", - "fields": { - "true": [ - "array", - { - "countType": "zigzag32", - "type": [ - "container", - [ - { - "name": "action", - "type": "Action" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "action", - "fields": { - "start_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "abort_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "crack_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "predict_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "continue_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_creative_content": [ - "container", - [ - { - "name": "items", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "entry_id", - "type": "varint" - }, - { - "name": "item", - "type": "ItemLegacy" - } - ] - ] - } - ] - } - ] - ], - "packet_player_enchant_options": [ - "container", - [ - { - "name": "options", - "type": [ - "array", - { - "countType": "varint", - "type": "EnchantOption" - } - ] - } - ] - ], - "packet_item_stack_request": [ - "container", - [ - { - "name": "requests", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemStackRequest" - } - ] - } - ] - ], - "packet_item_stack_response": [ - "container", - [ - { - "name": "responses", - "type": "ItemStackResponses" - } - ] - ], - "packet_player_armor_damage": [ - "container", - [ - { - "name": "type", - "type": "ArmorDamageType" - }, - { - "name": "helmet_damage", - "type": [ - "switch", - { - "compareTo": "type.head", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "chestplate_damage", - "type": [ - "switch", - { - "compareTo": "type.chest", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "leggings_damage", - "type": [ - "switch", - { - "compareTo": "type.legs", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "boots_damage", - "type": [ - "switch", - { - "compareTo": "type.feet", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - }, - { - "name": "player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_position_tracking_db_request": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "query" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - } - ] - ], - "packet_position_tracking_db_broadcast": [ - "container", - [ - { - "name": "broadcast_action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "update", - "1": "destory", - "2": "not_found" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_packet_violation_warning": [ - "container", - [ - { - "name": "violation_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "malformed" - } - } - ] - }, - { - "name": "severity", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "warning", - "1": "final_warning", - "2": "terminating" - } - } - ] - }, - { - "name": "packet_id", - "type": "zigzag32" - }, - { - "name": "reason", - "type": "string" - } - ] - ], - "packet_motion_prediction_hints": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - } - ] - ], - "packet_animate_entity": [ - "container", - [ - { - "name": "animation", - "type": "string" - }, - { - "name": "next_state", - "type": "string" - }, - { - "name": "stop_condition", - "type": "string" - }, - { - "name": "controller", - "type": "string" - }, - { - "name": "blend_out_time", - "type": "lf32" - }, - { - "name": "runtime_entity_ids", - "type": [ - "array", - { - "countType": "varint", - "type": "varint64" - } - ] - } - ] - ], - "packet_camera_shake": [ - "container", - [ - { - "name": "intensity", - "type": "lf32" - }, - { - "name": "duration", - "type": "lf32" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "stop" - } - } - ] - } - ] - ], - "packet_player_fog": [ - "container", - [ - { - "name": "stack", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_correct_player_move_prediction": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_item_component": [ - "container", - [ - { - "name": "entries", - "type": "ItemComponentList" - } - ] - ], - "packet_filter_text_packet": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "from_server", - "type": "bool" - } - ] - ], - "packet_debug_renderer": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "1": "clear", - "2": "add_cube" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "clear": "void", - "add_cube": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "red", - "type": "lf32" - }, - { - "name": "green", - "type": "lf32" - }, - { - "name": "blue", - "type": "lf32" - }, - { - "name": "alpha", - "type": "lf32" - }, - { - "name": "duration", - "type": "li64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_sync_entity_property": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_add_volume_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint64" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_remove_volume_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint64" - } - ] - ], - "string": [ - "pstring", - { - "countType": "varint" - } - ], - "ByteArray": [ - "buffer", - { - "countType": "varint" - } - ], - "SignedByteArray": [ - "buffer", - { - "countType": "zigzag32" - } - ], - "LittleString": [ - "pstring", - { - "countType": "li32" - } - ], - "ShortArray": [ - "buffer", - { - "countType": "li16" - } - ], - "MetadataFlags1": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "onfire", - "sneaking", - "riding", - "sprinting", - "action", - "invisible", - "tempted", - "inlove", - "saddled", - "powered", - "ignited", - "baby", - "converting", - "critical", - "can_show_nametag", - "always_show_nametag", - "no_ai", - "silent", - "wallclimbing", - "can_climb", - "swimmer", - "can_fly", - "walker", - "resting", - "sitting", - "angry", - "interested", - "charged", - "tamed", - "orphaned", - "leashed", - "sheared", - "gliding", - "elder", - "moving", - "breathing", - "chested", - "stackable", - "showbase", - "rearing", - "vibrating", - "idling", - "evoker_spell", - "charge_attack", - "wasd_controlled", - "can_power_jump", - "linger", - "has_collision", - "affected_by_gravity", - "fire_immune", - "dancing", - "enchanted", - "show_trident_rope", - "container_private", - "transforming", - "spin_attack", - "swimming", - "bribed", - "pregnant", - "laying_egg", - "rider_can_pick", - "transition_sitting", - "eating", - "laying_down" - ] - } - ], - "MetadataFlags2": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "sneezing", - "trusting", - "rolling", - "scared", - "in_scaffolding", - "over_scaffolding", - "fall_through_scaffolding", - "blocking", - "transition_blocking", - "blocked_using_shield", - "blocked_using_damaged_shield", - "sleeping", - "wants_to_wake", - "trade_interest", - "door_breaker", - "breaking_obstruction", - "door_opener", - "illager_captain", - "stunned", - "roaring", - "delayed_attacking", - "avoiding_mobs", - "avoiding_block", - "facing_target_to_range_attack", - "hidden_when_invisible", - "is_in_ui", - "stalking", - "emoting", - "celebrating", - "admiring", - "celebrating_special", - "unknown95", - "ram_attack", - "playing_dead" - ] - } - ], - "UpdateBlockFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "neighbors": 1, - "network": 2, - "no_graphic": 4, - "unused": 8, - "priority": 16 - } - } - ], - "AdventureFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "world_immutable": 1, - "no_pvp": 2, - "auto_jump": 32, - "allow_flight": 64, - "no_clip": 128, - "world_builder": 256, - "flying": 512, - "muted": 1024 - } - } - ], - "ActionPermissions": [ - "bitflags", - { - "type": "varint", - "flags": { - "mine": 65537, - "doors_and_switches": 65538, - "open_containers": 65540, - "attack_players": 65544, - "attack_mobs": 65552, - "operator": 65568, - "teleport": 65664, - "build": 65792, - "default": 66048 - } - } - ], - "UpdateMapFlags": [ - "bitflags", - { - "type": "varint", - "flags": [ - "void", - "texture", - "decoration", - "initialisation" - ] - } - ], - "CommandFlags": [ - "bitfield", - [ - { - "name": "unused", - "size": 6, - "signed": false - }, - { - "name": "has_semantic_constraint", - "size": 1, - "signed": false - }, - { - "name": "collapse_enum", - "size": 1, - "signed": false - } - ] - ], - "DeltaMoveFlags": [ - "bitflags", - { - "type": "lu16", - "flags": { - "has_x": 1, - "has_y": 2, - "has_z": 4, - "has_rot_x": 8, - "has_rot_y": 16, - "has_rot_z": 32, - "on_ground": 64, - "teleport": 128, - "force_move": 256 - } - } - ], - "InputFlag": [ - "bitflags", - { - "type": "varint64", - "big": true, - "flags": [ - "ascend", - "descend", - "north_jump", - "jump_down", - "sprint_down", - "change_height", - "jumping", - "auto_jumping_in_water", - "sneaking", - "sneak_down", - "up", - "down", - "left", - "right", - "up_left", - "up_right", - "want_up", - "want_down", - "want_down_slow", - "want_up_slow", - "sprinting", - "ascend_scaffolding", - "descend_scaffolding", - "sneak_toggle_down", - "persist_sneak", - "start_sprinting", - "stop_sprinting", - "start_sneaking", - "stop_sneaking", - "start_swimming", - "stop_swimming", - "start_jumping", - "start_gliding", - "stop_gliding", - "item_interact", - "block_action", - "item_stack_request" - ] - } - ], - "ArmorDamageType": [ - "bitflags", - { - "type": "u8", - "flags": { - "head": 1, - "chest": 2, - "legs": 4, - "feet": 8 - } - } - ] - } -} \ No newline at end of file diff --git a/data/1.17.10/protocol.json b/data/1.17.10/protocol.json deleted file mode 100644 index 21d4fac..0000000 --- a/data/1.17.10/protocol.json +++ /dev/null @@ -1,9081 +0,0 @@ -{ - "types": { - "varint64": "native", - "zigzag32": "native", - "zigzag64": "native", - "uuid": "native", - "byterot": "native", - "bitflags": "native", - "restBuffer": "native", - "encapsulated": "native", - "nbt": "native", - "lnbt": "native", - "nbtLoop": "native", - "enum_size_based_on_values_len": "native", - "MapInfo": "native", - "BehaviourPackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - } - ] - ] - } - ], - "TexturePackInfos": [ - "array", - { - "countType": "li16", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "content_key", - "type": "string" - }, - { - "name": "sub_pack_name", - "type": "string" - }, - { - "name": "content_identity", - "type": "string" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "rtx_enabled", - "type": "bool" - } - ] - ] - } - ], - "ResourcePackIdVersions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "uuid", - "type": "string" - }, - { - "name": "version", - "type": "string" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "ResourcePackIds": [ - "array", - { - "countType": "li16", - "type": "string" - } - ], - "Experiment": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "enabled", - "type": "bool" - } - ] - ], - "Experiments": [ - "array", - { - "countType": "li32", - "type": "Experiment" - } - ], - "GameMode": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "survival", - "1": "creative", - "2": "adventure", - "3": "survival_spectator", - "4": "creative_spectator", - "5": "fallback" - } - } - ], - "GameRule": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "editable", - "type": "bool" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "bool", - "2": "int", - "3": "float" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "bool": "bool", - "int": "zigzag32", - "float": "lf32" - }, - "default": "void" - } - ] - } - ] - ], - "GameRules": [ - "array", - { - "countType": "varint", - "type": "GameRule" - } - ], - "Blob": [ - "container", - [ - { - "name": "hash", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "BlockProperties": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "state", - "type": "nbt" - } - ] - ] - } - ], - "Itemstates": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "runtime_id", - "type": "li16" - }, - { - "name": "component_based", - "type": "bool" - } - ] - ] - } - ], - "ItemExtraDataWithBlockingTick": [ - "container", - [ - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "lnbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "blocking_tick", - "type": "li64" - } - ] - ], - "ItemExtraDataWithoutBlockingTick": [ - "container", - [ - { - "name": "has_nbt", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "0": "false", - "65535": "true" - } - } - ] - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "has_nbt", - "fields": { - "true": [ - "container", - [ - { - "name": "version", - "type": "u8" - }, - { - "name": "nbt", - "type": "lnbt" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "can_place_on", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - }, - { - "name": "can_destroy", - "type": [ - "array", - { - "countType": "li32", - "type": "ShortArray" - } - ] - } - ] - ], - "ItemLegacy": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "count", - "type": "lu16" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "block_runtime_id", - "type": "zigzag32" - }, - { - "name": "extra", - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "/ShieldItemID": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithBlockingTick" - } - ] - }, - "default": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithoutBlockingTick" - } - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "Item": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "count", - "type": "lu16" - }, - { - "name": "metadata", - "type": "varint" - }, - { - "name": "has_stack_id", - "type": "u8" - }, - { - "name": "stack_id", - "type": [ - "switch", - { - "compareTo": "has_stack_id", - "fields": { - "0": "void" - }, - "default": "zigzag32" - } - ] - }, - { - "name": "block_runtime_id", - "type": "zigzag32" - }, - { - "name": "extra", - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "/ShieldItemID": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithBlockingTick" - } - ] - }, - "default": [ - "encapsulated", - { - "lengthType": "varint", - "type": "ItemExtraDataWithoutBlockingTick" - } - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "vec3i": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "vec3u": [ - "container", - [ - { - "name": "x", - "type": "varint" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "varint" - } - ] - ], - "vec3f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "y", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "vec2f": [ - "container", - [ - { - "name": "x", - "type": "lf32" - }, - { - "name": "z", - "type": "lf32" - } - ] - ], - "MetadataDictionary": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "key", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "flags", - "1": "health", - "2": "variant", - "3": "color", - "4": "nametag", - "5": "owner_eid", - "6": "target_eid", - "7": "air", - "8": "potion_color", - "9": "potion_ambient", - "10": "jump_duration", - "11": "hurt_time", - "12": "hurt_direction", - "13": "paddle_time_left", - "14": "paddle_time_right", - "15": "experience_value", - "16": "minecart_display_block", - "17": "minecart_display_offset", - "18": "minecart_has_display", - "20": "old_swell", - "21": "swell_dir", - "22": "charge_amount", - "23": "enderman_held_runtime_id", - "24": "entity_age", - "26": "player_flags", - "27": "player_index", - "28": "player_bed_position", - "29": "fireball_power_x", - "30": "fireball_power_y", - "31": "fireball_power_z", - "32": "aux_power", - "33": "fish_x", - "34": "fish_z", - "35": "fish_angle", - "36": "potion_aux_value", - "37": "lead_holder_eid", - "38": "scale", - "39": "interactive_tag", - "40": "npc_skin_id", - "41": "url_tag", - "42": "max_airdata_max_air", - "43": "mark_variant", - "44": "container_type", - "45": "container_base_size", - "46": "container_extra_slots_per_strength", - "47": "block_target", - "48": "wither_invulnerable_ticks", - "49": "wither_target_1", - "50": "wither_target_2", - "51": "wither_target_3", - "52": "aerial_attack", - "53": "boundingbox_width", - "54": "boundingbox_height", - "55": "fuse_length", - "56": "rider_seat_position", - "57": "rider_rotation_locked", - "58": "rider_max_rotation", - "59": "rider_min_rotation", - "60": "rider_rotation_offset", - "61": "area_effect_cloud_radius", - "62": "area_effect_cloud_waiting", - "63": "area_effect_cloud_particle_id", - "64": "shulker_peek_id", - "65": "shulker_attach_face", - "66": "shulker_attached", - "67": "shulker_attach_pos", - "68": "trading_player_eid", - "69": "trading_career", - "70": "has_command_block", - "71": "command_block_command", - "72": "command_block_last_output", - "73": "command_block_track_output", - "74": "controlling_rider_seat_number", - "75": "strength", - "76": "max_strength", - "77": "spell_casting_color", - "78": "limited_life", - "79": "armor_stand_pose_index", - "80": "ender_crystal_time_offset", - "81": "always_show_nametag", - "82": "color_2", - "83": "name_author", - "84": "score_tag", - "85": "balloon_attached_entity", - "86": "pufferfish_size", - "87": "bubble_time", - "88": "agent", - "89": "sitting_amount", - "90": "sitting_amount_previous", - "91": "eating_counter", - "92": "flags_extended", - "93": "laying_amount", - "94": "laying_amount_previous", - "95": "duration", - "96": "spawn_time", - "97": "change_rate", - "98": "change_on_pickup", - "99": "pickup_count", - "100": "interact_text", - "101": "trade_tier", - "102": "max_trade_tier", - "103": "trade_experience", - "104": "skin_id", - "105": "spawning_frames", - "106": "command_block_tick_delay", - "107": "command_block_execute_on_first_tick", - "108": "ambient_sound_interval", - "109": "ambient_sound_interval_range", - "110": "ambient_sound_event_name", - "111": "fall_damage_multiplier", - "112": "name_raw_text", - "113": "can_ride_target", - "114": "low_tier_cured_discount", - "115": "high_tier_cured_discount", - "116": "nearby_cured_discount", - "117": "nearby_cured_discount_timestamp", - "118": "hitbox", - "119": "is_buoyant", - "120": "base_runtime_id", - "121": "freezing_effect_strength", - "122": "buoyancy_data", - "123": "goat_horn_count", - "124": "update_properties" - } - } - ] - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "byte", - "1": "short", - "2": "int", - "3": "float", - "4": "string", - "5": "compound", - "6": "vec3i", - "7": "long", - "8": "vec3f" - } - } - ] - }, - { - "name": "value", - "type": [ - "switch", - { - "compareTo": "key", - "fields": { - "flags": "MetadataFlags1", - "flags_extended": "MetadataFlags2" - }, - "default": [ - "switch", - { - "compareTo": "type", - "fields": { - "byte": "i8", - "short": "li16", - "int": "zigzag32", - "float": "lf32", - "string": "string", - "compound": "nbt", - "vec3i": "vec3i", - "long": "zigzag64", - "vec3f": "vec3f" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ], - "Link": [ - "container", - [ - { - "name": "ridden_entity_id", - "type": "zigzag64" - }, - { - "name": "rider_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "immediate", - "type": "bool" - }, - { - "name": "rider_initiated", - "type": "bool" - } - ] - ], - "Links": [ - "array", - { - "countType": "varint", - "type": "Link" - } - ], - "EntityAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "min", - "type": "lf32" - }, - { - "name": "value", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - } - ] - ] - } - ], - "Rotation": [ - "container", - [ - { - "name": "yaw", - "type": "byterot" - }, - { - "name": "pitch", - "type": "byterot" - }, - { - "name": "head_yaw", - "type": "byterot" - } - ] - ], - "BlockCoordinates": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "varint" - }, - { - "name": "z", - "type": "zigzag32" - } - ] - ], - "PlayerAttributes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "min", - "type": "lf32" - }, - { - "name": "max", - "type": "lf32" - }, - { - "name": "current", - "type": "lf32" - }, - { - "name": "default", - "type": "lf32" - }, - { - "name": "name", - "type": "string" - } - ] - ] - } - ], - "TransactionUseItem": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "click_block", - "1": "click_air", - "2": "break_block" - } - } - ] - }, - { - "name": "block_position", - "type": "vec3i" - }, - { - "name": "face", - "type": "varint" - }, - { - "name": "hotbar_slot", - "type": "varint" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - }, - { - "name": "block_runtime_id", - "type": "varint" - } - ] - ], - "TransactionActions": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "source_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "container", - "1": "global", - "2": "world_interaction", - "3": "creative", - "100": "craft_slot", - "99999": "craft" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "source_type", - "fields": { - "container": [ - "container", - [ - { - "name": "inventory_id", - "type": "WindowIDVarint" - } - ] - ], - "craft": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ], - "world_interaction": [ - "container", - [ - { - "name": "flags", - "type": "varint" - } - ] - ], - "craft_slot": [ - "container", - [ - { - "name": "action", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "old_item", - "type": "Item" - }, - { - "name": "new_item", - "type": "Item" - } - ] - ] - } - ], - "TransactionLegacy": [ - "container", - [ - { - "name": "legacy_request_id", - "type": "zigzag32" - }, - { - "name": "legacy_transactions", - "type": [ - "switch", - { - "compareTo": "legacy_request_id", - "fields": { - "0": "void" - }, - "default": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "container_id", - "type": "u8" - }, - { - "name": "changed_slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_id", - "type": "u8" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - } - ] - ], - "Transaction": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "transaction_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "inventory_mismatch", - "2": "item_use", - "3": "item_use_on_entity", - "4": "item_release" - } - } - ] - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "transaction_data", - "type": [ - "switch", - { - "compareTo": "transaction_type", - "fields": { - "normal": "void", - "inventory_mismatch": "void", - "item_use": "TransactionUseItem", - "item_use_on_entity": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "interact", - "1": "attack" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "player_pos", - "type": "vec3f" - }, - { - "name": "click_pos", - "type": "vec3f" - } - ] - ], - "item_release": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "release", - "1": "consume" - } - } - ] - }, - { - "name": "hotbar_slot", - "type": "zigzag32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "head_pos", - "type": "vec3f" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "ItemStacks": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ], - "RecipeIngredient": [ - "container", - [ - { - "name": "network_id", - "type": "zigzag32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "network_id", - "fields": { - "0": "void" - }, - "default": [ - "container", - [ - { - "name": "network_data", - "type": "zigzag32" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ], - "PotionTypeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "input_item_meta", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "ingredient_meta", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - }, - { - "name": "output_item_meta", - "type": "zigzag32" - } - ] - ] - } - ], - "PotionContainerChangeRecipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "input_item_id", - "type": "zigzag32" - }, - { - "name": "ingredient_id", - "type": "zigzag32" - }, - { - "name": "output_item_id", - "type": "zigzag32" - } - ] - ] - } - ], - "Recipes": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "shapeless", - "1": "shaped", - "2": "furnace", - "3": "furnace_with_metadata", - "4": "multi", - "5": "shulker_box", - "6": "shapeless_chemistry", - "7": "shaped_chemistry" - } - } - ] - }, - { - "name": "recipe", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "shapeless": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shulker_box": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shapeless_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "RecipeIngredient" - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "shaped_chemistry": [ - "container", - [ - { - "name": "recipe_id", - "type": "string" - }, - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "input", - "type": [ - "array", - { - "count": "width", - "type": [ - "array", - { - "count": "height", - "type": "RecipeIngredient" - } - ] - } - ] - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "block", - "type": "string" - }, - { - "name": "priority", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ], - "furnace": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "output", - "type": "ItemLegacy" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "furnace_with_metadata": [ - "container", - [ - { - "name": "input_id", - "type": "zigzag32" - }, - { - "name": "input_meta", - "type": "zigzag32" - }, - { - "name": "output", - "type": "ItemLegacy" - }, - { - "name": "block", - "type": "string" - } - ] - ], - "multi": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "network_id", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "SkinImage": [ - "container", - [ - { - "name": "width", - "type": "li32" - }, - { - "name": "height", - "type": "li32" - }, - { - "name": "data", - "type": "ByteArray" - } - ] - ], - "Skin": [ - "container", - [ - { - "name": "skin_id", - "type": "string" - }, - { - "name": "play_fab_id", - "type": "string" - }, - { - "name": "skin_resource_pack", - "type": "string" - }, - { - "name": "skin_data", - "type": "SkinImage" - }, - { - "name": "animations", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "skin_image", - "type": "SkinImage" - }, - { - "name": "animation_type", - "type": "li32" - }, - { - "name": "animation_frames", - "type": "lf32" - }, - { - "name": "expression_type", - "type": "lf32" - } - ] - ] - } - ] - }, - { - "name": "cape_data", - "type": "SkinImage" - }, - { - "name": "geometry_data", - "type": "string" - }, - { - "name": "animation_data", - "type": "string" - }, - { - "name": "premium", - "type": "bool" - }, - { - "name": "persona", - "type": "bool" - }, - { - "name": "cape_on_classic", - "type": "bool" - }, - { - "name": "cape_id", - "type": "string" - }, - { - "name": "full_skin_id", - "type": "string" - }, - { - "name": "arm_size", - "type": "string" - }, - { - "name": "skin_color", - "type": "string" - }, - { - "name": "personal_pieces", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_id", - "type": "string" - }, - { - "name": "piece_type", - "type": "string" - }, - { - "name": "pack_id", - "type": "string" - }, - { - "name": "is_default_piece", - "type": "bool" - }, - { - "name": "product_id", - "type": "string" - } - ] - ] - } - ] - }, - { - "name": "piece_tint_colors", - "type": [ - "array", - { - "countType": "li32", - "type": [ - "container", - [ - { - "name": "piece_type", - "type": "string" - }, - { - "name": "colors", - "type": [ - "array", - { - "countType": "li32", - "type": "string" - } - ] - } - ] - ] - } - ] - } - ] - ], - "PlayerRecords": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "remove" - } - } - ] - }, - { - "name": "records_count", - "type": "varint" - }, - { - "name": "records", - "type": [ - "array", - { - "count": "records_count", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "xbox_user_id", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "build_platform", - "type": "li32" - }, - { - "name": "skin_data", - "type": "Skin" - }, - { - "name": "is_teacher", - "type": "bool" - }, - { - "name": "is_host", - "type": "bool" - } - ] - ], - "remove": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - }, - { - "name": "verified", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "add": [ - "array", - { - "count": "records_count", - "type": "bool" - } - ] - }, - "default": "void" - } - ] - } - ] - ], - "Enchant": [ - "container", - [ - { - "name": "id", - "type": "u8" - }, - { - "name": "level", - "type": "u8" - } - ] - ], - "EnchantOption": [ - "container", - [ - { - "name": "cost", - "type": "varint" - }, - { - "name": "slot_flags", - "type": "li32" - }, - { - "name": "equip_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "held_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "self_enchants", - "type": [ - "array", - { - "countType": "varint", - "type": "Enchant" - } - ] - }, - { - "name": "name", - "type": "string" - }, - { - "name": "option_id", - "type": "zigzag32" - } - ] - ], - "Action": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "start_break", - "1": "abort_break", - "2": "stop_break", - "3": "get_updated_block", - "4": "drop_item", - "5": "start_sleeping", - "6": "stop_sleeping", - "7": "respawn", - "8": "jump", - "9": "start_sprint", - "10": "stop_sprint", - "11": "start_sneak", - "12": "stop_sneak", - "13": "creative_player_destroy_block", - "14": "dimension_change_ack", - "15": "start_glide", - "16": "stop_glide", - "17": "build_denied", - "18": "crack_break", - "19": "change_skin", - "20": "set_enchatnment_seed", - "21": "swimming", - "22": "stop_swimming", - "23": "start_spin_attack", - "24": "stop_spin_attack", - "25": "interact_block", - "26": "predict_break", - "27": "continue_break" - } - } - ], - "StackRequestSlotInfo": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "stack_id", - "type": "zigzag32" - } - ] - ], - "ItemStackRequest": [ - "container", - [ - { - "name": "request_id", - "type": "varint" - }, - { - "name": "actions", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "type_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "take", - "1": "place", - "2": "swap", - "3": "drop", - "4": "destroy", - "5": "consume", - "6": "create", - "7": "lab_table_combine", - "8": "beacon_payment", - "9": "mine_block", - "10": "craft_recipe", - "11": "craft_recipe_auto", - "12": "craft_creative", - "13": "optional", - "14": "non_implemented", - "15": "results_deprecated" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type_id", - "fields": { - "take": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "place": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "swap": [ - "container", - [ - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "destination", - "type": "StackRequestSlotInfo" - } - ] - ], - "drop": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - }, - { - "name": "randomly", - "type": "bool" - } - ] - ], - "destroy": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "consume": [ - "container", - [ - { - "name": "count", - "type": "u8" - }, - { - "name": "source", - "type": "StackRequestSlotInfo" - } - ] - ], - "create": [ - "container", - [ - { - "name": "result_slot_id", - "type": "u8" - } - ] - ], - "beacon_payment": [ - "container", - [ - { - "name": "primary_effect", - "type": "zigzag32" - }, - { - "name": "secondary_effect", - "type": "zigzag32" - } - ] - ], - "mine_block": [ - "container", - [ - { - "name": "unknown1", - "type": "zigzag32" - }, - { - "name": "predicted_durability", - "type": "zigzag32" - }, - { - "name": "network_id", - "type": "zigzag32" - } - ] - ], - "craft_recipe": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_recipe_auto": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - } - ] - ], - "craft_creative": [ - "container", - [ - { - "name": "item_id", - "type": "varint" - } - ] - ], - "optional": [ - "container", - [ - { - "name": "recipe_network_id", - "type": "varint" - }, - { - "name": "filtered_string_index", - "type": "li32" - } - ] - ], - "non_implemented": "void", - "results_deprecated": [ - "container", - [ - { - "name": "result_items", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemLegacy" - } - ] - }, - { - "name": "times_crafted", - "type": "u8" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - { - "name": "custom_names", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "ItemStackResponses": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "ok", - "1": "error" - } - } - ] - }, - { - "name": "request_id", - "type": "varint" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "status", - "fields": { - "ok": [ - "container", - [ - { - "name": "containers", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot_type", - "type": "ContainerSlotType" - }, - { - "name": "slots", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "slot", - "type": "u8" - }, - { - "name": "hotbar_slot", - "type": "u8" - }, - { - "name": "count", - "type": "u8" - }, - { - "name": "item_stack_id", - "type": "varint" - }, - { - "name": "custom_name", - "type": "string" - }, - { - "name": "durability_correction", - "type": "zigzag32" - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ], - "ItemComponentList": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ] - } - ], - "CommandOrigin": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "player", - "1": "block", - "2": "minecart_block", - "3": "dev_console", - "4": "test", - "5": "automation_player", - "6": "client_automation", - "7": "dedicated_server", - "8": "entity", - "9": "virtual", - "10": "game_argument", - "11": "entity_server", - "12": "precompiled", - "13": "game_director_entity_server", - "14": "script" - } - } - ] - }, - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "request_id", - "type": "string" - }, - { - "name": "player_entity_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "dev_console": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ], - "test": [ - "container", - [ - { - "name": "player_entity_id", - "type": "zigzag64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "TrackedObject": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "entity", - "1": "block" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "block_position", - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "block": "BlockCoordinates" - }, - "default": "void" - } - ] - } - ] - ], - "MapDecoration": [ - "container", - [ - { - "name": "type", - "type": "u8" - }, - { - "name": "rotation", - "type": "u8" - }, - { - "name": "x", - "type": "u8" - }, - { - "name": "y", - "type": "u8" - }, - { - "name": "label", - "type": "string" - }, - { - "name": "color_abgr", - "type": "varint" - } - ] - ], - "StructureBlockSettings": [ - "container", - [ - { - "name": "palette_name", - "type": "string" - }, - { - "name": "ignore_entities", - "type": "bool" - }, - { - "name": "ignore_blocks", - "type": "bool" - }, - { - "name": "size", - "type": "BlockCoordinates" - }, - { - "name": "structure_offset", - "type": "BlockCoordinates" - }, - { - "name": "last_editing_player_unique_id", - "type": "zigzag64" - }, - { - "name": "rotation", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "90_deg", - "2": "180_deg", - "3": "270_deg" - } - } - ] - }, - { - "name": "mirror", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "x_axis", - "2": "z_axis", - "3": "both_axes" - } - } - ] - }, - { - "name": "animation_mode", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "layers", - "2": "blocks" - } - } - ] - }, - { - "name": "animation_duration", - "type": "lf32" - }, - { - "name": "integrity", - "type": "lf32" - }, - { - "name": "seed", - "type": "lu32" - }, - { - "name": "pivot", - "type": "vec3f" - } - ] - ], - "WindowID": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowIDVarint": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "inventory", - "1": "first", - "100": "last", - "119": "offhand", - "120": "armor", - "121": "creative", - "122": "hotbar", - "123": "fixed_inventory", - "124": "ui", - "-100": "drop_contents", - "-24": "beacon", - "-23": "trading_output", - "-22": "trading_use_inputs", - "-21": "trading_input_2", - "-20": "trading_input_1", - "-17": "enchant_output", - "-16": "enchant_material", - "-15": "enchant_input", - "-13": "anvil_output", - "-12": "anvil_result", - "-11": "anvil_material", - "-10": "container_input", - "-5": "crafting_use_ingredient", - "-4": "crafting_result", - "-3": "crafting_remove_ingredient", - "-2": "crafting_add_ingredient", - "-1": "none" - } - } - ], - "WindowType": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "container", - "1": "workbench", - "2": "furnace", - "3": "enchantment", - "4": "brewing_stand", - "5": "anvil", - "6": "dispenser", - "7": "dropper", - "8": "hopper", - "9": "cauldron", - "10": "minecart_chest", - "11": "minecart_hopper", - "12": "horse", - "13": "beacon", - "14": "structure_editor", - "15": "trading", - "16": "command_block", - "17": "jukebox", - "18": "armor", - "19": "hand", - "20": "compound_creator", - "21": "element_constructor", - "22": "material_reducer", - "23": "lab_table", - "24": "loom", - "25": "lectern", - "26": "grindstone", - "27": "blast_furnace", - "28": "smoker", - "29": "stonecutter", - "30": "cartography", - "31": "hud", - "32": "jigsaw_editor", - "33": "smithing_table", - "-9": "none", - "-1": "inventory" - } - } - ], - "ContainerSlotType": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "anvil_input", - "1": "anvil_material", - "2": "anvil_result", - "3": "smithing_table_input", - "4": "smithing_table_material", - "5": "smithing_table_result", - "6": "armor", - "7": "container", - "8": "beacon_payment", - "9": "brewing_input", - "10": "brewing_result", - "11": "brewing_fuel", - "12": "hotbar_and_inventory", - "13": "crafting_input", - "14": "crafting_output", - "15": "recipe_construction", - "16": "recipe_nature", - "17": "recipe_items", - "18": "recipe_search", - "19": "recipe_search_bar", - "20": "recipe_equipment", - "21": "enchanting_input", - "22": "enchanting_lapis", - "23": "furnace_fuel", - "24": "furnace_ingredient", - "25": "furnace_output", - "26": "horse_equip", - "27": "hotbar", - "28": "inventory", - "29": "shulker", - "30": "trade_ingredient1", - "31": "trade_ingredient2", - "32": "trade_result", - "33": "offhand", - "34": "compcreate_input", - "35": "compcreate_output", - "36": "elemconstruct_output", - "37": "matreduce_input", - "38": "matreduce_output", - "39": "labtable_input", - "40": "loom_input", - "41": "loom_dye", - "42": "loom_material", - "43": "loom_result", - "44": "blast_furnace_ingredient", - "45": "smoker_ingredient", - "46": "trade2_ingredient1", - "47": "trade2_ingredient2", - "48": "trade2_result", - "49": "grindstone_input", - "50": "grindstone_additional", - "51": "grindstone_result", - "52": "stonecutter_input", - "53": "stonecutter_result", - "54": "cartography_input", - "55": "cartography_additional", - "56": "cartography_result", - "57": "barrel", - "58": "cursor", - "59": "creative_output" - } - } - ], - "SoundType": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "ItemUseOn", - "1": "Hit", - "2": "Step", - "3": "Fly", - "4": "Jump", - "5": "Break", - "6": "Place", - "7": "HeavyStep", - "8": "Gallop", - "9": "Fall", - "10": "Ambient", - "11": "AmbientBaby", - "12": "AmbientInWater", - "13": "Breathe", - "14": "Death", - "15": "DeathInWater", - "16": "DeathToZombie", - "17": "Hurt", - "18": "HurtInWater", - "19": "Mad", - "20": "Boost", - "21": "Bow", - "22": "SquishBig", - "23": "SquishSmall", - "24": "FallBig", - "25": "FallSmall", - "26": "Splash", - "27": "Fizz", - "28": "Flap", - "29": "Swim", - "30": "Drink", - "31": "Eat", - "32": "Takeoff", - "33": "Shake", - "34": "Plop", - "35": "Land", - "36": "Saddle", - "37": "Armor", - "38": "MobArmorStandPlace", - "39": "AddChest", - "40": "Throw", - "41": "Attack", - "42": "AttackNoDamage", - "43": "AttackStrong", - "44": "Warn", - "45": "Shear", - "46": "Milk", - "47": "Thunder", - "48": "Explode", - "49": "Fire", - "50": "Ignite", - "51": "Fuse", - "52": "Stare", - "53": "Spawn", - "54": "Shoot", - "55": "BreakBlock", - "56": "Launch", - "57": "Blast", - "58": "LargeBlast", - "59": "Twinkle", - "60": "Remedy", - "61": "Infect", - "62": "LevelUp", - "63": "BowHit", - "64": "BulletHit", - "65": "ExtinguishFire", - "66": "ItemFizz", - "67": "ChestOpen", - "68": "ChestClosed", - "69": "ShulkerBoxOpen", - "70": "ShulkerBoxClosed", - "71": "EnderChestOpen", - "72": "EnderChestClosed", - "73": "PowerOn", - "74": "PowerOff", - "75": "Attach", - "76": "Detach", - "77": "Deny", - "78": "Tripod", - "79": "Pop", - "80": "DropSlot", - "81": "Note", - "82": "Thorns", - "83": "PistonIn", - "84": "PistonOut", - "85": "Portal", - "86": "Water", - "87": "LavaPop", - "88": "Lava", - "89": "Burp", - "90": "BucketFillWater", - "91": "BucketFillLava", - "92": "BucketEmptyWater", - "93": "BucketEmptyLava", - "94": "ArmorEquipChain", - "95": "ArmorEquipDiamond", - "96": "ArmorEquipGeneric", - "97": "ArmorEquipGold", - "98": "ArmorEquipIron", - "99": "ArmorEquipLeather", - "100": "ArmorEquipElytra", - "101": "Record13", - "102": "RecordCat", - "103": "RecordBlocks", - "104": "RecordChirp", - "105": "RecordFar", - "106": "RecordMall", - "107": "RecordMellohi", - "108": "RecordStal", - "109": "RecordStrad", - "110": "RecordWard", - "111": "Record11", - "112": "RecordWait", - "113": "unknown1", - "114": "Flop", - "115": "ElderGuardianCurse", - "116": "MobWarning", - "117": "MobWarningBaby", - "118": "Teleport", - "119": "ShulkerOpen", - "120": "ShulkerClose", - "121": "Haggle", - "122": "HaggleYes", - "123": "HaggleNo", - "124": "HaggleIdle", - "125": "ChorusGrow", - "126": "ChorusDeath", - "127": "Glass", - "128": "PotionBrewed", - "129": "CastSpell", - "130": "PrepareAttack", - "131": "PrepareSummon", - "132": "PrepareWololo", - "133": "Fang", - "134": "Charge", - "135": "CameraTakePicture", - "136": "LeashKnotPlace", - "137": "LeashKnotBreak", - "138": "Growl", - "139": "Whine", - "140": "Pant", - "141": "Purr", - "142": "Purreow", - "143": "DeathMinVolume", - "144": "DeathMidVolume", - "145": "unknown2", - "146": "ImitateCaveSpider", - "147": "ImitateCreeper", - "148": "ImitateElderGuardian", - "149": "ImitateEnderDragon", - "150": "ImitateEnderman", - "151": "unknown3", - "152": "ImitateEvocationIllager", - "153": "ImitateGhast", - "154": "ImitateHusk", - "155": "ImitateIllusionIllager", - "156": "ImitateMagmaCube", - "157": "ImitatePolarBear", - "158": "ImitateShulker", - "159": "ImitateSilverfish", - "160": "ImitateSkeleton", - "161": "ImitateSlime", - "162": "ImitateSpider", - "163": "ImitateStray", - "164": "ImitateVex", - "165": "ImitateVindicationIllager", - "166": "ImitateWitch", - "167": "ImitateWither", - "168": "ImitateWitherSkeleton", - "169": "ImitateWolf", - "170": "ImitateZombie", - "171": "ImitateZombiePigman", - "172": "ImitateZombieVillager", - "173": "BlockEndPortalFrameFill", - "174": "BlockEndPortalSpawn", - "175": "RandomAnvilUse", - "176": "BottleDragonBreath", - "177": "PortalTravel", - "178": "ItemTridentHit", - "179": "ItemTridentReturn", - "180": "ItemTridentRiptide1", - "181": "ItemTridentRiptide2", - "182": "ItemTridentRiptide3", - "183": "ItemTridentThrow", - "184": "ItemTridentThunder", - "185": "ItemTridentHitGround", - "186": "Default", - "187": "BlockFletchingTableUse", - "188": "ElemConstructOpen", - "189": "IceBombHit", - "190": "BalloonPop", - "191": "LtReactionIceBomb", - "192": "LtReactionBleach", - "193": "LtReactionEPaste", - "194": "LtReactionEPaste2", - "195": "LtReactionFertilizer", - "196": "LtReactionFireball", - "197": "LtReactionMgsalt", - "198": "LtReactionMiscfire", - "199": "LtReactionFire", - "200": "LtReactionMiscexplosion", - "201": "LtReactionMiscmystical", - "202": "LtReactionMiscmystical2", - "203": "LtReactionProduct", - "204": "SparklerUse", - "205": "GlowstickUse", - "206": "SparklerActive", - "207": "ConvertToDrowned", - "208": "BucketFillFish", - "209": "BucketEmptyFish", - "210": "BubbleUp", - "211": "BubbleDown", - "212": "BubblePop", - "213": "BubbleUpInside", - "214": "BubbleDownInside", - "215": "HurtBaby", - "216": "DeathBaby", - "217": "StepBaby", - "218": "BabySpawn", - "219": "Born", - "220": "BlockTurtleEggBreak", - "221": "BlockTurtleEggCrack", - "222": "BlockTurtleEggHatch", - "223": "TurtleLayEgg", - "224": "BlockTurtleEggAttack", - "225": "BeaconActivate", - "226": "BeaconAmbient", - "227": "BeaconDeactivate", - "228": "BeaconPower", - "229": "ConduitActivate", - "230": "ConduitAmbient", - "231": "ConduitAttack", - "232": "ConduitDeactivate", - "233": "ConduitShort", - "234": "Swoop", - "235": "BlockBambooSaplingPlace", - "236": "PreSneeze", - "237": "Sneeze", - "238": "AmbientTame", - "239": "Scared", - "240": "BlockScaffoldingClimb", - "241": "CrossbowLoadingStart", - "242": "CrossbowLoadingMiddle", - "243": "CrossbowLoadingEnd", - "244": "CrossbowShoot", - "245": "CrossbowQuickChargeStart", - "246": "CrossbowQuickChargeMiddle", - "247": "CrossbowQuickChargeEnd", - "248": "AmbientAggressive", - "249": "AmbientWorried", - "250": "CantBreed", - "251": "ItemShieldBlock", - "252": "ItemBookPut", - "253": "BlockGrindstoneUse", - "254": "BlockBellHit", - "255": "BlockCampfireCrackle", - "256": "Roar", - "257": "Stun", - "258": "BlockSweetBerryBushHurt", - "259": "BlockSweetBerryBushPick", - "260": "UICartographyTableTakeResult", - "261": "UIStoneCutterTakeResult", - "262": "BlockComposterEmpty", - "263": "BlockComposterFill", - "264": "BlockComposterFillSuccess", - "265": "BlockComposterReady", - "266": "BlockBarrelOpen", - "267": "BlockBarrelClose", - "268": "RaidHorn", - "269": "BlockLoomUse", - "270": "AmbientRaid", - "271": "UICartographyTableUse", - "272": "UIStoneCutterUse", - "273": "UILoomUse", - "274": "SmokerUse", - "275": "BlastFurnaceUse", - "276": "SmithingTableUse", - "277": "Screech", - "278": "Sleep", - "279": "FurnaceUse", - "280": "MooshroomConvert", - "281": "MilkSuspiciously", - "282": "Celebrate", - "283": "JumpPrevent", - "284": "AmbientPollinate", - "285": "BeeHiveDrip", - "286": "BeeHiveEnter", - "287": "BeeHiveExit", - "288": "BeeHiveWork", - "289": "BeeHiveShear", - "290": "HoneyBottleDrink", - "291": "AmbientCave", - "292": "Retreat", - "293": "ConvertToZombified", - "294": "Admire", - "295": "StepLava", - "296": "Tempt", - "297": "Panic", - "298": "Angry", - "299": "AmbientWarpedForest", - "300": "AmbientSoulsandValley", - "301": "AmbientNetherWastes", - "302": "AmbientBasaltDeltas", - "303": "AmbientCrimsonForest", - "304": "RespawnAnchorCharge", - "305": "RespawnAnchorDeplete", - "306": "RespawnAnchorSetSpawn", - "307": "RespawnAnchorAmbient", - "308": "SoulEscapeQuiet", - "309": "SoulEscapeLoud", - "310": "RecordPigstep", - "311": "LinkCompassToLodestone", - "312": "BlockSmithingTableUse", - "313": "EquipNetherite", - "314": "AmbientLoopWarpedForest", - "315": "AmbientLoopSoulsandValley", - "316": "AmbientLoopNetherWastes", - "317": "AmbientLoopBasaltDeltas", - "318": "AmbientLoopCrimsonForest", - "319": "AmbientAdditionWarpedForest", - "320": "AmbientAdditionSoulsandValley", - "321": "AmbientAdditionNetherWastes", - "322": "AmbientAdditionBasaltDeltas", - "323": "AmbientAdditionCrimsonForest", - "324": "SculkSensorPowerOn", - "325": "SculkSensorPowerOff", - "326": "BucketFillPowderSnow", - "327": "BucketEmptyPowderSnow", - "328": "PointedDripstoneCauldronDripWater", - "329": "PointedDripstoneCauldronDripLava", - "330": "PointedDripstoneDripWater", - "331": "PointedDripstoneDripLava", - "332": "CaveVinesPickBerries", - "333": "BigDripleafTiltDown", - "334": "BigDripleafTiltUp", - "335": "unknown335", - "336": "unknown336", - "337": "unknown337", - "338": "unknown338", - "339": "copper_wax_on", - "340": "copper_wax_off", - "341": "scrape", - "342": "player_hurt_drown", - "343": "player_hurt_on_fire", - "344": "player_hurt_freeze", - "345": "use_spyglass", - "346": "stop_using_spyglass", - "347": "amethyst_block_chime", - "348": "ambient_screamer", - "349": "hurt_screamer", - "350": "death_screamer", - "351": "milk_screamer", - "352": "jump_to_block", - "353": "pre_ram", - "354": "pre_ram_screamer", - "355": "ram_impact", - "356": "ram_impact_screamer", - "357": "squid_ink_squirt", - "358": "glow_squid_ink_squirt", - "359": "convert_to_stray", - "360": "extinguish_candle", - "361": "ambient_candle", - "362": "Undefined" - } - } - ], - "LegacyEntityType": [ - "mapper", - { - "type": "li32", - "mappings": { - "10": "chicken", - "11": "cow", - "12": "pig", - "13": "sheep", - "14": "wolf", - "15": "villager", - "16": "mooshroom", - "17": "squid", - "18": "rabbit", - "19": "bat", - "20": "iron_golem", - "21": "snow_golem", - "22": "ocelot", - "23": "horse", - "24": "donkey", - "25": "mule", - "26": "skeleton_horse", - "27": "zombie_horse", - "28": "polar_bear", - "29": "llama", - "30": "parrot", - "31": "dolphin", - "32": "zombie", - "33": "creeper", - "34": "skeleton", - "35": "spider", - "36": "zombie_pigman", - "37": "slime", - "38": "enderman", - "39": "silverfish", - "40": "cave_spider", - "41": "ghast", - "42": "magma_cube", - "43": "blaze", - "44": "zombie_villager", - "45": "witch", - "46": "stray", - "47": "husk", - "48": "wither_skeleton", - "49": "guardian", - "50": "elder_guardian", - "51": "npc", - "52": "wither", - "53": "ender_dragon", - "54": "shulker", - "55": "endermite", - "56": "agent", - "57": "vindicator", - "58": "phantom", - "61": "armor_stand", - "62": "tripod_camera", - "63": "player", - "64": "item", - "65": "tnt", - "66": "falling_block", - "67": "moving_block", - "68": "xp_bottle", - "69": "xp_orb", - "70": "eye_of_ender_signal", - "71": "ender_crystal", - "72": "fireworks_rocket", - "73": "thrown_trident", - "74": "turtle", - "75": "cat", - "76": "shulker_bullet", - "77": "fishing_hook", - "78": "chalkboard", - "79": "dragon_fireball", - "80": "arrow", - "81": "snowball", - "82": "egg", - "83": "painting", - "84": "minecart", - "85": "fireball", - "86": "splash_potion", - "87": "ender_pearl", - "88": "leash_knot", - "89": "wither_skull", - "90": "boat", - "91": "wither_skull_dangerous", - "93": "lightning_bolt", - "94": "small_fireball", - "95": "area_effect_cloud", - "96": "hopper_minecart", - "97": "tnt_minecart", - "98": "chest_minecart", - "100": "command_block_minecart", - "101": "lingering_potion", - "102": "llama_spit", - "103": "evocation_fang", - "104": "evocation_illager", - "105": "vex", - "106": "ice_bomb", - "107": "balloon", - "108": "pufferfish", - "109": "salmon", - "110": "drowned", - "111": "tropicalfish", - "112": "cod", - "113": "panda" - } - } - ], - "mcpe_packet": [ - "container", - [ - { - "name": "name", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "1": "login", - "2": "play_status", - "3": "server_to_client_handshake", - "4": "client_to_server_handshake", - "5": "disconnect", - "6": "resource_packs_info", - "7": "resource_pack_stack", - "8": "resource_pack_client_response", - "9": "text", - "10": "set_time", - "11": "start_game", - "12": "add_player", - "13": "add_entity", - "14": "remove_entity", - "15": "add_item_entity", - "17": "take_item_entity", - "18": "move_entity", - "19": "move_player", - "20": "rider_jump", - "21": "update_block", - "22": "add_painting", - "23": "tick_sync", - "24": "level_sound_event_old", - "25": "level_event", - "26": "block_event", - "27": "entity_event", - "28": "mob_effect", - "29": "update_attributes", - "30": "inventory_transaction", - "31": "mob_equipment", - "32": "mob_armor_equipment", - "33": "interact", - "34": "block_pick_request", - "35": "entity_pick_request", - "36": "player_action", - "38": "hurt_armor", - "39": "set_entity_data", - "40": "set_entity_motion", - "41": "set_entity_link", - "42": "set_health", - "43": "set_spawn_position", - "44": "animate", - "45": "respawn", - "46": "container_open", - "47": "container_close", - "48": "player_hotbar", - "49": "inventory_content", - "50": "inventory_slot", - "51": "container_set_data", - "52": "crafting_data", - "53": "crafting_event", - "54": "gui_data_pick_item", - "55": "adventure_settings", - "56": "block_entity_data", - "57": "player_input", - "58": "level_chunk", - "59": "set_commands_enabled", - "60": "set_difficulty", - "61": "change_dimension", - "62": "set_player_game_type", - "63": "player_list", - "64": "simple_event", - "65": "event", - "66": "spawn_experience_orb", - "67": "clientbound_map_item_data", - "68": "map_info_request", - "69": "request_chunk_radius", - "70": "chunk_radius_update", - "71": "item_frame_drop_item", - "72": "game_rules_changed", - "73": "camera", - "74": "boss_event", - "75": "show_credits", - "76": "available_commands", - "77": "command_request", - "78": "command_block_update", - "79": "command_output", - "80": "update_trade", - "81": "update_equipment", - "82": "resource_pack_data_info", - "83": "resource_pack_chunk_data", - "84": "resource_pack_chunk_request", - "85": "transfer", - "86": "play_sound", - "87": "stop_sound", - "88": "set_title", - "89": "add_behavior_tree", - "90": "structure_block_update", - "91": "show_store_offer", - "92": "purchase_receipt", - "93": "player_skin", - "94": "sub_client_login", - "95": "initiate_web_socket_connection", - "96": "set_last_hurt_by", - "97": "book_edit", - "98": "npc_request", - "99": "photo_transfer", - "100": "modal_form_request", - "101": "modal_form_response", - "102": "server_settings_request", - "103": "server_settings_response", - "104": "show_profile", - "105": "set_default_game_type", - "106": "remove_objective", - "107": "set_display_objective", - "108": "set_score", - "109": "lab_table", - "110": "update_block_synced", - "111": "move_entity_delta", - "112": "set_scoreboard_identity", - "113": "set_local_player_as_initialized", - "114": "update_soft_enum", - "115": "network_stack_latency", - "117": "script_custom_event", - "118": "spawn_particle_effect", - "119": "available_entity_identifiers", - "120": "level_sound_event_v2", - "121": "network_chunk_publisher_update", - "122": "biome_definition_list", - "123": "level_sound_event", - "124": "level_event_generic", - "125": "lectern_update", - "126": "video_stream_connect", - "127": "add_ecs_entity", - "128": "remove_ecs_entity", - "129": "client_cache_status", - "130": "on_screen_texture_animation", - "131": "map_create_locked_copy", - "132": "structure_template_data_export_request", - "133": "structure_template_data_export_response", - "134": "update_block_properties", - "135": "client_cache_blob_status", - "136": "client_cache_miss_response", - "137": "education_settings", - "139": "multiplayer_settings", - "140": "settings_command", - "141": "anvil_damage", - "142": "completed_using_item", - "143": "network_settings", - "144": "player_auth_input", - "145": "creative_content", - "146": "player_enchant_options", - "147": "item_stack_request", - "148": "item_stack_response", - "149": "player_armor_damage", - "151": "update_player_game_type", - "153": "position_tracking_db_broadcast", - "154": "position_tracking_db_request", - "156": "packet_violation_warning", - "157": "motion_prediction_hints", - "158": "animate_entity", - "159": "camera_shake", - "160": "player_fog", - "161": "correct_player_move_prediction", - "162": "item_component", - "163": "filter_text_packet", - "164": "debug_renderer", - "165": "sync_entity_property", - "166": "add_volume_entity", - "167": "remove_volume_entity", - "168": "simulation_type", - "169": "npc_dialogue" - } - } - ] - }, - { - "name": "params", - "type": [ - "switch", - { - "compareTo": "name", - "fields": { - "login": "packet_login", - "play_status": "packet_play_status", - "server_to_client_handshake": "packet_server_to_client_handshake", - "client_to_server_handshake": "packet_client_to_server_handshake", - "disconnect": "packet_disconnect", - "resource_packs_info": "packet_resource_packs_info", - "resource_pack_stack": "packet_resource_pack_stack", - "resource_pack_client_response": "packet_resource_pack_client_response", - "text": "packet_text", - "set_time": "packet_set_time", - "start_game": "packet_start_game", - "add_player": "packet_add_player", - "add_entity": "packet_add_entity", - "remove_entity": "packet_remove_entity", - "add_item_entity": "packet_add_item_entity", - "take_item_entity": "packet_take_item_entity", - "move_entity": "packet_move_entity", - "move_player": "packet_move_player", - "rider_jump": "packet_rider_jump", - "update_block": "packet_update_block", - "add_painting": "packet_add_painting", - "tick_sync": "packet_tick_sync", - "level_sound_event_old": "packet_level_sound_event_old", - "level_event": "packet_level_event", - "block_event": "packet_block_event", - "entity_event": "packet_entity_event", - "mob_effect": "packet_mob_effect", - "update_attributes": "packet_update_attributes", - "inventory_transaction": "packet_inventory_transaction", - "mob_equipment": "packet_mob_equipment", - "mob_armor_equipment": "packet_mob_armor_equipment", - "interact": "packet_interact", - "block_pick_request": "packet_block_pick_request", - "entity_pick_request": "packet_entity_pick_request", - "player_action": "packet_player_action", - "hurt_armor": "packet_hurt_armor", - "set_entity_data": "packet_set_entity_data", - "set_entity_motion": "packet_set_entity_motion", - "set_entity_link": "packet_set_entity_link", - "set_health": "packet_set_health", - "set_spawn_position": "packet_set_spawn_position", - "animate": "packet_animate", - "respawn": "packet_respawn", - "container_open": "packet_container_open", - "container_close": "packet_container_close", - "player_hotbar": "packet_player_hotbar", - "inventory_content": "packet_inventory_content", - "inventory_slot": "packet_inventory_slot", - "container_set_data": "packet_container_set_data", - "crafting_data": "packet_crafting_data", - "crafting_event": "packet_crafting_event", - "gui_data_pick_item": "packet_gui_data_pick_item", - "adventure_settings": "packet_adventure_settings", - "block_entity_data": "packet_block_entity_data", - "player_input": "packet_player_input", - "level_chunk": "packet_level_chunk", - "set_commands_enabled": "packet_set_commands_enabled", - "set_difficulty": "packet_set_difficulty", - "change_dimension": "packet_change_dimension", - "set_player_game_type": "packet_set_player_game_type", - "player_list": "packet_player_list", - "simple_event": "packet_simple_event", - "event": "packet_event", - "spawn_experience_orb": "packet_spawn_experience_orb", - "clientbound_map_item_data": "packet_clientbound_map_item_data", - "map_info_request": "packet_map_info_request", - "request_chunk_radius": "packet_request_chunk_radius", - "chunk_radius_update": "packet_chunk_radius_update", - "item_frame_drop_item": "packet_item_frame_drop_item", - "game_rules_changed": "packet_game_rules_changed", - "camera": "packet_camera", - "boss_event": "packet_boss_event", - "show_credits": "packet_show_credits", - "available_commands": "packet_available_commands", - "command_request": "packet_command_request", - "command_block_update": "packet_command_block_update", - "command_output": "packet_command_output", - "update_trade": "packet_update_trade", - "update_equipment": "packet_update_equipment", - "resource_pack_data_info": "packet_resource_pack_data_info", - "resource_pack_chunk_data": "packet_resource_pack_chunk_data", - "resource_pack_chunk_request": "packet_resource_pack_chunk_request", - "transfer": "packet_transfer", - "play_sound": "packet_play_sound", - "stop_sound": "packet_stop_sound", - "set_title": "packet_set_title", - "add_behavior_tree": "packet_add_behavior_tree", - "structure_block_update": "packet_structure_block_update", - "show_store_offer": "packet_show_store_offer", - "purchase_receipt": "packet_purchase_receipt", - "player_skin": "packet_player_skin", - "sub_client_login": "packet_sub_client_login", - "initiate_web_socket_connection": "packet_initiate_web_socket_connection", - "set_last_hurt_by": "packet_set_last_hurt_by", - "book_edit": "packet_book_edit", - "npc_request": "packet_npc_request", - "photo_transfer": "packet_photo_transfer", - "modal_form_request": "packet_modal_form_request", - "modal_form_response": "packet_modal_form_response", - "server_settings_request": "packet_server_settings_request", - "server_settings_response": "packet_server_settings_response", - "show_profile": "packet_show_profile", - "set_default_game_type": "packet_set_default_game_type", - "remove_objective": "packet_remove_objective", - "set_display_objective": "packet_set_display_objective", - "set_score": "packet_set_score", - "lab_table": "packet_lab_table", - "update_block_synced": "packet_update_block_synced", - "move_entity_delta": "packet_move_entity_delta", - "set_scoreboard_identity": "packet_set_scoreboard_identity", - "set_local_player_as_initialized": "packet_set_local_player_as_initialized", - "update_soft_enum": "packet_update_soft_enum", - "network_stack_latency": "packet_network_stack_latency", - "script_custom_event": "packet_script_custom_event", - "spawn_particle_effect": "packet_spawn_particle_effect", - "available_entity_identifiers": "packet_available_entity_identifiers", - "level_sound_event_v2": "packet_level_sound_event_v2", - "network_chunk_publisher_update": "packet_network_chunk_publisher_update", - "biome_definition_list": "packet_biome_definition_list", - "level_sound_event": "packet_level_sound_event", - "level_event_generic": "packet_level_event_generic", - "lectern_update": "packet_lectern_update", - "video_stream_connect": "packet_video_stream_connect", - "add_ecs_entity": "packet_add_ecs_entity", - "remove_ecs_entity": "packet_remove_ecs_entity", - "client_cache_status": "packet_client_cache_status", - "on_screen_texture_animation": "packet_on_screen_texture_animation", - "map_create_locked_copy": "packet_map_create_locked_copy", - "structure_template_data_export_request": "packet_structure_template_data_export_request", - "structure_template_data_export_response": "packet_structure_template_data_export_response", - "update_block_properties": "packet_update_block_properties", - "client_cache_blob_status": "packet_client_cache_blob_status", - "client_cache_miss_response": "packet_client_cache_miss_response", - "education_settings": "packet_education_settings", - "multiplayer_settings": "packet_multiplayer_settings", - "settings_command": "packet_settings_command", - "anvil_damage": "packet_anvil_damage", - "completed_using_item": "packet_completed_using_item", - "network_settings": "packet_network_settings", - "player_auth_input": "packet_player_auth_input", - "creative_content": "packet_creative_content", - "player_enchant_options": "packet_player_enchant_options", - "item_stack_request": "packet_item_stack_request", - "item_stack_response": "packet_item_stack_response", - "player_armor_damage": "packet_player_armor_damage", - "update_player_game_type": "packet_update_player_game_type", - "position_tracking_db_request": "packet_position_tracking_db_request", - "position_tracking_db_broadcast": "packet_position_tracking_db_broadcast", - "packet_violation_warning": "packet_packet_violation_warning", - "motion_prediction_hints": "packet_motion_prediction_hints", - "animate_entity": "packet_animate_entity", - "camera_shake": "packet_camera_shake", - "player_fog": "packet_player_fog", - "correct_player_move_prediction": "packet_correct_player_move_prediction", - "item_component": "packet_item_component", - "filter_text_packet": "packet_filter_text_packet", - "debug_renderer": "packet_debug_renderer", - "sync_entity_property": "packet_sync_entity_property", - "add_volume_entity": "packet_add_volume_entity", - "remove_volume_entity": "packet_remove_volume_entity", - "simulation_type": "packet_simulation_type", - "npc_dialogue": "packet_npc_dialogue" - }, - "default": "void" - } - ] - } - ] - ], - "packet_login": [ - "container", - [ - { - "name": "protocol_version", - "type": "i32" - }, - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "LoginTokens": [ - "container", - [ - { - "name": "identity", - "type": "LittleString" - }, - { - "name": "client", - "type": "LittleString" - } - ] - ], - "packet_play_status": [ - "container", - [ - { - "name": "status", - "type": [ - "mapper", - { - "type": "i32", - "mappings": { - "0": "login_success", - "1": "failed_client", - "2": "failed_spawn", - "3": "player_spawn", - "4": "failed_invalid_tenant", - "5": "failed_vanilla_edu", - "6": "failed_edu_vanilla", - "7": "failed_server_full" - } - } - ] - } - ] - ], - "packet_server_to_client_handshake": [ - "container", - [ - { - "name": "token", - "type": "string" - } - ] - ], - "packet_client_to_server_handshake": [ - "container", - [] - ], - "packet_disconnect": [ - "container", - [ - { - "name": "hide_disconnect_reason", - "type": "bool" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "packet_resource_packs_info": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "has_scripts", - "type": "bool" - }, - { - "name": "force_server_packs", - "type": "bool" - }, - { - "name": "behaviour_packs", - "type": "BehaviourPackInfos" - }, - { - "name": "texture_packs", - "type": "TexturePackInfos" - } - ] - ], - "packet_resource_pack_stack": [ - "container", - [ - { - "name": "must_accept", - "type": "bool" - }, - { - "name": "behavior_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "resource_packs", - "type": "ResourcePackIdVersions" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - } - ] - ], - "packet_resource_pack_client_response": [ - "container", - [ - { - "name": "response_status", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "none", - "1": "refused", - "2": "send_packs", - "3": "have_all_packs", - "4": "completed" - } - } - ] - }, - { - "name": "resourcepackids", - "type": "ResourcePackIds" - } - ] - ], - "packet_text": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "raw", - "1": "chat", - "2": "translation", - "3": "popup", - "4": "jukebox_popup", - "5": "tip", - "6": "system", - "7": "whisper", - "8": "announcement", - "9": "json_whisper", - "10": "json" - } - } - ] - }, - { - "name": "needs_translation", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "chat": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "whisper": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "announcement": [ - "container", - [ - { - "name": "source_name", - "type": "string" - }, - { - "name": "message", - "type": "string" - } - ] - ], - "raw": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "tip": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "system": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json_whisper": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "json": [ - "container", - [ - { - "name": "message", - "type": "string" - } - ] - ], - "translation": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "jukebox_popup": [ - "container", - [ - { - "name": "message", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "xuid", - "type": "string" - }, - { - "name": "platform_chat_id", - "type": "string" - } - ] - ], - "packet_set_time": [ - "container", - [ - { - "name": "time", - "type": "zigzag32" - } - ] - ], - "packet_start_game": [ - "container", - [ - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "player_gamemode", - "type": "GameMode" - }, - { - "name": "player_position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "vec2f" - }, - { - "name": "seed", - "type": "zigzag32" - }, - { - "name": "biome_type", - "type": "li16" - }, - { - "name": "biome_name", - "type": "string" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "generator", - "type": "zigzag32" - }, - { - "name": "world_gamemode", - "type": "GameMode" - }, - { - "name": "difficulty", - "type": "zigzag32" - }, - { - "name": "spawn_position", - "type": "BlockCoordinates" - }, - { - "name": "achievements_disabled", - "type": "bool" - }, - { - "name": "day_cycle_stop_time", - "type": "zigzag32" - }, - { - "name": "edu_offer", - "type": "zigzag32" - }, - { - "name": "edu_features_enabled", - "type": "bool" - }, - { - "name": "edu_product_uuid", - "type": "string" - }, - { - "name": "rain_level", - "type": "lf32" - }, - { - "name": "lightning_level", - "type": "lf32" - }, - { - "name": "has_confirmed_platform_locked_content", - "type": "bool" - }, - { - "name": "is_multiplayer", - "type": "bool" - }, - { - "name": "broadcast_to_lan", - "type": "bool" - }, - { - "name": "xbox_live_broadcast_mode", - "type": "varint" - }, - { - "name": "platform_broadcast_mode", - "type": "varint" - }, - { - "name": "enable_commands", - "type": "bool" - }, - { - "name": "is_texturepacks_required", - "type": "bool" - }, - { - "name": "gamerules", - "type": "GameRules" - }, - { - "name": "experiments", - "type": "Experiments" - }, - { - "name": "experiments_previously_used", - "type": "bool" - }, - { - "name": "bonus_chest", - "type": "bool" - }, - { - "name": "map_enabled", - "type": "bool" - }, - { - "name": "permission_level", - "type": "zigzag32" - }, - { - "name": "server_chunk_tick_range", - "type": "li32" - }, - { - "name": "has_locked_behavior_pack", - "type": "bool" - }, - { - "name": "has_locked_resource_pack", - "type": "bool" - }, - { - "name": "is_from_locked_world_template", - "type": "bool" - }, - { - "name": "msa_gamertags_only", - "type": "bool" - }, - { - "name": "is_from_world_template", - "type": "bool" - }, - { - "name": "is_world_template_option_locked", - "type": "bool" - }, - { - "name": "only_spawn_v1_villagers", - "type": "bool" - }, - { - "name": "game_version", - "type": "string" - }, - { - "name": "limited_world_width", - "type": "li32" - }, - { - "name": "limited_world_length", - "type": "li32" - }, - { - "name": "is_new_nether", - "type": "bool" - }, - { - "name": "experimental_gameplay_override", - "type": "bool" - }, - { - "name": "level_id", - "type": "string" - }, - { - "name": "world_name", - "type": "string" - }, - { - "name": "premium_world_template_id", - "type": "string" - }, - { - "name": "is_trial", - "type": "bool" - }, - { - "name": "movement_authority", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "client", - "1": "server", - "2": "server_with_rewind" - } - } - ] - }, - { - "name": "rewind_history_size", - "type": "zigzag32" - }, - { - "name": "server_authoritative_block_breaking", - "type": "bool" - }, - { - "name": "current_tick", - "type": "li64" - }, - { - "name": "enchantment_seed", - "type": "zigzag32" - }, - { - "name": "block_properties", - "type": "BlockProperties" - }, - { - "name": "itemstates", - "type": "Itemstates" - }, - { - "name": "multiplayer_correlation_id", - "type": "string" - }, - { - "name": "server_authoritative_inventory", - "type": "bool" - }, - { - "name": "engine", - "type": "string" - } - ] - ], - "packet_add_player": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "username", - "type": "string" - }, - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "platform_chat_id", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "held_item", - "type": "Item" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "flags", - "type": "varint" - }, - { - "name": "command_permission", - "type": "varint" - }, - { - "name": "action_permissions", - "type": "varint" - }, - { - "name": "permission_level", - "type": "varint" - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - }, - { - "name": "links", - "type": "Links" - }, - { - "name": "device_id", - "type": "string" - }, - { - "name": "device_os", - "type": "li32" - } - ] - ], - "packet_add_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "attributes", - "type": "EntityAttributes" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "links", - "type": "Links" - } - ] - ], - "packet_remove_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - } - ] - ], - "packet_add_item_entity": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "is_from_fishing", - "type": "bool" - } - ] - ], - "packet_take_item_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "target", - "type": "varint" - } - ] - ], - "packet_move_entity": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "rotation", - "type": "Rotation" - } - ] - ], - "packet_move_player": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "normal", - "1": "reset", - "2": "teleport", - "3": "rotation" - } - } - ] - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "ridden_runtime_id", - "type": "varint" - }, - { - "name": "teleport", - "type": [ - "switch", - { - "compareTo": "mode", - "fields": { - "teleport": [ - "container", - [ - { - "name": "cause", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "unknown", - "1": "projectile", - "2": "chorus_fruit", - "3": "command", - "4": "behavior" - } - } - ] - }, - { - "name": "source_entity_type", - "type": "LegacyEntityType" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_rider_jump": [ - "container", - [ - { - "name": "jump_strength", - "type": "zigzag32" - } - ] - ], - "packet_update_block": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - } - ] - ], - "packet_add_painting": [ - "container", - [ - { - "name": "entity_id_self", - "type": "zigzag64" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "coordinates", - "type": "vec3f" - }, - { - "name": "direction", - "type": "zigzag32" - }, - { - "name": "title", - "type": "string" - } - ] - ], - "packet_tick_sync": [ - "container", - [ - { - "name": "request_time", - "type": "li64" - }, - { - "name": "response_time", - "type": "li64" - } - ] - ], - "packet_level_sound_event_old": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "zigzag32" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event": [ - "container", - [ - { - "name": "event", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "1000": "sound_click", - "1001": "sound_click_fail", - "1002": "sound_shoot", - "1003": "sound_door", - "1004": "sound_fizz", - "1005": "sound_ignite", - "1007": "sound_ghast", - "1008": "sound_ghast_shoot", - "1009": "sound_blaze_shoot", - "1010": "sound_door_bump", - "1012": "sound_door_crash", - "1018": "sound_enderman_teleport", - "1020": "sound_anvil_break", - "1021": "sound_anvil_use", - "1022": "sound_anvil_fall", - "1030": "sound_pop", - "1032": "sound_portal", - "1040": "sound_itemframe_add_item", - "1041": "sound_itemframe_remove", - "1042": "sound_itemframe_place", - "1043": "sound_itemframe_remove_item", - "1044": "sound_itemframe_rotate_item", - "1050": "sound_camera", - "1051": "sound_orb", - "1052": "sound_totem", - "1060": "sound_armor_stand_break", - "1061": "sound_armor_stand_hit", - "1062": "sound_armor_stand_fall", - "1063": "sound_armor_stand_place", - "1064": "pointed_dripstone_land", - "1065": "dye_used", - "1066": "ink_sack_used", - "2000": "particle_shoot", - "2001": "particle_destroy", - "2002": "particle_splash", - "2003": "particle_eye_despawn", - "2004": "particle_spawn", - "2005": "particle_crop_growth", - "2006": "particle_guardian_curse", - "2007": "particle_death_smoke", - "2008": "particle_block_force_field", - "2009": "particle_projectile_hit", - "2010": "particle_dragon_egg_teleport", - "2011": "particle_crop_eaten", - "2012": "particle_critical", - "2013": "particle_enderman_teleport", - "2014": "particle_punch_block", - "2015": "particle_bubble", - "2016": "particle_evaporate", - "2017": "particle_destroy_armor_stand", - "2018": "particle_breaking_egg", - "2019": "particle_destroy_egg", - "2020": "particle_evaporate_water", - "2021": "particle_destroy_block_no_sound", - "2022": "particle_knockback_roar", - "2023": "particle_teleport_trail", - "2024": "particle_point_cloud", - "2025": "particle_explosion", - "2026": "particle_block_explosion", - "2027": "particle_vibration_signal", - "2028": "particle_dripstone_drip", - "2029": "particle_fizz_effect", - "2030": "particle_wax_on", - "2031": "particle_wax_off", - "2032": "particle_scrape", - "2033": "particle_electric_spark", - "3001": "start_rain", - "3002": "start_thunder", - "3003": "stop_rain", - "3004": "stop_thunder", - "3005": "pause_game", - "3006": "pause_game_no_screen", - "3007": "set_game_speed", - "3500": "redstone_trigger", - "3501": "cauldron_explode", - "3502": "cauldron_dye_armor", - "3503": "cauldron_clean_armor", - "3504": "cauldron_fill_potion", - "3505": "cauldron_take_potion", - "3506": "cauldron_fill_water", - "3507": "cauldron_take_water", - "3508": "cauldron_add_dye", - "3509": "cauldron_clean_banner", - "3600": "block_start_break", - "3601": "block_stop_break", - "4000": "set_data", - "9800": "players_sleeping", - "16384": "add_particle_mask", - "16385": "particle_bubble", - "16386": "particle_bubble_manual", - "16387": "particle_critical", - "16388": "particle_block_force_field", - "16389": "particle_smoke", - "16390": "particle_explode", - "16391": "particle_evaporation", - "16392": "particle_flame", - "16393": "particle_candle_flame", - "16394": "particle_lava", - "16395": "particle_large_smoke", - "16396": "particle_redstone", - "16397": "particle_rising_red_dust", - "16398": "particle_item_break", - "16399": "particle_snowball_poof", - "16400": "particle_huge_explode", - "16401": "particle_huge_explode_seed", - "16402": "particle_mob_flame", - "16403": "particle_heart", - "16404": "particle_terrain", - "16405": "particle_town_aura", - "16406": "particle_portal", - "16408": "particle_water_splash", - "16409": "particle_water_splash_manual", - "16410": "particle_water_wake", - "16411": "particle_drip_water", - "16412": "particle_drip_lava", - "16413": "particle_drip_honey", - "16414": "particle_stalactite_drip_water", - "16415": "particle_stalactite_drip_lava", - "16416": "particle_falling_dust", - "16417": "particle_mob_spell", - "16418": "particle_mob_spell_ambient", - "16419": "particle_mob_spell_instantaneous", - "16420": "particle_ink", - "16421": "particle_slime", - "16422": "particle_rain_splash", - "16423": "particle_villager_angry", - "16424": "particle_villager_happy", - "16425": "particle_enchantment_table", - "16426": "particle_tracking_emitter", - "16427": "particle_note", - "16428": "particle_witch_spell", - "16429": "particle_carrot", - "16430": "particle_mob_appearance", - "16431": "particle_end_rod", - "16432": "particle_dragons_breath", - "16433": "particle_spit", - "16434": "particle_totem", - "16435": "particle_food", - "16436": "particle_fireworks_starter", - "16437": "particle_fireworks_spark", - "16438": "particle_fireworks_overlay", - "16439": "particle_balloon_gas", - "16440": "particle_colored_flame", - "16441": "particle_sparkler", - "16442": "particle_conduit", - "16443": "particle_bubble_column_up", - "16444": "particle_bubble_column_down", - "16445": "particle_sneeze", - "16446": "particle_shulker_bullet", - "16447": "particle_bleach", - "16448": "particle_dragon_destroy_block", - "16449": "particle_mycelium_dust", - "16450": "particle_falling_red_dust", - "16451": "particle_campfire_smoke", - "16452": "particle_tall_campfire_smoke", - "16453": "particle_dragon_breath_fire", - "16454": "particle_dragon_breath_trail", - "16455": "particle_blue_flame", - "16456": "particle_soul", - "16457": "particle_obsidian_tear", - "16458": "particle_portal_reverse", - "16459": "particle_snowflake", - "16460": "particle_vibration_signal", - "16461": "particle_sculk_sensor_redstone", - "16462": "particle_spore_blossom_shower", - "16463": "particle_spore_blossom_ambient", - "16464": "particle_wax", - "16465": "particle_electric_spark" - } - } - ] - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_block_event": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "sound", - "1": "change_state" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_entity_event": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "jump", - "2": "hurt_animation", - "3": "death_animation", - "4": "arm_swing", - "5": "stop_attack", - "6": "tame_fail", - "7": "tame_success", - "8": "shake_wet", - "9": "use_item", - "10": "eat_grass_animation", - "11": "fish_hook_bubble", - "12": "fish_hook_position", - "13": "fish_hook_hook", - "14": "fish_hook_tease", - "15": "squid_ink_cloud", - "16": "zombie_villager_cure", - "18": "respawn", - "19": "iron_golem_offer_flower", - "20": "iron_golem_withdraw_flower", - "21": "love_particles", - "22": "villager_angry", - "23": "villager_happy", - "24": "witch_spell_particles", - "25": "firework_particles", - "26": "in_love_particles", - "27": "silverfish_spawn_animation", - "28": "guardian_attack", - "29": "witch_drink_potion", - "30": "witch_throw_potion", - "31": "minecart_tnt_prime_fuse", - "32": "creeper_prime_fuse", - "33": "air_supply_expired", - "34": "player_add_xp_levels", - "35": "elder_guardian_curse", - "36": "agent_arm_swing", - "37": "ender_dragon_death", - "38": "dust_particles", - "39": "arrow_shake", - "57": "eating_item", - "60": "baby_animal_feed", - "61": "death_smoke_cloud", - "62": "complete_trade", - "63": "remove_leash", - "65": "consume_totem", - "66": "player_check_treasure_hunter_achievement", - "67": "entity_spawn", - "68": "dragon_puke", - "69": "item_entity_merge", - "70": "start_swim", - "71": "balloon_pop", - "72": "treasure_hunt", - "73": "agent_summon", - "74": "charged_crossbow", - "75": "fall" - } - } - ] - }, - { - "name": "data", - "type": "zigzag32" - } - ] - ], - "packet_mob_effect": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "event_id", - "type": "u8" - }, - { - "name": "effect_id", - "type": "zigzag32" - }, - { - "name": "amplifier", - "type": "zigzag32" - }, - { - "name": "particles", - "type": "bool" - }, - { - "name": "duration", - "type": "zigzag32" - } - ] - ], - "packet_update_attributes": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "attributes", - "type": "PlayerAttributes" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_inventory_transaction": [ - "container", - [ - { - "name": "transaction", - "type": "Transaction" - } - ] - ], - "packet_mob_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "item", - "type": "Item" - }, - { - "name": "slot", - "type": "u8" - }, - { - "name": "selected_slot", - "type": "u8" - }, - { - "name": "window_id", - "type": "WindowID" - } - ] - ], - "packet_mob_armor_equipment": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "helmet", - "type": "Item" - }, - { - "name": "chestplate", - "type": "Item" - }, - { - "name": "leggings", - "type": "Item" - }, - { - "name": "boots", - "type": "Item" - } - ] - ], - "packet_interact": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "3": "leave_vehicle", - "4": "mouse_over_entity", - "6": "open_inventory" - } - } - ] - }, - { - "name": "target_entity_id", - "type": "varint64" - }, - { - "name": "position", - "type": [ - "switch", - { - "compareTo": "action_id", - "fields": { - "mouse_over_entity": "vec3f", - "leave_vehicle": "vec3f" - }, - "default": "void" - } - ] - } - ] - ], - "packet_block_pick_request": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "y", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "add_user_data", - "type": "bool" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_entity_pick_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "lu64" - }, - { - "name": "selected_slot", - "type": "u8" - } - ] - ], - "packet_player_action": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "action", - "type": "Action" - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "packet_hurt_armor": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_entity_data": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "metadata", - "type": "MetadataDictionary" - }, - { - "name": "tick", - "type": "varint" - } - ] - ], - "packet_set_entity_motion": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - } - ] - ], - "packet_set_entity_link": [ - "container", - [ - { - "name": "link", - "type": "Link" - } - ] - ], - "packet_set_health": [ - "container", - [ - { - "name": "health", - "type": "zigzag32" - } - ] - ], - "packet_set_spawn_position": [ - "container", - [ - { - "name": "spawn_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "player", - "1": "world" - } - } - ] - }, - { - "name": "player_position", - "type": "BlockCoordinates" - }, - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "world_position", - "type": "BlockCoordinates" - } - ] - ], - "packet_animate": [ - "container", - [ - { - "name": "action_id", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "none", - "1": "swing_arm", - "2": "unknown", - "3": "wake_up", - "4": "critical_hit", - "5": "magic_critical_hit", - "6": "row_right", - "7": "row_left" - } - } - ] - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_respawn": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "state", - "type": "u8" - }, - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_container_open": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "runtime_entity_id", - "type": "zigzag64" - } - ] - ], - "packet_container_close": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "server", - "type": "bool" - } - ] - ], - "packet_player_hotbar": [ - "container", - [ - { - "name": "selected_slot", - "type": "varint" - }, - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "select_slot", - "type": "bool" - } - ] - ], - "packet_inventory_content": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "input", - "type": "ItemStacks" - } - ] - ], - "packet_inventory_slot": [ - "container", - [ - { - "name": "window_id", - "type": "WindowIDVarint" - }, - { - "name": "slot", - "type": "varint" - }, - { - "name": "item", - "type": "Item" - } - ] - ], - "packet_container_set_data": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "property", - "type": "zigzag32" - }, - { - "name": "value", - "type": "zigzag32" - } - ] - ], - "packet_crafting_data": [ - "container", - [ - { - "name": "recipes", - "type": "Recipes" - }, - { - "name": "potion_type_recipes", - "type": "PotionTypeRecipes" - }, - { - "name": "potion_container_recipes", - "type": "PotionContainerChangeRecipes" - }, - { - "name": "is_clean", - "type": "bool" - } - ] - ], - "packet_crafting_event": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "recipe_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "inventory", - "1": "crafting", - "2": "workbench" - } - } - ] - }, - { - "name": "recipe_id", - "type": "uuid" - }, - { - "name": "input", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - }, - { - "name": "result", - "type": [ - "array", - { - "countType": "varint", - "type": "Item" - } - ] - } - ] - ], - "packet_gui_data_pick_item": [ - "container", - [ - { - "name": "item_name", - "type": "string" - }, - { - "name": "item_effects", - "type": "string" - }, - { - "name": "hotbar_slot", - "type": "li32" - } - ] - ], - "packet_adventure_settings": [ - "container", - [ - { - "name": "flags", - "type": "AdventureFlags" - }, - { - "name": "command_permission", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "operator", - "2": "host", - "3": "automation", - "4": "admin" - } - } - ] - }, - { - "name": "action_permissions", - "type": "ActionPermissions" - }, - { - "name": "permission_level", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "visitor", - "1": "member", - "2": "operator", - "3": "custom" - } - } - ] - }, - { - "name": "custom_stored_permissions", - "type": "varint" - }, - { - "name": "user_id", - "type": "li64" - } - ] - ], - "packet_block_entity_data": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_player_input": [ - "container", - [ - { - "name": "motion_x", - "type": "lf32" - }, - { - "name": "motion_z", - "type": "lf32" - }, - { - "name": "jumping", - "type": "bool" - }, - { - "name": "sneaking", - "type": "bool" - } - ] - ], - "packet_level_chunk": [ - "container", - [ - { - "name": "x", - "type": "zigzag32" - }, - { - "name": "z", - "type": "zigzag32" - }, - { - "name": "sub_chunk_count", - "type": "varint" - }, - { - "name": "cache_enabled", - "type": "bool" - }, - { - "name": "blobs", - "type": [ - "switch", - { - "compareTo": "cache_enabled", - "fields": { - "true": [ - "container", - [ - { - "name": "hashes", - "type": [ - "array", - { - "countType": "varint", - "type": "lu64" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_set_commands_enabled": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_set_difficulty": [ - "container", - [ - { - "name": "difficulty", - "type": "varint" - } - ] - ], - "packet_change_dimension": [ - "container", - [ - { - "name": "dimension", - "type": "zigzag32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "respawn", - "type": "bool" - } - ] - ], - "packet_set_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_player_list": [ - "container", - [ - { - "name": "records", - "type": "PlayerRecords" - } - ] - ], - "packet_simple_event": [ - "container", - [ - { - "name": "event_type", - "type": "lu16" - } - ] - ], - "packet_event": [ - "container", - [ - { - "name": "runtime_id", - "type": "varint64" - }, - { - "name": "event_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "achievement_awarded", - "1": "entity_interact", - "2": "portal_built", - "3": "portal_used", - "4": "mob_killed", - "5": "cauldron_used", - "6": "player_death", - "7": "boss_killed", - "8": "agent_command", - "9": "agent_created", - "10": "banner_pattern_removed", - "11": "commaned_executed", - "12": "fish_bucketed", - "13": "mob_born", - "14": "pet_died", - "15": "cauldron_block_used", - "16": "composter_block_used", - "17": "bell_block_used", - "18": "actor_definition", - "19": "raid_update", - "20": "player_movement_anomaly", - "21": "player_moement_corrected", - "22": "honey_harvested", - "23": "target_block_hit", - "24": "piglin_barter", - "25": "waxed_or_unwaxed_copper" - } - } - ] - }, - { - "name": "use_player_id", - "type": "u8" - }, - { - "name": "event_data", - "type": "restBuffer" - } - ] - ], - "packet_spawn_experience_orb": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "count", - "type": "zigzag32" - } - ] - ], - "packet_clientbound_map_item_data": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - }, - { - "name": "update_flags", - "type": "UpdateMapFlags" - }, - { - "name": "dimension", - "type": "u8" - }, - { - "name": "locked", - "type": "bool" - }, - { - "name": "included_in", - "type": [ - "switch", - { - "compareTo": "update_flags.initialisation", - "fields": { - "true": [ - "array", - { - "countType": "varint", - "type": "zigzag64" - } - ] - }, - "default": "void" - } - ] - }, - { - "name": "scale", - "type": [ - "switch", - { - "compareTo": "update_flags.initialisation || update_flags.decoration || update_flags.texture", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "tracked", - "type": [ - "switch", - { - "compareTo": "update_flags.decoration", - "fields": { - "true": [ - "container", - [ - { - "name": "objects", - "type": [ - "array", - { - "countType": "varint", - "type": "TrackedObject" - } - ] - }, - { - "name": "decorations", - "type": [ - "array", - { - "countType": "varint", - "type": "MapDecoration" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "texture", - "type": [ - "switch", - { - "compareTo": "update_flags.texture", - "fields": { - "true": [ - "container", - [ - { - "name": "width", - "type": "zigzag32" - }, - { - "name": "height", - "type": "zigzag32" - }, - { - "name": "x_offset", - "type": "zigzag32" - }, - { - "name": "y_offset", - "type": "zigzag32" - }, - { - "name": "pixels", - "type": [ - "array", - { - "countType": "varint", - "type": "varint" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_map_info_request": [ - "container", - [ - { - "name": "map_id", - "type": "zigzag64" - } - ] - ], - "packet_request_chunk_radius": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_chunk_radius_update": [ - "container", - [ - { - "name": "chunk_radius", - "type": "zigzag32" - } - ] - ], - "packet_item_frame_drop_item": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - } - ] - ], - "packet_game_rules_changed": [ - "container", - [ - { - "name": "rules", - "type": "GameRules" - } - ] - ], - "packet_camera": [ - "container", - [ - { - "name": "camera_entity_unique_id", - "type": "zigzag64" - }, - { - "name": "target_player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_boss_event": [ - "container", - [ - { - "name": "boss_entity_id", - "type": "zigzag64" - }, - { - "name": "type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "show_bar", - "1": "register_player", - "2": "hide_bar", - "3": "unregister_player", - "4": "set_bar_progress", - "5": "set_bar_title", - "6": "update_properties", - "7": "texture" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "show_bar": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "progress", - "type": "lf32" - }, - { - "name": "screen_darkening", - "type": "li16" - }, - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "register_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "unregister_player": [ - "container", - [ - { - "name": "player_id", - "type": "zigzag64" - } - ] - ], - "set_bar_progress": [ - "container", - [ - { - "name": "progress", - "type": "lf32" - } - ] - ], - "set_bar_title": [ - "container", - [ - { - "name": "title", - "type": "string" - } - ] - ], - "update_properties": [ - "container", - [ - { - "name": "screen_darkening", - "type": "li16" - }, - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ], - "texture": [ - "container", - [ - { - "name": "color", - "type": "varint" - }, - { - "name": "overlay", - "type": "varint" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_show_credits": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "status", - "type": "zigzag32" - } - ] - ], - "packet_available_commands": [ - "container", - [ - { - "name": "values_len", - "type": "varint" - }, - { - "name": "_enum_type", - "type": [ - "enum_size_based_on_values_len" - ] - }, - { - "name": "enum_values", - "type": [ - "array", - { - "count": "values_len", - "type": "string" - } - ] - }, - { - "name": "suffixes", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - }, - { - "name": "enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "switch", - { - "compareTo": "../_enum_type", - "fields": { - "byte": "u8", - "short": "lu16", - "int": "lu32" - }, - "default": "void" - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "command_data", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "description", - "type": "string" - }, - { - "name": "flags", - "type": "lu16" - }, - { - "name": "permission_level", - "type": "u8" - }, - { - "name": "alias", - "type": "li32" - }, - { - "name": "overloads", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "paramater_name", - "type": "string" - }, - { - "name": "value_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "1": "int", - "2": "float", - "3": "value", - "4": "wildcard_int", - "5": "operator", - "6": "target", - "16": "file_path", - "32": "string", - "40": "position", - "44": "message", - "46": "raw_text", - "50": "json", - "63": "command" - } - } - ] - }, - { - "name": "enum_type", - "type": [ - "mapper", - { - "type": "lu16", - "mappings": { - "16": "valid", - "32": "enum", - "256": "suffixed", - "1024": "soft_enum" - } - } - ] - }, - { - "name": "optional", - "type": "bool" - }, - { - "name": "options", - "type": "CommandFlags" - } - ] - ] - } - ] - } - ] - } - ] - ] - } - ] - }, - { - "name": "dynamic_enums", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "values", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "enum_constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "value_index", - "type": "li32" - }, - { - "name": "enum_index", - "type": "li32" - }, - { - "name": "constraints", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "constraint", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "cheats_enabled", - "1": "operator_permissions", - "2": "host_permissions" - } - } - ] - } - ] - ] - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_command_request": [ - "container", - [ - { - "name": "command", - "type": "string" - }, - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "interval", - "type": "bool" - } - ] - ], - "packet_command_block_update": [ - "container", - [ - { - "name": "is_block", - "type": "bool" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "is_block", - "fields": { - "true": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "impulse", - "1": "repeat", - "2": "chain" - } - } - ] - }, - { - "name": "needs_redstone", - "type": "bool" - }, - { - "name": "conditional", - "type": "bool" - } - ] - ] - }, - "default": [ - "container", - [ - { - "name": "minecart_entity_runtime_id", - "type": "varint64" - } - ] - ] - } - ] - }, - { - "name": "command", - "type": "string" - }, - { - "name": "last_output", - "type": "string" - }, - { - "name": "name", - "type": "string" - }, - { - "name": "should_track_output", - "type": "bool" - }, - { - "name": "tick_delay", - "type": "li32" - }, - { - "name": "execute_on_first_tick", - "type": "bool" - } - ] - ], - "packet_command_output": [ - "container", - [ - { - "name": "origin", - "type": "CommandOrigin" - }, - { - "name": "output_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "last", - "2": "silent", - "3": "all", - "4": "data_set" - } - } - ] - }, - { - "name": "success_count", - "type": "varint" - }, - { - "name": "output", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "success", - "type": "bool" - }, - { - "name": "message_id", - "type": "string" - }, - { - "name": "paramaters", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ] - } - ] - }, - { - "name": "data_set", - "type": [ - "switch", - { - "compareTo": "output_type", - "fields": { - "data_set": "string" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_trade": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "varint" - }, - { - "name": "trade_tier", - "type": "varint" - }, - { - "name": "villager_unique_id", - "type": "varint64" - }, - { - "name": "entity_unique_id", - "type": "varint64" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "new_trading_ui", - "type": "bool" - }, - { - "name": "economic_trades", - "type": "bool" - }, - { - "name": "offers", - "type": "nbt" - } - ] - ], - "packet_update_equipment": [ - "container", - [ - { - "name": "window_id", - "type": "WindowID" - }, - { - "name": "window_type", - "type": "WindowType" - }, - { - "name": "size", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "inventory", - "type": "nbt" - } - ] - ], - "packet_resource_pack_data_info": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "max_chunk_size", - "type": "lu32" - }, - { - "name": "chunk_count", - "type": "lu32" - }, - { - "name": "size", - "type": "lu64" - }, - { - "name": "hash", - "type": "ByteArray" - }, - { - "name": "is_premium", - "type": "bool" - }, - { - "name": "pack_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "addon", - "2": "cached", - "3": "copy_protected", - "4": "behavior", - "5": "persona_piece", - "6": "resources", - "7": "skins", - "8": "world_template" - } - } - ] - } - ] - ], - "packet_resource_pack_chunk_data": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - }, - { - "name": "progress", - "type": "lu64" - }, - { - "name": "payload", - "type": "ByteArray" - } - ] - ], - "packet_resource_pack_chunk_request": [ - "container", - [ - { - "name": "pack_id", - "type": "string" - }, - { - "name": "chunk_index", - "type": "lu32" - } - ] - ], - "packet_transfer": [ - "container", - [ - { - "name": "server_address", - "type": "string" - }, - { - "name": "port", - "type": "lu16" - } - ] - ], - "packet_play_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "volume", - "type": "lf32" - }, - { - "name": "pitch", - "type": "lf32" - } - ] - ], - "packet_stop_sound": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "stop_all", - "type": "bool" - } - ] - ], - "packet_set_title": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "clear", - "1": "reset", - "2": "set_title", - "3": "set_subtitle", - "4": "action_bar_message", - "5": "set_durations", - "6": "set_title_json", - "7": "set_subtitle_json", - "8": "action_bar_message_json" - } - } - ] - }, - { - "name": "text", - "type": "string" - }, - { - "name": "fade_in_time", - "type": "zigzag32" - }, - { - "name": "stay_time", - "type": "zigzag32" - }, - { - "name": "fade_out_time", - "type": "zigzag32" - }, - { - "name": "xuid", - "type": "string" - }, - { - "name": "platform_online_id", - "type": "string" - } - ] - ], - "packet_add_behavior_tree": [ - "container", - [ - { - "name": "behaviortree", - "type": "string" - } - ] - ], - "packet_structure_block_update": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "structure_name", - "type": "string" - }, - { - "name": "data_field", - "type": "string" - }, - { - "name": "include_players", - "type": "bool" - }, - { - "name": "show_bounding_box", - "type": "bool" - }, - { - "name": "structure_block_type", - "type": "zigzag32" - }, - { - "name": "settings", - "type": "StructureBlockSettings" - }, - { - "name": "redstone_save_mode", - "type": "zigzag32" - }, - { - "name": "should_trigger", - "type": "bool" - } - ] - ], - "packet_show_store_offer": [ - "container", - [ - { - "name": "offer_id", - "type": "string" - }, - { - "name": "show_all", - "type": "bool" - } - ] - ], - "packet_purchase_receipt": [ - "container", - [ - { - "name": "receipts", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_player_skin": [ - "container", - [ - { - "name": "uuid", - "type": "uuid" - }, - { - "name": "skin", - "type": "Skin" - }, - { - "name": "skin_name", - "type": "string" - }, - { - "name": "old_skin_name", - "type": "string" - }, - { - "name": "is_verified", - "type": "bool" - } - ] - ], - "packet_sub_client_login": [ - "container", - [ - { - "name": "tokens", - "type": [ - "encapsulated", - { - "lengthType": "varint", - "type": "LoginTokens" - } - ] - } - ] - ], - "packet_initiate_web_socket_connection": [ - "container", - [ - { - "name": "server", - "type": "string" - } - ] - ], - "packet_set_last_hurt_by": [ - "container", - [ - { - "name": "entity_type", - "type": "varint" - } - ] - ], - "packet_book_edit": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "replace_page", - "1": "add_page", - "2": "delete_page", - "3": "swap_pages", - "4": "sign" - } - } - ] - }, - { - "name": "slot", - "type": "u8" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "replace_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "add_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - }, - { - "name": "text", - "type": "string" - }, - { - "name": "photo_name", - "type": "string" - } - ] - ], - "delete_page": [ - "container", - [ - { - "name": "page_number", - "type": "u8" - } - ] - ], - "swap_pages": [ - "container", - [ - { - "name": "page1", - "type": "u8" - }, - { - "name": "page2", - "type": "u8" - } - ] - ], - "sign": [ - "container", - [ - { - "name": "title", - "type": "string" - }, - { - "name": "author", - "type": "string" - }, - { - "name": "xuid", - "type": "string" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_npc_request": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "request_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "set_actions", - "1": "execute_action", - "2": "execute_closing_commands", - "3": "set_name", - "4": "set_skin", - "5": "set_interaction_text" - } - } - ] - }, - { - "name": "command", - "type": "string" - }, - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "set_actions", - "1": "execute_action", - "2": "execute_closing_commands", - "3": "set_name", - "4": "set_skin", - "5": "set_interact_text", - "6": "execute_openining_commands" - } - } - ] - }, - { - "name": "scene_name", - "type": "string" - } - ] - ], - "packet_photo_transfer": [ - "container", - [ - { - "name": "image_name", - "type": "string" - }, - { - "name": "image_data", - "type": "string" - }, - { - "name": "book_id", - "type": "string" - } - ] - ], - "packet_modal_form_request": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_modal_form_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_server_settings_request": [ - "container", - [] - ], - "packet_server_settings_response": [ - "container", - [ - { - "name": "form_id", - "type": "varint" - }, - { - "name": "data", - "type": "string" - } - ] - ], - "packet_show_profile": [ - "container", - [ - { - "name": "xuid", - "type": "string" - } - ] - ], - "packet_set_default_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - } - ] - ], - "packet_remove_objective": [ - "container", - [ - { - "name": "objective_name", - "type": "string" - } - ] - ], - "packet_set_display_objective": [ - "container", - [ - { - "name": "display_slot", - "type": "string" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "display_name", - "type": "string" - }, - { - "name": "criteria_name", - "type": "string" - }, - { - "name": "sort_order", - "type": "zigzag32" - } - ] - ], - "packet_set_score": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "change", - "1": "remove" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "objective_name", - "type": "string" - }, - { - "name": "score", - "type": "li32" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "../action", - "fields": { - "change": [ - "container", - [ - { - "name": "entry_type", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "1": "player", - "2": "entity", - "3": "fake_player" - } - } - ] - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "player": "zigzag64", - "entity": "zigzag64" - }, - "default": "void" - } - ] - }, - { - "name": "custom_name", - "type": [ - "switch", - { - "compareTo": "entry_type", - "fields": { - "fake_player": "string" - }, - "default": "void" - } - ] - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_lab_table": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "combine", - "1": "react" - } - } - ] - }, - { - "name": "position", - "type": "vec3u" - }, - { - "name": "reaction_type", - "type": "u8" - } - ] - ], - "packet_update_block_synced": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "block_runtime_id", - "type": "varint" - }, - { - "name": "flags", - "type": "UpdateBlockFlags" - }, - { - "name": "layer", - "type": "varint" - }, - { - "name": "entity_unique_id", - "type": "zigzag64" - }, - { - "name": "transition_type", - "type": [ - "mapper", - { - "type": "varint64", - "mappings": { - "0": "entity", - "1": "create", - "2": "destroy" - } - } - ] - } - ] - ], - "packet_move_entity_delta": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - }, - { - "name": "flags", - "type": "DeltaMoveFlags" - }, - { - "name": "x", - "type": [ - "switch", - { - "compareTo": "flags.has_x", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "y", - "type": [ - "switch", - { - "compareTo": "flags.has_y", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "z", - "type": [ - "switch", - { - "compareTo": "flags.has_z", - "fields": { - "true": "lf32" - }, - "default": "void" - } - ] - }, - { - "name": "rot_x", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_x", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_y", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_y", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - }, - { - "name": "rot_z", - "type": [ - "switch", - { - "compareTo": "flags.has_rot_z", - "fields": { - "true": "u8" - }, - "default": "void" - } - ] - } - ] - ], - "packet_set_scoreboard_identity": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "i8", - "mappings": { - "0": "register_identity", - "1": "clear_identity" - } - } - ] - }, - { - "name": "entries", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "scoreboard_id", - "type": "zigzag64" - }, - { - "name": "entity_unique_id", - "type": [ - "switch", - { - "compareTo": "../action", - "fields": { - "register_identity": "zigzag64" - }, - "default": "void" - } - ] - } - ] - ] - } - ] - } - ] - ], - "packet_set_local_player_as_initialized": [ - "container", - [ - { - "name": "runtime_entity_id", - "type": "varint64" - } - ] - ], - "packet_update_soft_enum": [ - "container", - [] - ], - "packet_network_stack_latency": [ - "container", - [ - { - "name": "timestamp", - "type": "lu64" - }, - { - "name": "needs_response", - "type": "u8" - } - ] - ], - "packet_script_custom_event": [ - "container", - [ - { - "name": "event_name", - "type": "string" - }, - { - "name": "event_data", - "type": "string" - } - ] - ], - "packet_spawn_particle_effect": [ - "container", - [ - { - "name": "dimension", - "type": "u8" - }, - { - "name": "entity_id", - "type": "zigzag64" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "particle_name", - "type": "string" - } - ] - ], - "packet_available_entity_identifiers": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event_v2": [ - "container", - [ - { - "name": "sound_id", - "type": "u8" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "block_id", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_network_chunk_publisher_update": [ - "container", - [ - { - "name": "coordinates", - "type": "BlockCoordinates" - }, - { - "name": "radius", - "type": "varint" - } - ] - ], - "packet_biome_definition_list": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_level_sound_event": [ - "container", - [ - { - "name": "sound_id", - "type": "SoundType" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "extra_data", - "type": "zigzag32" - }, - { - "name": "entity_type", - "type": "string" - }, - { - "name": "is_baby_mob", - "type": "bool" - }, - { - "name": "is_global", - "type": "bool" - } - ] - ], - "packet_level_event_generic": [ - "container", - [ - { - "name": "event_id", - "type": "varint" - }, - { - "name": "nbt", - "type": "nbtLoop" - } - ] - ], - "packet_lectern_update": [ - "container", - [ - { - "name": "page", - "type": "u8" - }, - { - "name": "page_count", - "type": "u8" - }, - { - "name": "position", - "type": "vec3i" - }, - { - "name": "drop_book", - "type": "bool" - } - ] - ], - "packet_video_stream_connect": [ - "container", - [ - { - "name": "server_uri", - "type": "string" - }, - { - "name": "frame_send_frequency", - "type": "lf32" - }, - { - "name": "action", - "type": "u8" - }, - { - "name": "resolution_x", - "type": "li32" - }, - { - "name": "resolution_y", - "type": "li32" - } - ] - ], - "packet_add_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_remove_ecs_entity": [ - "container", - [ - { - "name": "network_id", - "type": "varint64" - } - ] - ], - "packet_client_cache_status": [ - "container", - [ - { - "name": "enabled", - "type": "bool" - } - ] - ], - "packet_on_screen_texture_animation": [ - "container", - [ - { - "name": "animation_type", - "type": "lu32" - } - ] - ], - "packet_map_create_locked_copy": [ - "container", - [ - { - "name": "original_map_id", - "type": "zigzag64" - }, - { - "name": "new_map_id", - "type": "zigzag64" - } - ] - ], - "packet_structure_template_data_export_request": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "settings", - "type": "StructureBlockSettings" - }, - { - "name": "request_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "export_from_save", - "2": "export_from_load", - "3": "query_saved_structure" - } - } - ] - } - ] - ], - "packet_structure_template_data_export_response": [ - "container", - [ - { - "name": "name", - "type": "string" - }, - { - "name": "success", - "type": "bool" - }, - { - "name": "nbt", - "type": [ - "switch", - { - "compareTo": "success", - "fields": { - "true": "nbt" - }, - "default": "void" - } - ] - }, - { - "name": "response_type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "1": "export", - "2": "query" - } - } - ] - } - ] - ], - "packet_update_block_properties": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_client_cache_blob_status": [ - "container", - [ - { - "name": "misses", - "type": "varint" - }, - { - "name": "haves", - "type": "varint" - }, - { - "name": "missing", - "type": [ - "array", - { - "count": "misses", - "type": "lu64" - } - ] - }, - { - "name": "have", - "type": [ - "array", - { - "count": "haves", - "type": "lu64" - } - ] - } - ] - ], - "packet_client_cache_miss_response": [ - "container", - [ - { - "name": "blobs", - "type": [ - "array", - { - "countType": "varint", - "type": "Blob" - } - ] - } - ] - ], - "packet_education_settings": [ - "container", - [ - { - "name": "CodeBuilderDefaultURI", - "type": "string" - }, - { - "name": "CodeBuilderTitle", - "type": "string" - }, - { - "name": "CanResizeCodeBuilder", - "type": "bool" - }, - { - "name": "HasOverrideURI", - "type": "bool" - }, - { - "name": "OverrideURI", - "type": [ - "switch", - { - "compareTo": "HasOverrideURI", - "fields": { - "true": "string" - }, - "default": "void" - } - ] - }, - { - "name": "HasQuiz", - "type": "bool" - } - ] - ], - "packet_multiplayer_settings": [ - "container", - [ - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "enable_multiplayer", - "1": "disable_multiplayer", - "2": "refresh_join_code" - } - } - ] - } - ] - ], - "packet_settings_command": [ - "container", - [ - { - "name": "command_line", - "type": "string" - }, - { - "name": "suppress_output", - "type": "bool" - } - ] - ], - "packet_anvil_damage": [ - "container", - [ - { - "name": "damage", - "type": "u8" - }, - { - "name": "position", - "type": "BlockCoordinates" - } - ] - ], - "packet_completed_using_item": [ - "container", - [ - { - "name": "used_item_id", - "type": "li16" - }, - { - "name": "use_method", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "0": "equip_armor", - "1": "eat", - "2": "attack", - "3": "consume", - "4": "throw", - "5": "shoot", - "6": "place", - "7": "fill_bottle", - "8": "fill_bucket", - "9": "pour_bucket", - "10": "use_tool", - "11": "interact", - "12": "retrieved", - "13": "dyed", - "14": "traded" - } - } - ] - } - ] - ], - "packet_network_settings": [ - "container", - [ - { - "name": "compression_threshold", - "type": "u16" - } - ] - ], - "packet_player_auth_input": [ - "container", - [ - { - "name": "pitch", - "type": "lf32" - }, - { - "name": "yaw", - "type": "lf32" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "move_vector", - "type": "vec2f" - }, - { - "name": "head_yaw", - "type": "lf32" - }, - { - "name": "input_data", - "type": "InputFlag" - }, - { - "name": "input_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "unknown", - "1": "mouse", - "2": "touch", - "3": "game_pad", - "4": "motion_controller" - } - } - ] - }, - { - "name": "play_mode", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "normal", - "1": "teaser", - "2": "screen", - "3": "viewer", - "4": "reality", - "5": "placement", - "6": "living_room", - "7": "exit_level", - "8": "exit_level_living_room", - "9": "num_modes" - } - } - ] - }, - { - "name": "gaze_direction", - "type": [ - "switch", - { - "compareTo": "play_mode", - "fields": { - "reality": "vec3f" - }, - "default": "void" - } - ] - }, - { - "name": "tick", - "type": "varint64" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "transaction", - "type": [ - "switch", - { - "compareTo": "input_data.item_interact", - "fields": { - "true": [ - "container", - [ - { - "name": "legacy", - "type": "TransactionLegacy" - }, - { - "name": "actions", - "type": "TransactionActions" - }, - { - "name": "data", - "type": "TransactionUseItem" - } - ] - ] - }, - "default": "void" - } - ] - }, - { - "name": "item_stack_request", - "type": [ - "switch", - { - "compareTo": "input_data.item_stack_request", - "fields": { - "true": "ItemStackRequest" - }, - "default": "void" - } - ] - }, - { - "name": "block_action", - "type": [ - "switch", - { - "compareTo": "input_data.block_action", - "fields": { - "true": [ - "array", - { - "countType": "zigzag32", - "type": [ - "container", - [ - { - "name": "action", - "type": "Action" - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "action", - "fields": { - "start_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "abort_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "crack_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "predict_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ], - "continue_break": [ - "container", - [ - { - "name": "position", - "type": "BlockCoordinates" - }, - { - "name": "face", - "type": "zigzag32" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ] - } - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_creative_content": [ - "container", - [ - { - "name": "items", - "type": [ - "array", - { - "countType": "varint", - "type": [ - "container", - [ - { - "name": "entry_id", - "type": "varint" - }, - { - "name": "item", - "type": "ItemLegacy" - } - ] - ] - } - ] - } - ] - ], - "packet_player_enchant_options": [ - "container", - [ - { - "name": "options", - "type": [ - "array", - { - "countType": "varint", - "type": "EnchantOption" - } - ] - } - ] - ], - "packet_item_stack_request": [ - "container", - [ - { - "name": "requests", - "type": [ - "array", - { - "countType": "varint", - "type": "ItemStackRequest" - } - ] - } - ] - ], - "packet_item_stack_response": [ - "container", - [ - { - "name": "responses", - "type": "ItemStackResponses" - } - ] - ], - "packet_player_armor_damage": [ - "container", - [ - { - "name": "type", - "type": "ArmorDamageType" - }, - { - "name": "helmet_damage", - "type": [ - "switch", - { - "compareTo": "type.head", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "chestplate_damage", - "type": [ - "switch", - { - "compareTo": "type.chest", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "leggings_damage", - "type": [ - "switch", - { - "compareTo": "type.legs", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - }, - { - "name": "boots_damage", - "type": [ - "switch", - { - "compareTo": "type.feet", - "fields": { - "true": "zigzag32" - }, - "default": "void" - } - ] - } - ] - ], - "packet_update_player_game_type": [ - "container", - [ - { - "name": "gamemode", - "type": "GameMode" - }, - { - "name": "player_unique_id", - "type": "zigzag64" - } - ] - ], - "packet_position_tracking_db_request": [ - "container", - [ - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "query" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - } - ] - ], - "packet_position_tracking_db_broadcast": [ - "container", - [ - { - "name": "broadcast_action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "update", - "1": "destory", - "2": "not_found" - } - } - ] - }, - { - "name": "tracking_id", - "type": "zigzag32" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_packet_violation_warning": [ - "container", - [ - { - "name": "violation_type", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "malformed" - } - } - ] - }, - { - "name": "severity", - "type": [ - "mapper", - { - "type": "zigzag32", - "mappings": { - "0": "warning", - "1": "final_warning", - "2": "terminating" - } - } - ] - }, - { - "name": "packet_id", - "type": "zigzag32" - }, - { - "name": "reason", - "type": "string" - } - ] - ], - "packet_motion_prediction_hints": [ - "container", - [ - { - "name": "entity_runtime_id", - "type": "varint64" - }, - { - "name": "velocity", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - } - ] - ], - "packet_animate_entity": [ - "container", - [ - { - "name": "animation", - "type": "string" - }, - { - "name": "next_state", - "type": "string" - }, - { - "name": "stop_condition", - "type": "string" - }, - { - "name": "controller", - "type": "string" - }, - { - "name": "blend_out_time", - "type": "lf32" - }, - { - "name": "runtime_entity_ids", - "type": [ - "array", - { - "countType": "varint", - "type": "varint64" - } - ] - } - ] - ], - "packet_camera_shake": [ - "container", - [ - { - "name": "intensity", - "type": "lf32" - }, - { - "name": "duration", - "type": "lf32" - }, - { - "name": "type", - "type": "u8" - }, - { - "name": "action", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "add", - "1": "stop" - } - } - ] - } - ] - ], - "packet_player_fog": [ - "container", - [ - { - "name": "stack", - "type": [ - "array", - { - "countType": "varint", - "type": "string" - } - ] - } - ] - ], - "packet_correct_player_move_prediction": [ - "container", - [ - { - "name": "position", - "type": "vec3f" - }, - { - "name": "delta", - "type": "vec3f" - }, - { - "name": "on_ground", - "type": "bool" - }, - { - "name": "tick", - "type": "varint64" - } - ] - ], - "packet_item_component": [ - "container", - [ - { - "name": "entries", - "type": "ItemComponentList" - } - ] - ], - "packet_filter_text_packet": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "from_server", - "type": "bool" - } - ] - ], - "packet_debug_renderer": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "li32", - "mappings": { - "1": "clear", - "2": "add_cube" - } - } - ] - }, - { - "anon": true, - "type": [ - "switch", - { - "compareTo": "type", - "fields": { - "clear": "void", - "add_cube": [ - "container", - [ - { - "name": "text", - "type": "string" - }, - { - "name": "position", - "type": "vec3f" - }, - { - "name": "red", - "type": "lf32" - }, - { - "name": "green", - "type": "lf32" - }, - { - "name": "blue", - "type": "lf32" - }, - { - "name": "alpha", - "type": "lf32" - }, - { - "name": "duration", - "type": "li64" - } - ] - ] - }, - "default": "void" - } - ] - } - ] - ], - "packet_sync_entity_property": [ - "container", - [ - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_add_volume_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint64" - }, - { - "name": "nbt", - "type": "nbt" - } - ] - ], - "packet_remove_volume_entity": [ - "container", - [ - { - "name": "entity_id", - "type": "varint64" - } - ] - ], - "packet_simulation_type": [ - "container", - [ - { - "name": "type", - "type": [ - "mapper", - { - "type": "u8", - "mappings": { - "0": "game", - "1": "editor", - "2": "test", - "3": "invalid" - } - } - ] - } - ] - ], - "packet_npc_dialogue": [ - "container", - [ - { - "name": "entity_id", - "type": "lu64" - }, - { - "name": "action_type", - "type": [ - "mapper", - { - "type": "varint", - "mappings": { - "0": "open", - "1": "close" - } - } - ] - }, - { - "name": "dialogue", - "type": "string" - }, - { - "name": "screen_name", - "type": "string" - }, - { - "name": "npc_name", - "type": "string" - }, - { - "name": "action_json", - "type": "string" - } - ] - ], - "string": [ - "pstring", - { - "countType": "varint" - } - ], - "ByteArray": [ - "buffer", - { - "countType": "varint" - } - ], - "SignedByteArray": [ - "buffer", - { - "countType": "zigzag32" - } - ], - "LittleString": [ - "pstring", - { - "countType": "li32" - } - ], - "ShortArray": [ - "buffer", - { - "countType": "li16" - } - ], - "MetadataFlags1": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "onfire", - "sneaking", - "riding", - "sprinting", - "action", - "invisible", - "tempted", - "inlove", - "saddled", - "powered", - "ignited", - "baby", - "converting", - "critical", - "can_show_nametag", - "always_show_nametag", - "no_ai", - "silent", - "wallclimbing", - "can_climb", - "swimmer", - "can_fly", - "walker", - "resting", - "sitting", - "angry", - "interested", - "charged", - "tamed", - "orphaned", - "leashed", - "sheared", - "gliding", - "elder", - "moving", - "breathing", - "chested", - "stackable", - "showbase", - "rearing", - "vibrating", - "idling", - "evoker_spell", - "charge_attack", - "wasd_controlled", - "can_power_jump", - "linger", - "has_collision", - "affected_by_gravity", - "fire_immune", - "dancing", - "enchanted", - "show_trident_rope", - "container_private", - "transforming", - "spin_attack", - "swimming", - "bribed", - "pregnant", - "laying_egg", - "rider_can_pick", - "transition_sitting", - "eating", - "laying_down" - ] - } - ], - "MetadataFlags2": [ - "bitflags", - { - "type": "zigzag64", - "big": true, - "flags": [ - "sneezing", - "trusting", - "rolling", - "scared", - "in_scaffolding", - "over_scaffolding", - "fall_through_scaffolding", - "blocking", - "transition_blocking", - "blocked_using_shield", - "blocked_using_damaged_shield", - "sleeping", - "wants_to_wake", - "trade_interest", - "door_breaker", - "breaking_obstruction", - "door_opener", - "illager_captain", - "stunned", - "roaring", - "delayed_attacking", - "avoiding_mobs", - "avoiding_block", - "facing_target_to_range_attack", - "hidden_when_invisible", - "is_in_ui", - "stalking", - "emoting", - "celebrating", - "admiring", - "celebrating_special", - "unknown95", - "ram_attack", - "playing_dead" - ] - } - ], - "UpdateBlockFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "neighbors": 1, - "network": 2, - "no_graphic": 4, - "unused": 8, - "priority": 16 - } - } - ], - "AdventureFlags": [ - "bitflags", - { - "type": "varint", - "flags": { - "world_immutable": 1, - "no_pvp": 2, - "auto_jump": 32, - "allow_flight": 64, - "no_clip": 128, - "world_builder": 256, - "flying": 512, - "muted": 1024 - } - } - ], - "ActionPermissions": [ - "bitflags", - { - "type": "varint", - "flags": { - "mine": 65537, - "doors_and_switches": 65538, - "open_containers": 65540, - "attack_players": 65544, - "attack_mobs": 65552, - "operator": 65568, - "teleport": 65664, - "build": 65792, - "default": 66048 - } - } - ], - "UpdateMapFlags": [ - "bitflags", - { - "type": "varint", - "flags": [ - "void", - "texture", - "decoration", - "initialisation" - ] - } - ], - "CommandFlags": [ - "bitfield", - [ - { - "name": "unused", - "size": 6, - "signed": false - }, - { - "name": "has_semantic_constraint", - "size": 1, - "signed": false - }, - { - "name": "collapse_enum", - "size": 1, - "signed": false - } - ] - ], - "DeltaMoveFlags": [ - "bitflags", - { - "type": "lu16", - "flags": { - "has_x": 1, - "has_y": 2, - "has_z": 4, - "has_rot_x": 8, - "has_rot_y": 16, - "has_rot_z": 32, - "on_ground": 64, - "teleport": 128, - "force_move": 256 - } - } - ], - "InputFlag": [ - "bitflags", - { - "type": "varint64", - "big": true, - "flags": [ - "ascend", - "descend", - "north_jump", - "jump_down", - "sprint_down", - "change_height", - "jumping", - "auto_jumping_in_water", - "sneaking", - "sneak_down", - "up", - "down", - "left", - "right", - "up_left", - "up_right", - "want_up", - "want_down", - "want_down_slow", - "want_up_slow", - "sprinting", - "ascend_block", - "descend_block", - "sneak_toggle_down", - "persist_sneak", - "start_sprinting", - "stop_sprinting", - "start_sneaking", - "stop_sneaking", - "start_swimming", - "stop_swimming", - "start_jumping", - "start_gliding", - "stop_gliding", - "item_interact", - "block_action", - "item_stack_request" - ] - } - ], - "ArmorDamageType": [ - "bitflags", - { - "type": "u8", - "flags": { - "head": 1, - "chest": 2, - "legs": 4, - "feet": 8 - } - } - ] - } -} \ No newline at end of file diff --git a/data/latest/proto.yml b/data/latest/proto.yml deleted file mode 100644 index d2998d1..0000000 --- a/data/latest/proto.yml +++ /dev/null @@ -1,3171 +0,0 @@ -# Created from MiNET and gophertunnel docs -# The version below is the latest version this protocol schema was updated for. -# The output protocol.json will be in the folder for the version -!version: 1.17.10 - -# Some ProtoDef aliases -string: ["pstring",{"countType":"varint"}] # String / array types -ByteArray: ["buffer",{"countType":"varint"}] -SignedByteArray: ["buffer",{"countType":"zigzag32"}] -LittleString: ["pstring",{"countType":"li32"}] -ShortArray: ["buffer",{"countType":"li16"}] -varint64: native # Some primitives -zigzag32: native -zigzag64: native -uuid: native # Data types & special handling -byterot: native -bitflags: native -restBuffer: native -encapsulated: native -nbt: native # NBT -lnbt: native -nbtLoop: native -enum_size_based_on_values_len: native # Packet-specific custom logic -MapInfo: native - -# load the packet map file (auto-generated) -!import: packet_map.yml - -!StartDocs: Packets - -# # Login Sequence -# The login process is as follows: -# -# * C→S: [Login](#packet_login) -# * S→C: [Server To Client Handshake](#packet_server_to_client_handshake) -# * C→S: [Client To Server Handshake](#packet_client_to_server_handshake) -# * S→C: [Play Status (Login success)](#packet_play_status) -# * To spawn, the following packets should be sent, in order, after the ones above: -# * S→C: [Resource Packs Info](#packet_resource_packs_info) -# * C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) -# * S→C: [Resource Pack Stack](#packet_resource_pack_stack) -# * C→S: [Resource Pack Client Response](#packet_resource_pack_client_response) -# * S→C: [Start Game](#packet_start_game) -# * S→C: [Creative Content](#packet_creative_content) -# * S→C: [Biome Definition List](#packet_biome_definition_list) -# * S→C: [Chunks](#packet_level_chunk) -# * S→C: [Play Status (Player spawn)](#packet_play_status) -# -# If there are no resource packs being sent, a Resource Pack Stack can be sent directly -# after Resource Packs Info to avoid the client responses. -# -# === - -packet_login: - !id: 0x01 - !bound: server - # Protocol version (Big Endian!) - protocol_version: i32 - tokens: '["encapsulated", { "lengthType": "varint", "type": "LoginTokens" }]' - -LoginTokens: - # JSON array of JWT data: contains the display name, UUID and XUID - # It should be signed by the Mojang public key - identity: LittleString - # Skin related data - client: LittleString - -packet_play_status: - !id: 0x02 - !bound: client - status: i32 => - # Sent after Login has been successfully decoded and the player has logged in - 0: login_success - # Displays "Could not connect: Outdated client!" - 1: failed_client - # Displays "Could not connect: Outdated server!" - 2: failed_spawn - # Sent after world data to spawn the player - 3: player_spawn - # Displays "Unable to connect to world. Your school does not have access to this server." - 4: failed_invalid_tenant - # Displays "The server is not running Minecraft: Education Edition. Failed to connect." - 5: failed_vanilla_edu - # Displays "The server is running an incompatible edition of Minecraft. Failed to connect." - 6: failed_edu_vanilla - # Displays "Wow this server is popular! Check back later to see if space opens up. Server Full" - 7: failed_server_full - - -packet_server_to_client_handshake: - !id: 0x03 - !bound: client - # Contains the salt to complete the Diffie-Hellman key exchange - token: string - - -# Sent by the client in response to a Server To Client Handshake packet -# sent by the server. It is the first encrypted packet in the login handshake -# and serves as a confirmation that encryption is correctly initialized client side. -# It has no fields. -packet_client_to_server_handshake: - !id: 0x04 - !bound: server - -# Sent by the server to disconnect a client. -packet_disconnect: - !id: 0x05 - !bound: client - # Specifies if the disconnection screen should be hidden when the client is disconnected, - # meaning it will be sent directly to the main menu. - hide_disconnect_reason: bool - # An optional message to show when disconnected. - message: string - - -packet_resource_packs_info: - !id: 0x06 - !bound: client - # If the resource pack requires the client accept it. - must_accept: bool - # If scripting is enabled. - has_scripts: bool - # ForcingServerPacks is currently an unclear field. - force_server_packs: bool - # A list of behaviour packs that the client needs to download before joining the server. - # All of these behaviour packs will be applied together. - behaviour_packs: BehaviourPackInfos - # A list of resource packs that the client needs to download before joining the server. - # The order of these resource packs is not relevant in this packet. It is however important in the Resource Pack Stack packet. - texture_packs: TexturePackInfos - -packet_resource_pack_stack: - !id: 0x07 - !bound: client - # If the resource pack must be accepted for the player to join the server. - must_accept: bool - # [inline] - behavior_packs: ResourcePackIdVersions - # [inline] - resource_packs: ResourcePackIdVersions - game_version: string - experiments: Experiments # ??? such random fields - experiments_previously_used: bool - -packet_resource_pack_client_response: - !id: 0x08 - !bound: server - response_status: u8 => - 0: none - 1: refused - 2: send_packs - 3: have_all_packs - 4: completed - # All of the pack IDs. - resourcepackids: ResourcePackIds - -# Sent by the client to the server to send chat messages, and by the server to the client -# to forward or send messages, which may be chat, popups, tips etc. -## https://github.com/pmmp/PocketMine-MP/blob/a43b46a93cb127f037c879b5d8c29cda251dd60c/src/pocketmine/network/mcpe/protocol/TextPacket.php -## https://github.com/Sandertv/gophertunnel/blob/05ac3f843dd60d48b9ca0ab275cda8d9e85d8c43/minecraft/protocol/packet/text.go -packet_text: - !id: 0x09 - !bound: both - # TextType is the type of the text sent. When a client sends this to the server, it should always be - # TextTypeChat. If the server sends it, it may be one of the other text types above. - type: u8 => - 0: raw - 1: chat - 2: translation - 3: popup - 4: jukebox_popup - 5: tip - 6: system - 7: whisper - 8: announcement - 9: json_whisper - 10: json - # NeedsTranslation specifies if any of the messages need to be translated. It seems that where % is found - # in translatable text types, these are translated regardless of this bool. Translatable text types - # include TextTypeTip, TextTypePopup and TextTypeJukeboxPopup. - needs_translation: bool - _: type? - if chat or whisper or announcement: - source_name: string - message: string - if raw or tip or system or json_whisper or json: - message: string - if translation or popup or jukebox_popup: - message: string - paramaters: string[]varint - # The XUID of the player who sent this message. - xuid: string - # PlatformChatID is an identifier only set for particular platforms when chatting (presumably only for - # Nintendo Switch). It is otherwise an empty string, and is used to decide which players are able to - # chat with each other. - platform_chat_id: string -# For additional information and examples of all the chat types above, see here: https://imgur.com/a/KhcFscg - - -# Sent by the server to update the current time client-side. The client actually advances time -# client-side by itself, so this packet does not need to be sent each tick. It is merely a means -# of synchronizing time between server and client. -packet_set_time: - !id: 0x0a - !bound: client - # Time is the current time. The time is not limited to 24000 (time of day), but continues - # progressing after that. - time: zigzag32 - -# Sent by the server to send information about the world the player will be spawned in. -packet_start_game: - !id: 0x0b - !bound: client - # The unique ID of the player. The unique ID is a value that remains consistent across - # different sessions of the same world, but most unofficial servers simply fill the - # runtime ID of the entity out for this field. - entity_id: zigzag64 - # The runtime ID of the player. The runtime ID is unique for each world session, - # and entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint64 - # PlayerGameMode is the game mode the player currently has. It is a value from 0-4, with 0 being - # survival mode, 1 being creative mode, 2 being adventure mode, 3 being survival spectator and 4 being - # creative spectator. - # This field may be set to 5 to make the client fall back to the game mode set in the WorldGameMode - # field. - player_gamemode: GameMode - # The spawn position of the player in the world. In servers this is often the same as the - # world's spawn position found below. - player_position: vec3f - # The pitch and yaw of the player - rotation: vec2f - # The seed used to generate the world. Unlike in Java edition, the seed is a 32bit Integer here. - seed: zigzag32 - biome_type: li16 - biome_name: string - # Dimension is the ID of the dimension that the player spawns in. It is a value from 0-2, - # with 0 being the overworld, 1 being the nether and 2 being the end. - dimension: zigzag32 - # Generator is the generator used for the world. It is a value from 0-4, with 0 being old - # limited worlds, 1 being infinite worlds, 2 being flat worlds, 3 being nether worlds and - # 4 being end worlds. A value of 0 will actually make the client stop rendering chunks you - # send beyond the world limit. - generator: zigzag32 - # The world game mode that a player gets when it first spawns in the world. It is shown in the - # settings and is used if the Player Gamemode is set to 5. - world_gamemode: GameMode - # Difficulty is the difficulty of the world. It is a value from 0-3, with 0 being peaceful, - # 1 being easy, 2 being normal and 3 being hard. - difficulty: zigzag32 - # The block on which the world spawn of the world. This coordinate has no effect on the place - # that the client spawns, but it does have an effect on the direction that a compass poInts. - spawn_position: BlockCoordinates - # Defines if achievements are disabled in the world. The client crashes if this value is set - # to true while the player's or the world's game mode is creative, and it's recommended to simply - # always set this to false as a server. - achievements_disabled: bool - # The time at which the day cycle was locked if the day cycle is disabled using the respective - # game rule. The client will maIntain this time as Boolean as the day cycle is disabled. - day_cycle_stop_time: zigzag32 - # Some Minecraft: Education Edition field that specifies what 'region' the world was from, - # with 0 being None, 1 being RestOfWorld, and 2 being China. The actual use of this field is unknown. - edu_offer: zigzag32 - # Specifies if the world has education edition features enabled, such as the blocks or entities - # specific to education edition. - edu_features_enabled: bool - edu_product_uuid: string - # The level specifying the Intensity of the rain falling. When set to 0, no rain falls at all. - rain_level: lf32 - lightning_level: lf32 - # The level specifying the Intensity of the thunder. This may actually be set independently - # from the rain level, meaning dark clouds can be produced without rain. - has_confirmed_platform_locked_content: bool - # Specifies if the world is a multi-player game. This should always be set to true for servers. - is_multiplayer: bool - # Specifies if LAN broadcast was Intended to be enabled for the world. - broadcast_to_lan: bool - # The mode used to broadcast the joined game across XBOX Live. - xbox_live_broadcast_mode: varint - # The mode used to broadcast the joined game across the platform. - platform_broadcast_mode: varint - # If commands are enabled for the player. It is recommended to always set this to true on the - # server, as setting it to false means the player cannot, under any circumstance, use a command. - enable_commands: bool - # Specifies if the texture pack the world might hold is required, meaning the client was - # forced to download it before joining. - is_texturepacks_required: bool - # Defines game rules currently active with their respective values. The value of these game - # rules may be either 'bool', 'Int32' or 'Float32'. Some game rules are server side only, - # and don't necessarily need to be sent to the client. - gamerules: GameRules - experiments: Experiments - experiments_previously_used: bool - # Specifies if the world had the bonus map setting enabled when generating it. - # It does not have any effect client-side. - bonus_chest: bool - # Specifies if the world has the start with map setting enabled, meaning each - # joining player obtains a map. This should always be set to false, because the - # client obtains a map all on its own accord if this is set to true. - map_enabled: bool - # The permission level of the player. It is a value from 0-3, with 0 being visitor, - # 1 being member, 2 being operator and 3 being custom. - permission_level: zigzag32 - # The radius around the player in which chunks are ticked. Most servers set this value - # to a fixed number, as it does not necessarily affect anything client-side. - server_chunk_tick_range: li32 - # Specifies if the texture pack of the world is locked, meaning it cannot be disabled - # from the world. This is typically set for worlds on the marketplace that have a dedicated - # texture pack. - has_locked_behavior_pack: bool - # Specifies if the texture pack of the world is locked, meaning it cannot be disabled from the - # world. This is typically set for worlds on the marketplace that have a dedicated texture pack. - has_locked_resource_pack: bool - # Specifies if the world from the server was from a locked world template. - # For servers this should always be set to false. - is_from_locked_world_template: bool - msa_gamertags_only: bool - # Specifies if the world from the server was from a locked world template. - # For servers this should always be set to false. - is_from_world_template: bool - # Specifies if the world was a template that locks all settings that change properties - # above in the settings GUI. It is recommended to set this to true for servers that - # do not allow things such as setting game rules through the GUI. - is_world_template_option_locked: bool - # A hack that Mojang put in place to preserve backwards compatibility with old villagers. - # The his never actually read though, so it has no functionality. - only_spawn_v1_villagers: bool - # The version of the game from which Vanilla features will be used. - # The exact function of this field isn't clear. - game_version: string - limited_world_width: li32 - limited_world_length: li32 - is_new_nether: bool - experimental_gameplay_override: bool - # A base64 encoded world ID that is used to identify the world. - level_id: string - # The name of the world that the player is joining. Note that this field shows up - # above the player list for the rest of the game session, and cannot be changed. - # Setting the server name to this field is recommended. - world_name: string - # A UUID specific to the premium world template that might have been used to - # generate the world. Servers should always fill out an empty String for this. - premium_world_template_id: string - # Specifies if the world was a trial world, meaning features are limited and there - # is a time limit on the world. - is_trial: bool - - # MovementType specifies the way the server handles player movement. Available options are - # packet.AuthoritativeMovementModeClient, packet.AuthoritativeMovementModeServer and - # packet.AuthoritativeMovementModeServerWithRewind, where server the server authoritative types result - # in the client sending PlayerAuthInput packets instead of MovePlayer packets and the rewind mode - # requires sending the tick of movement and several actions. - # - # Specifies if the client or server is authoritative over the movement of the player, - # meaning it controls the movement of it. - ## https://github.com/pmmp/PocketMine-MP/blob/a43b46a93cb127f037c879b5d8c29cda251dd60c/src/pocketmine/network/mcpe/protocol/types/PlayerMovementType.php#L26 - movement_authority: zigzag32 => - 0: client - 1: server - # PlayerAuthInputPacket + a bunch of junk that solves a nonexisting problem - 2: server_with_rewind - # RewindHistorySize is the amount of history to keep at maximum if MovementType is - # packet.AuthoritativeMovementModeServerWithRewind. - rewind_history_size: zigzag32 - # ServerAuthoritativeBlockBreaking specifies if block breaking should be sent through - # packet.PlayerAuthInput or not. This field is somewhat redundant as it is always enabled if - # MovementType is packet.AuthoritativeMovementModeServer or - # packet.AuthoritativeMovementModeServerWithRewind - server_authoritative_block_breaking: bool - - # The total time in ticks that has elapsed since the start of the world. - current_tick: li64 - # The seed used to seed the random used to produce enchantments in the enchantment table. - # Note that the exact correct random implementation must be used to produce the correct - # results both client- and server-side. - enchantment_seed: zigzag32 - - # BlockProperties is a list of all the custom blocks registered on the server. - block_properties: BlockProperties - # A list of all items with their legacy IDs which are available in the game. - # Failing to send any of the items that are in the game will crash mobile clients. - itemstates: Itemstates - # A unique ID specifying the multi-player session of the player. - # A random UUID should be filled out for this field. - multiplayer_correlation_id: string - # ServerAuthoritativeInventory specifies if the server authoritative inventory system is enabled. This - # is a new system introduced in 1.16. Backwards compatibility with the inventory transactions has to - # some extent been preserved, but will eventually be removed. - server_authoritative_inventory: bool - # The server's engine version, used for telemetry - engine: string - -packet_add_player: - !id: 0x0c - !bound: client - # UUID is the UUID of the player. It is the same UUID that the client sent in the - # Login packet at the start of the session. A player with this UUID must exist - # in the player list (built up using the Player List packet) for it to show up in-game. - uuid: uuid - # Username is the name of the player. This username is the username that will be - # set as the initial name tag of the player. - username: string - # The unique ID of the player. The unique ID is a value that remains consistent - # across different sessions of the same world, but most unoffical servers simply - # fill the runtime ID of the player out for this field. - entity_id_self: zigzag64 - # The runtime ID of the player. The runtime ID is unique for each world session, - # and entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint64 - # An identifier only set for particular platforms when chatting (presumably only for - # Nintendo Switch). It is otherwise an empty string, and is used to decide which players - # are able to chat with each other. - platform_chat_id: string - position: vec3f - velocity: vec3f - pitch: lf32 - yaw: lf32 - head_yaw: lf32 - held_item: Item - metadata: MetadataDictionary - flags: varint - command_permission: varint - action_permissions: varint - permission_level: varint - custom_stored_permissions: varint - user_id: li64 - links: Links - device_id: string - device_os: li32 - -packet_add_entity: - !id: 0x0d - !bound: client - entity_id_self: zigzag64 - runtime_entity_id: varint64 - entity_type: string - position: vec3f - velocity: vec3f - pitch: lf32 - yaw: lf32 - head_yaw: lf32 - attributes: EntityAttributes - metadata: MetadataDictionary - links: Links - -packet_remove_entity: - !id: 0x0e - !bound: client - entity_id_self: zigzag64 - -packet_add_item_entity: - !id: 0x0f - !bound: client - entity_id_self: zigzag64 - runtime_entity_id: varint64 - item: Item - position: vec3f - velocity: vec3f - metadata: MetadataDictionary - is_from_fishing: bool - -packet_take_item_entity: - !id: 0x11 - !bound: client - runtime_entity_id: varint64 - target: varint - -# MoveActorAbsolute is sent by the server to move an entity to an absolute position. It is typically used -# for movements where high accuracy isn't needed, such as for long range teleporting. -packet_move_entity: - !id: 0x12 - !bound: both - # EntityRuntimeID is the runtime ID of the entity. The runtime ID is unique for each world session, and - # entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint64 - # Flags is a combination of flags that specify details of the movement. It is a combination of the flags - # above. - flags: u8 - # Position is the position to spawn the entity on. If the entity is on a distance that the player cannot - # see it, the entity will still show up if the player moves closer. - position: vec3f - # Rotation is a Vec3 holding the X, Y and Z rotation of the entity after the movement. This is a Vec3 for - # the reason that projectiles like arrows don't have yaw/pitch, but do have roll. - rotation: Rotation - -# MovePlayer is sent by players to send their movement to the server, and by the server to update the -# movement of player entities to other players. -packet_move_player: - !id: 0x13 - !bound: both - # EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and - # entities are generally identified in packets using this runtime ID. - runtime_id: varint - # Position is the position to spawn the player on. If the player is on a distance that the viewer cannot - # see it, the player will still show up if the viewer moves closer. - position: vec3f - # Pitch is the vertical rotation of the player. Facing straight forward yields a pitch of 0. Pitch is - # measured in degrees. - pitch: lf32 - # Yaw is the horizontal rotation of the player. Yaw is also measured in degrees - yaw: lf32 - # HeadYaw is the same as Yaw, except that it applies specifically to the head of the player. A different - # value for HeadYaw than Yaw means that the player will have its head turned - head_yaw: lf32 - # Mode is the mode of the movement. It specifies the way the player's movement should be shown to other - # players. It is one of the constants below. - mode: u8 => - 0: normal - 1: reset - 2: teleport - 3: rotation - # OnGround specifies if the player is considered on the ground. Note that proxies or hacked clients could - # fake this to always be true, so it should not be taken for granted. - on_ground: bool - # RiddenEntityRuntimeID is the runtime ID of the entity that the player might currently be riding. If not - # riding, this should be left 0. - ridden_runtime_id: varint - teleport: mode ? - if teleport: - # TeleportCause is written only if Mode is MoveModeTeleport. It specifies the cause of the teleportation, - # which is one of the constants above. - cause: li32 => - 0: unknown - 1: projectile - 2: chorus_fruit - 3: command - 4: behavior - # TeleportSourceEntityType is the entity type that caused the teleportation, for example an ender pearl. - # TODO: is this still a integer and not a string? - source_entity_type: LegacyEntityType - tick: varint64 - -packet_rider_jump: - !id: 0x14 - !bound: both - jump_strength: zigzag32 - -# UpdateBlock is sent by the server to update a block client-side, without resending the entire chunk that -# the block is located in. It is particularly useful for small modifications like block breaking/placing. -packet_update_block: - !id: 0x15 - !bound: client - # Position is the block position at which a block is updated. - position: BlockCoordinates - # NewBlockRuntimeID is the runtime ID of the block that is placed at Position after sending the packet - # to the client. - block_runtime_id: varint - # Flags is a combination of flags that specify the way the block is updated client-side. It is a - # combination of the flags above, but typically sending only the BlockUpdateNetwork flag is sufficient. - flags: UpdateBlockFlags - # Layer is the world layer on which the block is updated. For most blocks, this is the first layer, as - # that layer is the default layer to place blocks on, but for blocks inside of each other, this differs. - layer: varint - - -UpdateBlockFlags: [ "bitflags", - { - "type": "varint", - "flags": { - "neighbors": 1, - "network": 2, - "no_graphic": 0b100, - "unused": 0b1000, - "priority": 0b10000, - } - } -] - -packet_add_painting: - !id: 0x16 - !bound: client - entity_id_self: zigzag64 - runtime_entity_id: varint64 - coordinates: vec3f - direction: zigzag32 - title: string - -# TickSync is sent by the client and the server to maintain a synchronized, server-authoritative tick between -# the client and the server. The client sends this packet first, and the server should reply with another one -# of these packets, including the response time. -packet_tick_sync: - !id: 0x17 - !bound: both - # ClientRequestTimestamp is the timestamp on which the client sent this packet to the server. The server - # should fill out that same value when replying. - # The ClientRequestTimestamp is always 0 - request_time: li64 - # ServerReceptionTimestamp is the timestamp on which the server received the packet sent by the client. - # When the packet is sent by the client, this value is 0. - # ServerReceptionTimestamp is generally the current tick of the server. It isn't an actual timestamp, as - # the field implies - response_time: li64 - -packet_level_sound_event_old: - !id: 0x18 - !bound: both - sound_id: u8 - position: vec3f - block_id: zigzag32 - entity_type: zigzag32 - is_baby_mob: bool - is_global: bool - -packet_level_event: - !id: 0x19 - !bound: client - event: zigzag32 => - 1000: sound_click - 1001: sound_click_fail - 1002: sound_shoot - 1003: sound_door - 1004: sound_fizz - 1005: sound_ignite - 1007: sound_ghast - 1008: sound_ghast_shoot - 1009: sound_blaze_shoot - 1010: sound_door_bump - 1012: sound_door_crash - 1018: sound_enderman_teleport - 1020: sound_anvil_break - 1021: sound_anvil_use - 1022: sound_anvil_fall - 1030: sound_pop - 1032: sound_portal - 1040: sound_itemframe_add_item - 1041: sound_itemframe_remove - 1042: sound_itemframe_place - 1043: sound_itemframe_remove_item - 1044: sound_itemframe_rotate_item - 1050: sound_camera - 1051: sound_orb - 1052: sound_totem - 1060: sound_armor_stand_break - 1061: sound_armor_stand_hit - 1062: sound_armor_stand_fall - 1063: sound_armor_stand_place - 1064: pointed_dripstone_land - 1065: dye_used - 1066: ink_sack_used - 2000: particle_shoot #TODO: check 2000-2017 - 2001: particle_destroy - 2002: particle_splash - 2003: particle_eye_despawn - 2004: particle_spawn - 2005: particle_crop_growth - 2006: particle_guardian_curse - 2007: particle_death_smoke - 2008: particle_block_force_field - 2009: particle_projectile_hit - 2010: particle_dragon_egg_teleport - 2011: particle_crop_eaten - 2012: particle_critical - 2013: particle_enderman_teleport - 2014: particle_punch_block - 2015: particle_bubble - 2016: particle_evaporate - 2017: particle_destroy_armor_stand - 2018: particle_breaking_egg - 2019: particle_destroy_egg - 2020: particle_evaporate_water - 2021: particle_destroy_block_no_sound - 2022: particle_knockback_roar - 2023: particle_teleport_trail - 2024: particle_point_cloud - 2025: particle_explosion - 2026: particle_block_explosion - 2027: particle_vibration_signal - 2028: particle_dripstone_drip - 2029: particle_fizz_effect - 2030: particle_wax_on - 2031: particle_wax_off - 2032: particle_scrape - 2033: particle_electric_spark - - 3001: start_rain - 3002: start_thunder - 3003: stop_rain - 3004: stop_thunder - 3005: pause_game #data: 1 to pause, 0 to resume - 3006: pause_game_no_screen #data: 1 to pause, 0 to resume - same effect as normal pause but without screen - 3007: set_game_speed #x coordinate of pos = scale factor (default 1.0) - 3500: redstone_trigger - 3501: cauldron_explode - 3502: cauldron_dye_armor - 3503: cauldron_clean_armor - 3504: cauldron_fill_potion - 3505: cauldron_take_potion - 3506: cauldron_fill_water - 3507: cauldron_take_water - 3508: cauldron_add_dye - 3509: cauldron_clean_banner - 3600: block_start_break - 3601: block_stop_break - 4000: set_data - 9800: players_sleeping - 0x4000: add_particle_mask - # 0x4000 | + particle ID - 16385: particle_bubble # 1 - 16386: particle_bubble_manual # 2 - 16387: particle_critical # 3 - 16388: particle_block_force_field # 4 - 16389: particle_smoke # 5 - 16390: particle_explode # 6 - 16391: particle_evaporation # 7 - 16392: particle_flame # 8 - 16393: particle_candle_flame # 9 - 16394: particle_lava # 10 - 16395: particle_large_smoke # 11 - 16396: particle_redstone # 12 - 16397: particle_rising_red_dust # 13 - 16398: particle_item_break # 14 - 16399: particle_snowball_poof # 15 - 16400: particle_huge_explode # 16 - 16401: particle_huge_explode_seed # 17 - 16402: particle_mob_flame # 18 - 16403: particle_heart # 19 - 16404: particle_terrain # 20 - 16405: particle_town_aura # 21 - 16406: particle_portal # 22 - 16408: particle_water_splash # 24 - 16409: particle_water_splash_manual # 25 - 16410: particle_water_wake # 26 - 16411: particle_drip_water # 27 - 16412: particle_drip_lava # 28 - 16413: particle_drip_honey # 29 - 16414: particle_stalactite_drip_water # 30 - 16415: particle_stalactite_drip_lava # 31 - 16416: particle_falling_dust # 32 - 16417: particle_mob_spell # 33 - 16418: particle_mob_spell_ambient # 34 - 16419: particle_mob_spell_instantaneous # 35 - 16420: particle_ink # 36 - 16421: particle_slime # 37 - 16422: particle_rain_splash # 38 - 16423: particle_villager_angry # 39 - 16424: particle_villager_happy # 40 - 16425: particle_enchantment_table # 41 - 16426: particle_tracking_emitter # 42 - 16427: particle_note # 43 - 16428: particle_witch_spell # 44 - 16429: particle_carrot # 45 - 16430: particle_mob_appearance # 46 - 16431: particle_end_rod # 47 - 16432: particle_dragons_breath # 48 - 16433: particle_spit # 49 - 16434: particle_totem # 50 - 16435: particle_food # 51 - 16436: particle_fireworks_starter # 52 - 16437: particle_fireworks_spark # 53 - 16438: particle_fireworks_overlay # 54 - 16439: particle_balloon_gas # 55 - 16440: particle_colored_flame # 56 - 16441: particle_sparkler # 57 - 16442: particle_conduit # 58 - 16443: particle_bubble_column_up # 59 - 16444: particle_bubble_column_down # 60 - 16445: particle_sneeze # 61 - 16446: particle_shulker_bullet # 62 - 16447: particle_bleach # 63 - 16448: particle_dragon_destroy_block # 64 - 16449: particle_mycelium_dust # 65 - 16450: particle_falling_red_dust # 66 - 16451: particle_campfire_smoke # 67 - 16452: particle_tall_campfire_smoke # 68 - 16453: particle_dragon_breath_fire # 69 - 16454: particle_dragon_breath_trail # 70 - 16455: particle_blue_flame # 71 - 16456: particle_soul # 72 - 16457: particle_obsidian_tear # 73 - 16458: particle_portal_reverse # 74 - 16459: particle_snowflake # 75 - 16460: particle_vibration_signal # 76 - 16461: particle_sculk_sensor_redstone # 77 - 16462: particle_spore_blossom_shower # 78 - 16463: particle_spore_blossom_ambient # 79 - 16464: particle_wax # 80 - 16465: particle_electric_spark # 81 - position: vec3f - data: zigzag32 - -packet_block_event: - !id: 0x1a - !bound: client - # Position is the position of the block that an event occurred at. - position: BlockCoordinates - # EventType is the type of the block event. - # The event type decides the way the event data that follows is used - type: zigzag32 => - 0: sound - 1: change_state - # EventData holds event type specific data. For chests for example, - # opening the chest means the data must be 1 - data: zigzag32 - -packet_entity_event: - !id: 0x1b - !bound: both - runtime_entity_id: varint64 - event_id: u8 => - 1: jump - 2: hurt_animation - 3: death_animation - 4: arm_swing - 5: stop_attack - 6: tame_fail - 7: tame_success - 8: shake_wet - 9: use_item - 10: eat_grass_animation - 11: fish_hook_bubble - 12: fish_hook_position - 13: fish_hook_hook - 14: fish_hook_tease - 15: squid_ink_cloud - 16: zombie_villager_cure - 18: respawn - 19: iron_golem_offer_flower - 20: iron_golem_withdraw_flower - 21: love_particles #breeding - 22: villager_angry - 23: villager_happy - 24: witch_spell_particles - 25: firework_particles - 26: in_love_particles - 27: silverfish_spawn_animation - 28: guardian_attack - 29: witch_drink_potion - 30: witch_throw_potion - 31: minecart_tnt_prime_fuse - 32: creeper_prime_fuse - 33: air_supply_expired - 34: player_add_xp_levels - 35: elder_guardian_curse - 36: agent_arm_swing - 37: ender_dragon_death - 38: dust_particles #not sure what this is - 39: arrow_shake - - 57: eating_item - - 60: baby_animal_feed #green particles, like bonemeal on crops - 61: death_smoke_cloud - 62: complete_trade - 63: remove_leash #data 1 = cut leash - - 65: consume_totem - 66: player_check_treasure_hunter_achievement #mojang... - 67: entity_spawn #used for MinecraftEventing stuff, not needed - 68: dragon_puke #they call this puke particles - 69: item_entity_merge - 70: start_swim - 71: balloon_pop - 72: treasure_hunt - 73: agent_summon - 74: charged_crossbow - 75: fall - data: zigzag32 - -packet_mob_effect: - !id: 0x1c - !bound: client - runtime_entity_id: varint64 - event_id: u8 - effect_id: zigzag32 - amplifier: zigzag32 - particles: bool - duration: zigzag32 - -packet_update_attributes: - !id: 0x1d - !bound: client - runtime_entity_id: varint64 - attributes: PlayerAttributes - tick: varint64 - -# InventoryTransaction is a packet sent by the client. It essentially exists out of multiple sub-packets, -# each of which have something to do with the inventory in one way or another. Some of these sub-packets -# directly relate to the inventory, others relate to interaction with the world, that could potentially -# result in a change in the inventory. -packet_inventory_transaction: - !id: 0x1e - !bound: both - transaction: Transaction - -packet_mob_equipment: - !id: 0x1f - !bound: both - runtime_entity_id: varint64 - item: Item - slot: u8 - selected_slot: u8 - window_id: WindowID - -packet_mob_armor_equipment: - !id: 0x20 - !bound: both - runtime_entity_id: varint64 - helmet: Item - chestplate: Item - leggings: Item - boots: Item - -# Interact is sent by the client when it interacts with another entity in some way. It used to be used for -# normal entity and block interaction, but this is no longer the case now. -packet_interact: - !id: 0x21 - !bound: both - # Action type is the ID of the action that was executed by the player. It is one of the constants that - # may be found above. - action_id: u8 => - 3: leave_vehicle - 4: mouse_over_entity - 6: open_inventory - # TargetEntityRuntimeID is the runtime ID of the entity that the player interacted with. This is empty - # for the InteractActionOpenInventory action type. - target_entity_id: varint64 - # Position associated with the ActionType above. For the InteractActionMouseOverEntity, this is the - # position relative to the entity moused over over which the player hovered with its mouse/touch. For the - # InteractActionLeaveVehicle, this is the position that the player spawns at after leaving the vehicle. - position: action_id ? - if mouse_over_entity or leave_vehicle: vec3f - -packet_block_pick_request: - !id: 0x22 - !bound: server - x: zigzag32 - y: zigzag32 - z: zigzag32 - add_user_data: bool - selected_slot: u8 - -packet_entity_pick_request: - !id: 0x23 - !bound: server - runtime_entity_id: lu64 - selected_slot: u8 - -# PlayerAction is sent by the client when it executes any action, for example starting to sprint, swim, -# starting the breaking of a block, dropping an item, etc. -packet_player_action: - !id: 0x24 - !bound: server - # EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and - # entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint64 - # ActionType is the ID of the action that was executed by the player. It is one of the constants that may - # be found above. - action: Action - # BlockPosition is the position of the target block, if the action with the ActionType set concerned a - # block. If that is not the case, the block position will be zero. - position: BlockCoordinates - # BlockFace is the face of the target block that was touched. If the action with the ActionType set - # concerned a block. If not, the face is always 0. - face: zigzag32 - -packet_hurt_armor: - !id: 0x26 - !bound: client - health: zigzag32 - -packet_set_entity_data: - !id: 0x27 - !bound: both - runtime_entity_id: varint64 - metadata: MetadataDictionary - tick: varint - -# SetActorMotion is sent by the server to change the client-side velocity of an entity. It is usually used -# in combination with server-side movement calculation. -packet_set_entity_motion: - !id: 0x28 - !bound: both - # EntityRuntimeID is the runtime ID of the entity. The runtime ID is unique for each world session, and - # entities are generally identified in packets using this runtime ID. - runtime_entity_id: varint64 - # Velocity is the new velocity the entity gets. This velocity will initiate the client-side movement of - # the entity. - velocity: vec3f - -# SetActorLink is sent by the server to initiate an entity link client-side, meaning one entity will start -# riding another. -packet_set_entity_link: - !id: 0x29 - !bound: client - link: Link - -packet_set_health: - !id: 0x2a - !bound: client - health: zigzag32 - -packet_set_spawn_position: - !id: 0x2b - !bound: client - spawn_type: zigzag32 => - 0: player - 1: world - player_position: BlockCoordinates - dimension: zigzag32 - world_position: BlockCoordinates - -packet_animate: - !id: 0x2c - !bound: both - action_id: zigzag32 => - 0: none - 1: swing_arm - 2: unknown - 3: wake_up - 4: critical_hit - 5: magic_critical_hit - 6: row_right - 7: row_left - runtime_entity_id: varint64 - -packet_respawn: - !id: 0x2d - !bound: both - position: vec3f - state: u8 - runtime_entity_id: varint64 - -# ContainerOpen is sent by the server to open a container client-side. This container must be physically -# present in the world, for the packet to have any effect. Unlike Java Edition, Bedrock Edition requires that -# chests for example must be present and in range to open its inventory. -packet_container_open: - !id: 0x2e - !bound: client - # WindowID is the ID representing the window that is being opened. It may be used later to close the - # container using a ContainerClose packet. - window_id: WindowID - # ContainerType is the type ID of the container that is being opened when opening the container at the - # position of the packet. It depends on the block/entity, and could, for example, be the window type of - # a chest or a hopper, but also a horse inventory. - window_type: WindowType - # ContainerPosition is the position of the container opened. The position must point to a block entity - # that actually has a container. If that is not the case, the window will not be opened and the packet - # will be ignored, if a valid ContainerEntityUniqueID has not also been provided. - coordinates: BlockCoordinates - # ContainerEntityUniqueID is the unique ID of the entity container that was opened. It is only used if - # the ContainerType is one that points to an entity, for example a horse. - runtime_entity_id: zigzag64 - -# ContainerClose is sent by the server to close a container the player currently has opened, which was opened -# using the ContainerOpen packet, or by the client to tell the server it closed a particular container, such -# as the crafting grid. -packet_container_close: - !id: 0x2f - !bound: both - # WindowID is the ID representing the window of the container that should be closed. It must be equal to - # the one sent in the ContainerOpen packet to close the designated window. - window_id: WindowID - # ServerSide determines whether or not the container was force-closed by the server. If this value is - # not set correctly, the client may ignore the packet and respond with a PacketViolationWarning. - server: bool - -# PlayerHotBar is sent by the server to the client. It used to be used to link hot bar slots of the player to -# actual slots in the inventory, but as of 1.2, this was changed and hot bar slots are no longer a free -# floating part of the inventory. -# Since 1.2, the packet has been re-purposed, but its new functionality is not clear. -packet_player_hotbar: - !id: 0x30 - !bound: both - selected_slot: varint - window_id: WindowID - select_slot: bool - -# InventoryContent is sent by the server to update the full content of a particular inventory. It is usually -# sent for the main inventory of the player, but also works for other inventories that are currently opened -# by the player. -packet_inventory_content: - !id: 0x31 - !bound: both - # WindowID is the ID that identifies one of the windows that the client currently has opened, or one of - # the consistent windows such as the main inventory. - window_id: WindowIDVarint - # Content is the new content of the inventory. The length of this slice must be equal to the full size of - # the inventory window updated. - input: ItemStacks - -# InventorySlot is sent by the server to update a single slot in one of the inventory windows that the client -# currently has opened. Usually this is the main inventory, but it may also be the off hand or, for example, -# a chest inventory. -packet_inventory_slot: - !id: 0x32 - !bound: both - # WindowID is the ID of the window that the packet modifies. It must point to one of the windows that the - # client currently has opened. - window_id: WindowIDVarint - # Slot is the index of the slot that the packet modifies. The new item will be set to the slot at this - # index. - slot: varint - # NewItem is the item to be put in the slot at Slot. It will overwrite any item that may currently - # be present in that slot. - item: Item - -# ContainerSetData is sent by the server to update specific data of a single container, meaning a block such -# as a furnace or a brewing stand. This data is usually used by the client to display certain features -# client-side. -packet_container_set_data: - !id: 0x33 - !bound: client - # WindowID is the ID of the window that should have its data set. The player must have a window open with - # the window ID passed, or nothing will happen. - window_id: WindowID - # Key is the key of the property. It is one of the constants that can be found above. Multiple properties - # share the same key, but the functionality depends on the type of the container that the data is set to. - # IF FURNACE: - # 0: furnace_tick_count - # 1: furnace_lit_time - # 2: furnace_lit_duration - # 3: furnace_stored_xp - # 4: furnace_fuel_aux - # IF BREWING STAND: - # 0: brew_time - # 1: brew_fuel_amount - # 2: brew_fuel_total - property: zigzag32 - # Value is the value of the property. Its use differs per property. - value: zigzag32 - -packet_crafting_data: - !id: 0x34 - !bound: client - recipes: Recipes - potion_type_recipes: PotionTypeRecipes - potion_container_recipes: PotionContainerChangeRecipes - is_clean: bool - -# CraftingEvent is sent by the client when it crafts a particular item. Note that this packet may be fully -# ignored, as the InventoryTransaction packet provides all the information required. -packet_crafting_event: - !id: 0x35 - !bound: both - # WindowID is the ID representing the window that the player crafted in. - window_id: WindowID - # CraftingType is a type that indicates the way the crafting was done, for example if a crafting table - # was used. - recipe_type: zigzag32 => - 0: inventory - 1: crafting - 2: workbench - # RecipeUUID is the UUID of the recipe that was crafted. It points to the UUID of the recipe that was - # sent earlier in the CraftingData packet. - recipe_id: uuid - # Input is a list of items that the player put into the recipe so that it could create the Output items. - # These items are consumed in the process. - input: Item[]varint - # Output is a list of items that were obtained as a result of crafting the recipe. - result: Item[]varint - -# GUIDataPickItem is sent by the server to make the client 'select' a hot bar slot. It currently appears to -# be broken however, and does not actually set the selected slot to the hot bar slot set in the packet. -packet_gui_data_pick_item: - !id: 0x36 - !bound: client - # ItemName is the name of the item that shows up in the top part of the popup that shows up when - # selecting an item. It is shown as if an item was selected by the player itself. - item_name: string - # ItemEffects is the line under the ItemName, where the effects of the item are usually situated. - item_effects: string - # HotBarSlot is the hot bar slot to be selected/picked. This does not currently work, so it does not - # matter what number this is. - hotbar_slot: li32 - -# AdventureSettings is sent by the server to update game-play related features, in particular permissions to -# access these features for the client. It includes allowing the player to fly, build and mine, and attack -# entities. Most of these flags should be checked server-side instead of using this packet only. -# The client may also send this packet to the server when it updates one of these settings through the -# in-game settings interface. The server should verify if the player actually has permission to update those -# settings. -packet_adventure_settings: - !id: 0x37 - !bound: both - # Flags is a set of flags that specify certain properties of the player, such as whether or not it can - # fly and/or move through blocks. It is one of the AdventureFlag constants above. - flags: AdventureFlags - # CommandPermissionLevel is a permission level that specifies the kind of commands that the player is - # allowed to use. - command_permission: varint => - 0: normal - 1: operator - 2: host - 3: automation - 4: admin - # ActionPermissions is, much like Flags, a set of flags that specify actions that the player is allowed - # to undertake, such as whether it is allowed to edit blocks, open doors etc. It is a combination of the - # ActionPermission constants above. - action_permissions: ActionPermissions - # PermissionLevel is the permission level of the player as it shows up in the player list built up using - # the PlayerList packet. It is one of the PermissionLevel constants above. - permission_level: varint => - 0: visitor - 1: member - 2: operator - 3: custom - # Custom permissions - custom_stored_permissions: varint - # PlayerUniqueID is a unique identifier of the player. It appears it is not required to fill this field - # out with a correct value. Simply writing 0 seems to work. - user_id: li64 - -AdventureFlags: [ "bitflags", - { - "type": "varint", - "flags": { - "world_immutable": 1, - "no_pvp": 2, - "auto_jump": 0x20, - "allow_flight": 0x40, - "no_clip": 0x80, - "world_builder": 0x100, - "flying": 0x200, - "muted": 0x400 - } - } -] - -ActionPermissions: [ "bitflags", - { - "type": "varint", - "flags": { - "mine": 0x10001, - "doors_and_switches": 0x10002, - "open_containers": 0x10004, - "attack_players": 0x10008, - "attack_mobs": 0x10010, - "operator": 0x10020, - "teleport": 0x10080, - "build": 0x10100, - "default": 0x10200 - } - } -] - -packet_block_entity_data: - !id: 0x38 - !bound: both - position: BlockCoordinates - nbt: nbt - -packet_player_input: - !id: 0x39 - !bound: server - motion_x: lf32 - motion_z: lf32 - jumping: bool - sneaking: bool - -# LevelChunk is sent by the server to provide the client with a chunk of a world data (16xYx16 blocks). -# Typically a certain amount of chunks is sent to the client before sending it the spawn PlayStatus packet, -# so that the client spawns in a loaded world. -packet_level_chunk: - !id: 0x3a - !bound: client - # ChunkX is the X coordinate of the chunk sent. (To translate a block's X to a chunk's X: x >> 4) - x: zigzag32 - # ChunkZ is the Z coordinate of the chunk sent. (To translate a block's Z to a chunk's Z: z >> 4) - z: zigzag32 - # SubChunkCount is the amount of sub chunks that are part of the chunk sent. Depending on if the cache - # is enabled, a list of blob hashes will be sent, or, if disabled, the sub chunk data. - sub_chunk_count: varint - # CacheEnabled specifies if the client blob cache should be enabled. This system is based on hashes of - # blobs which are consistent and saved by the client in combination with that blob, so that the server - # does not have to send the same chunk multiple times. If the client does not yet have a blob with the hash sent, - # it will send a ClientCacheBlobStatus packet containing the hashes is does not have the data of. - cache_enabled: bool - blobs: cache_enabled? - if true: - # BlobHashes is a list of all blob hashes used in the chunk. It is composed of SubChunkCount + 1 hashes, - # with the first SubChunkCount hashes being those of the sub chunks and the last one that of the biome - # of the chunk. - # If CacheEnabled is set to false, BlobHashes can be left empty. - hashes: lu64[]varint - # RawPayload is a serialised string of chunk data. The data held depends on if CacheEnabled is set to - # true. If set to false, the payload is composed of multiple sub-chunks, each of which carry a version - # which indicates the way they are serialised, followed by biomes, border blocks and tile entities. If - # CacheEnabled is true, the payload consists out of the border blocks and tile entities only. - payload: ByteArray - -packet_set_commands_enabled: - !id: 0x3b - !bound: client - enabled: bool - -packet_set_difficulty: - !id: 0x3c - !bound: client - difficulty: varint - -packet_change_dimension: - !id: 0x3d - !bound: client - dimension: zigzag32 - position: vec3f - respawn: bool - -# SetPlayerGameType is sent by the server to update the game type (game mode) of the player -packet_set_player_game_type: - !id: 0x3e - !bound: both - # The new gamemode for the player. - # Some of these game types require additional flags to be set in an AdventureSettings packet for - # the game mode to obtain its full functionality. - gamemode: GameMode - -packet_player_list: - !id: 0x3f - !bound: client - records: PlayerRecords - -packet_simple_event: - !id: 0x40 - !bound: client - event_type: lu16 - -# Event is sent by the server to send an event with additional data. It is typically sent to the client for -# telemetry reasons, much like the SimpleEvent packet. -packet_event: - !id: 0x41 - !bound: client - runtime_id: varint64 - event_type: zigzag32 => - 0: achievement_awarded - 1: entity_interact - 2: portal_built - 3: portal_used - 4: mob_killed - 5: cauldron_used - 6: player_death - 7: boss_killed - 8: agent_command - 9: agent_created - 10: banner_pattern_removed - 11: commaned_executed - 12: fish_bucketed - 13: mob_born - 14: pet_died - 15: cauldron_block_used - 16: composter_block_used - 17: bell_block_used - 18: actor_definition - 19: raid_update - 20: player_movement_anomaly - 21: player_moement_corrected - 22: honey_harvested - 23: target_block_hit - 24: piglin_barter - 25: waxed_or_unwaxed_copper - use_player_id: u8 - event_data: restBuffer # Unknown data, TODO: add - -packet_spawn_experience_orb: - !id: 0x42 - !bound: client - position: vec3f - count: zigzag32 - -UpdateMapFlags: [ "bitflags", { - "type": "varint", - "flags": [ - "void", - "texture", - "decoration", - "initialisation" - ] -}] - -# ClientBoundMapItemData is sent by the server to the client to update the data of a map shown to the client. -# It is sent with a combination of flags that specify what data is updated. -# The ClientBoundMapItemData packet may be used to update specific parts of the map only. It is not required -# to send the entire map each time when updating one part. -packet_clientbound_map_item_data: - !id: 0x43 - !bound: client - # MapID is the unique identifier that represents the map that is updated over network. It remains - # consistent across sessions. - map_id: zigzag64 - # UpdateFlags is a combination of flags found above that indicate what parts of the map should be updated - # client-side. - update_flags: UpdateMapFlags - # Dimension is the dimension of the map that should be updated, for example the overworld (0), the nether - # (1) or the end (2). - dimension: u8 - # LockedMap specifies if the map that was updated was a locked map, which may be done using a cartography - # table. - locked: bool - # The following fields apply only for the MapUpdateFlagInitialisation. - # MapsIncludedIn holds an array of map IDs that the map updated is included in. This has to do with the - # scale of the map: Each map holds its own map ID and all map IDs of maps that include this map and have - # a bigger scale. This means that a scale 0 map will have 5 map IDs in this slice, whereas a scale 4 map - # will have only 1 (its own). - # The actual use of this field remains unknown. - included_in: update_flags.initialisation ? - if true: zigzag64[]varint - # Scale is the scale of the map as it is shown in-game. It is written when any of the MapUpdateFlags are - # set to the UpdateFlags field. - scale: update_flags.initialisation || update_flags.decoration || update_flags.texture ? - if true: u8 - # The following fields apply only for the MapUpdateFlagDecoration. - # TrackedObjects is a list of tracked objects on the map, which may either be entities or blocks. The - # client makes sure these tracked objects are actually tracked. (position updated etc.) - tracked: update_flags.decoration ? - if true: - objects: TrackedObject[]varint - decorations: MapDecoration[]varint - # Updates to the map contents itself (texture) - texture: update_flags.texture ? - if true: - # Width is the width of the texture area that was updated. The width may be a subset of the total width - # of the map. - width: zigzag32 - # Height is the height of the texture area that was updated. The height may be a subset of the total - # height of the map - height: zigzag32 - # XOffset is the X offset in pixels at which the updated texture area starts. From this X, the updated - # texture will extend exactly Width pixels to the right. - x_offset: zigzag32 - # YOffset is the Y offset in pixels at which the updated texture area starts. From this Y, the updated - # texture will extend exactly Height pixels up. - y_offset: zigzag32 - # Pixels is a list of pixel colours for the new texture of the map. It is indexed as Pixels[y][x], with - # the length of the outer slice having to be exactly Height long and the inner slices exactly Width long. - # To access this array, use $width * y + x - pixels: varint[]varint - - -packet_map_info_request: - !id: 0x44 - !bound: both - map_id: zigzag64 - -# RequestChunkRadius is sent by the client to the server to update the server on the chunk view radius that -# it has set in the settings. The server may respond with a ChunkRadiusUpdated packet with either the chunk -# radius requested, or a different chunk radius if the server chooses so. -packet_request_chunk_radius: - !id: 0x45 - !bound: both - # ChunkRadius is the requested chunk radius. This value is always the value set in the settings of the - # player. - chunk_radius: zigzag32 - -# ChunkRadiusUpdated is sent by the server in response to a RequestChunkRadius packet. It defines the chunk -# radius that the server allows the client to have. This may be lower than the chunk radius requested by the -# client in the RequestChunkRadius packet. -packet_chunk_radius_update: - !id: 0x46 - !bound: client - # ChunkRadius is the final chunk radius that the client will adapt when it receives the packet. It does - # not have to be the same as the requested chunk radius. - chunk_radius: zigzag32 - -packet_item_frame_drop_item: - !id: 0x47 - !bound: both - coordinates: BlockCoordinates - -packet_game_rules_changed: - !id: 0x48 - !bound: client - rules: GameRules - -# Camera is sent by the server to use an Education Edition camera on a player. It produces an image -# client-side. -packet_camera: - !id: 0x49 - !bound: client - # CameraEntityUniqueID is the unique ID of the camera entity from which the picture was taken. - camera_entity_unique_id: zigzag64 - # TargetPlayerUniqueID is the unique ID of the target player. The unique ID is a value that remains - # consistent across different sessions of the same world, but most servers simply fill the runtime ID of - # the player out for this field. - target_player_unique_id: zigzag64 - -packet_boss_event: - !id: 0x4a - !bound: both - boss_entity_id: zigzag64 - type: varint => - # S2C: Shows the boss-bar to the player. - 0: show_bar - # C2S: Registers a player to a boss fight. - 1: register_player - # S2C: Removes the boss-bar from the client. - 2: hide_bar - # C2S: Unregisters a player from a boss fight. - 3: unregister_player - # S2C: Sets the bar percentage. - 4: set_bar_progress - # S2C: Sets title of the bar. - 5: set_bar_title - # S2C: darkens the sky - 6: update_properties - # S2C: Not implemented :( Intended to alter bar appearance, but these currently produce no effect on client-side whatsoever. - 7: texture - _: type? - if show_bar: - # BossBarTitle is the title shown above the boss bar. It currently does not function, and instead uses - # the name tag of the boss entity at all times. It is only set if the EventType is BossEventShow or - # BossEventTitle. - title: string - # HealthPercentage is the percentage of health that is shown in the boss bar. It currently does not - # function, and instead uses the health percentage of the boss entity at all times. It is only set if the - # EventType is BossEventShow or BossEventHealthPercentage. - progress: lf32 - # ScreenDarkening currently seems not to do anything. - screen_darkening: li16 - # Colour is the colour of the boss bar that is shown when a player is subscribed. It currently does not - # function. It is only set if the EventType is BossEventShow, BossEventAppearanceProperties or - # BossEventTexture. - # Format is ARGB - color: varint - # Overlay is the overlay of the boss bar that is shown on top of the boss bar when a player is - # subscribed. It currently does not function. It is only set if the EventType is BossEventShow, - # BossEventAppearanceProperties or BossEventTexture. - overlay: varint - if register_player or unregister_player: - # PlayerUniqueID is the unique ID of the player that is registered to or unregistered from the boss - # fight. It is set if EventType is either BossEventRegisterPlayer or BossEventUnregisterPlayer. - player_id: zigzag64 - if set_bar_progress: - progress: lf32 - if set_bar_title: - title: string - if update_properties: - screen_darkening: li16 - color: varint - overlay: varint - if texture: - color: varint - overlay: varint - -packet_show_credits: - !id: 0x4b - !bound: client - runtime_entity_id: varint64 - status: zigzag32 - -# This packet sends a list of commands to the client. Commands can have -# arguments, and some of those arguments can have 'enum' values, which are a list of possible -# values for the argument. The serialization is rather complex and involves palettes like chunks. -## In bedrock-protocol, listen to on('client.commands') for a simpler representation -packet_available_commands: - !id: 0x4c - !bound: client - # The length of the enums for all the command paramaters in this packet - values_len: varint - # Not read from stream: instead calculated from the `values_len` field - # - # If the values_len < 0xff => byte, - # If the values_len < 0xffff => short, - # If the values_len < 0xffffff => int - _enum_type: '["enum_size_based_on_values_len"]' - # Here all the enum values for all of the possible commands are stored to one array palette - enum_values: string[]$values_len - # Integer paramaters may sometimes have a prefix, such as the XP command: - # /xp [player: target] <- here, the xp command gives experience points - # /xp L [player: target] <- here, the xp command gives experience levels - # This is the palette of suffixes - suffixes: string[]varint - # The list of enum objects - enums: []varint - # The name of the enum - name: string - # The values in the enum - values: []varint - # The indexes to value in the palette - _: ../_enum_type? - if byte: u8 - if short: lu16 - if int: lu32 - command_data: []varint - name: string - description: string - flags: lu16 - permission_level: u8 - alias: li32 - # The list of overload paramaters for this command - overloads: []varint - # Each of the paramaters gets an array of posible overloads - _: []varint - # The name of the paramater shown to the user (the `amount` in `/xp `) - paramater_name: string - value_type: lu16 => - 1: int - 2: float - 3: value - 4: wildcard_int - 5: operator - 6: target - 16: file_path - 32: string - 40: position - 44: message - 46: raw_text - 50: json - 63: command - # In MC, this + prior field are combined to one 32bit bitfield - enum_type: lu16 => - 0x10: valid - 0x20: enum - 0x100: suffixed - 0x400: soft_enum - # Is this paramater required? - optional: bool - # Additinal options for this command (thanks macroshaft...) - options: CommandFlags - # There are two types of enums: static enums which cannot be changed after sending AvaliableCommands, - # (unless you resend the whole packet) and 'soft' or 'dynamic' enums like below which is an array - # that can be updated with the UpdateSoftEnum packet - dynamic_enums: []varint - name: string - values: string[]varint - enum_constraints: []varint - value_index: li32 - enum_index: li32 - constraints: []varint - constraint: u8 => - 0: cheats_enabled - 1: operator_permissions - 2: host_permissions - -# ParamOptionCollapseEnum specifies if the enum (only if the Type is actually an enum type. If not, -# setting this to true has no effect) should be collapsed. This means that the options of the enum are -# never shown in the actual usage of the command, but only as auto-completion, like it automatically does -# with enums that have a big amount of options. To illustrate, it can make -# <$Name: bool>. -CommandFlags: [ "bitfield", [ - { "name": "unused", "size": 6, "signed": false }, # 6 unused upper bits - { "name": "has_semantic_constraint", "size": 1, "signed": false }, - { "name": "collapse_enum", "size": 1, "signed": false } -]] - -# enum_size_based_on_values_len: native - -# CommandRequest is sent by the client to request the execution of a server-side command. Although some -# servers support sending commands using the Text packet, this packet is guaranteed to have the correct -# result. -packet_command_request: - !id: 0x4d - !bound: server - # CommandLine is the raw entered command line. The client does no parsing of the command line by itself - # (unlike it did in the early stages), but lets the server do that. - command: string - # Origin holds information about the command sender that will be returnd back in the command response - origin: CommandOrigin - # Internal specifies if the command request internal. Setting it to false seems to work and the usage of - # this field is not known. - interval: bool - - -# CommandBlockUpdate is sent by the client to update a command block at a specific position. The command -# block may be either a physical block or an entity. -packet_command_block_update: - !id: 0x4e - !bound: server - # Block specifies if the command block updated was an actual physical block. If false, the command block - # is in a minecart and has an entity runtime ID instead. - is_block: bool - # Position is the position of the command block updated. It is only set if Block is set to true. Nothing - # happens if no command block is set at this position. - _: is_block ? - if true: - # Position is the position of the command block updated. It is only set if Block is set to true. Nothing - # happens if no command block is set at this position. - position: BlockCoordinates - # Mode is the mode of the command block. It is either CommandBlockImpulse, CommandBlockChain or - # CommandBlockRepeat. It is only set if Block is set to true. - mode: varint => - 0: impulse - 1: repeat - 2: chain - # NeedsRedstone specifies if the command block needs to be powered by redstone to be activated. If false, - # the command block is always active. The field is only set if Block is set to true. - needs_redstone: bool - # Conditional specifies the behaviour of the command block if the command block before it (the opposite - # side of the direction the arrow if facing) fails to execute. If set to false, it will activate at all - # times, whereas if set to true, it will activate only if the previous command block executed - # successfully. The field is only set if Block is set to true. - conditional: bool - default: - minecart_entity_runtime_id: varint64 - # Command is the command currently entered in the command block. This is the command that is executed - # when the command block is activated. - command: string - # LastOutput is the output of the last command executed by the command block. It may be left empty to - # show simply no output at all, in combination with setting ShouldTrackOutput to false. - last_output: string - # Name is the name of the command block updated. If not empty, it will show this name hovering above the - # command block when hovering over the block with the cursor. - name: string - # ShouldTrackOutput specifies if the command block tracks output. If set to false, the output box won't - # be shown within the command block. - should_track_output: bool - # TickDelay is the delay in ticks between executions of a command block, if it is a repeating command - # block. - tick_delay: li32 - # ExecuteOnFirstTick specifies if the command block should execute on the first tick, AKA as soon as the - # command block is enabled. - execute_on_first_tick: bool - -packet_command_output: - !id: 0x4f - !bound: client - # CommandOrigin is the data specifying the origin of the command. In other words, the source that the - # command request was from, such as the player itself or a websocket server. The client forwards the - # messages in this packet to the right origin, depending on what is sent here. - origin: CommandOrigin - # OutputType specifies the type of output that is sent. - output_type: i8 => - 1: last - 2: silent - 3: all - 4: data_set - # SuccessCount is the amount of times that a command was executed successfully as a result of the command - # that was requested. For servers, this is usually a rather meaningless fields, but for vanilla, this is - # applicable for commands created with Functions. - success_count: varint - # OutputMessages is a list of all output messages that should be sent to the player. Whether they are - # shown or not, depends on the type of the messages. - output: []varint - # Success indicates if the output message was one of a successful command execution. If set to true, the - # output message is by default coloured white, whereas if set to false, the message is by default - # coloured red. - success: bool - # Message is the message that is sent to the client in the chat window. It may either be simply a - # message or a translated built-in string like 'commands.tp.success.coordinates', combined with specific - # parameters below. - message_id: string - # Parameters is a list of parameters that serve to supply the message sent with additional information, - # such as the position that a player was teleported to or the effect that was applied to an entity. - # These parameters only apply for the Minecraft built-in command output. - paramaters: string[]varint - data_set: output_type ? - if data_set: string - default: void - - -# UpdateTrade is sent by the server to update the trades offered by a villager to a player. It is sent at the -# moment that a player interacts with a villager. -packet_update_trade: - !id: 0x50 - !bound: client - # WindowID is the ID that identifies the trading window that the client currently has opened. - window_id: WindowID - # WindowType is an identifier specifying the type of the window opened. In vanilla, it appears this is - # always filled out with 15. - window_type: WindowType - # Size is the amount of trading options that the villager has. - size: varint - # TradeTier is the tier of the villager that the player is trading with. The tier starts at 0 with a - # first two offers being available, after which two additional offers are unlocked each time the tier - # becomes one higher. - trade_tier: varint - # VillagerUniqueID is the unique ID of the villager entity that the player is trading with. The - # TradeTier sent above applies to this villager. - villager_unique_id: varint64 - # EntityUniqueID is the unique ID of the entity (usually a player) for which the trades are updated. The - # updated trades may apply only to this entity. - entity_unique_id: varint64 - # DisplayName is the name displayed at the top of the trading UI. It is usually used to represent the - # profession of the villager in the UI. - display_name: string - # NewTradeUI specifies if the villager should be using the new trade UI (The one added in 1.11.) rather - # than the old one. This should usually be set to true. - new_trading_ui: bool - # Trading based on Minecraft economy - specifies if the prices of the villager's offers are modified by an increase in - # demand for the item. (A mechanic added in 1.11.) Buying more of the same item will increase the price - # of that particular item. - # https://minecraft.gamepedia.com/Trading#Economics - economic_trades: bool - # NBT serialised compound of offers that the villager has. - offers: nbt - -# UpdateEquip is sent by the server to the client upon opening a horse inventory. It is used to set the -# content of the inventory and specify additional properties, such as the items that are allowed to be put -# in slots of the inventory. -packet_update_equipment: - !id: 0x51 - !bound: client - # WindowID is the identifier associated with the window that the UpdateEquip packet concerns. It is the - # ID sent for the horse inventory that was opened before this packet was sent. - window_id: WindowID - # WindowType is the type of the window that was opened. Generally, this is the type of a horse inventory, - # as the packet is specifically made for that. - window_type: WindowType - # Size is the size of the horse inventory that should be opened. A bigger size does, in fact, change the - # amount of slots displayed. - size: u8 - # EntityUniqueID is the unique ID of the entity whose equipment was 'updated' to the player. It is - # typically the horse entity that had its inventory opened. - entity_id: zigzag64 - # `inventory` is a network NBT serialised compound holding the content of the inventory of - # the entity (the equipment) and additional data such as the allowed items for a particular slot, used to - # make sure only saddles can be put in the saddle slot etc. - inventory: nbt - - -# ResourcePackDataInfo is sent by the server to the client to inform the client about the data contained in -# one of the resource packs that are about to be sent. -packet_resource_pack_data_info: - !id: 0x52 - !bound: client - # UUID is the unique ID of the resource pack that the info concerns. - pack_id: string - # DataChunkSize is the maximum size in bytes of the chunks in which the total size of the resource pack - # to be sent will be divided. A size of 1MB (1024*1024) means that a resource pack of 15.5MB will be - # split into 16 data chunks. - max_chunk_size: lu32 - # ChunkCount is the total amount of data chunks that the sent resource pack will exist out of. It is the - # total size of the resource pack divided by the DataChunkSize field. - # The client doesn't actually seem to use this field. Rather, it divides the size by the chunk size to - # calculate it itself. - chunk_count: lu32 - # Size is the total size in bytes that the resource pack occupies. This is the size of the compressed - # archive (zip) of the resource pack. - size: lu64 - # Hash is a SHA256 hash of the content of the resource pack. - hash: ByteArray - # Premium specifies if the resource pack was a premium resource pack, meaning it was bought from the - # Minecraft store. - is_premium: bool - # PackType is the type of the resource pack. It is one of the resource pack types listed. - pack_type: u8 => - 1: addon - 2: cached - 3: copy_protected - 4: behavior - 5: persona_piece - 6: resources - 7: skins - 8: world_template - -# ResourcePackChunkData is sent to the client so that the client can download the resource pack. Each packet -# holds a chunk of the compressed resource pack, of which the size is defined in the ResourcePackDataInfo -# packet sent before. -packet_resource_pack_chunk_data: - !id: 0x53 - !bound: client - # UUID is the unique ID of the resource pack that the chunk of data is taken out of. - pack_id: string - # ChunkIndex is the current chunk index of the chunk. It is a number that starts at 0 and is incremented - # for each resource pack data chunk sent to the client. - chunk_index: lu32 - # DataOffset is the current progress in bytes or offset in the data that the resource pack data chunk is - # taken from. - progress: lu64 - # RawPayload is a byte slice containing a chunk of data from the resource pack. It must be of the same size or - # less than the DataChunkSize set in the ResourcePackDataInfo packet. - payload: ByteArray - -# ResourcePackChunkRequest is sent by the client to request a chunk of data from a particular resource pack, -# that it has obtained information about in a ResourcePackDataInfo packet. -packet_resource_pack_chunk_request: - !id: 0x54 - !bound: server - # UUID is the unique ID of the resource pack that the chunk of data is requested from. - pack_id: string - # ChunkIndex is the requested chunk index of the chunk. It is a number that starts at 0 and is - # incremented for each resource pack data chunk requested. - chunk_index: lu32 - -packet_transfer: - !id: 0x55 - !bound: client - server_address: string - port: lu16 - -packet_play_sound: - !id: 0x56 - !bound: client - name: string - coordinates: BlockCoordinates - volume: lf32 - pitch: lf32 - -packet_stop_sound: - !id: 0x57 - !bound: client - name: string - stop_all: bool - -# SetTitle is sent by the server to make a title, subtitle or action bar shown to a player. It has several -# fields that allow setting the duration of the titles. -packet_set_title: - !id: 0x58 - !bound: client - # ActionType is the type of the action that should be executed upon the title of a player. It is one of - # the constants above and specifies the response of the client to the packet. - type: zigzag32 => - 0: clear - 1: reset - 2: set_title - 3: set_subtitle - 4: action_bar_message - 5: set_durations - 6: set_title_json - 7: set_subtitle_json - 8: action_bar_message_json - # Text is the text of the title, which has a different meaning depending on the ActionType that the - # packet has. The text is the text of a title, subtitle or action bar, depending on the type set. - text: string - # FadeInDuration is the duration that the title takes to fade in on the screen of the player. It is - # measured in 20ths of a second (AKA in ticks). - fade_in_time: zigzag32 - # RemainDuration is the duration that the title remains on the screen of the player. It is measured in - # 20ths of a second (AKA in ticks). - stay_time: zigzag32 - # FadeOutDuration is the duration that the title takes to fade out of the screen of the player. It is - # measured in 20ths of a second (AKA in ticks). - fade_out_time: zigzag32 - # XUID is the XBOX Live user ID of the player, which will remain consistent as long as the player is - # logged in with the XBOX Live account. It is empty if the user is not logged into its XBL account. - xuid: string - # PlatformOnlineID is either a uint64 or an empty string. - platform_online_id: string - -packet_add_behavior_tree: - !id: 0x59 - !bound: client - behaviortree: string - -# StructureBlockUpdate is sent by the client when it updates a structure block using the in-game UI. The -# data it contains depends on the type of structure block that it is. In Minecraft Bedrock Edition v1.11, -# there is only the Export structure block type, but in v1.13 the ones present in Java Edition will, -# according to the wiki, be added too. -packet_structure_block_update: - !id: 0x5a - !bound: client - # Position is the position of the structure block that is updated. - position: BlockCoordinates - # StructureName is the name of the structure that was set in the structure block's UI. This is the name - # used to export the structure to a file. - structure_name: string - # DataField is the name of a function to run, usually used during natural generation. A description can - # be found here: https://minecraft.gamepedia.com/Structure_Block#Data. - data_field: string - # IncludePlayers specifies if the 'Include Players' toggle has been enabled, meaning players are also - # exported by the structure block. - include_players: bool - # ShowBoundingBox specifies if the structure block should have its bounds outlined. A thin line will - # encapsulate the bounds of the structure if set to true. - show_bounding_box: bool - # StructureBlockType is the type of the structure block updated. A list of structure block types that - # will be used can be found in the constants above. - structure_block_type: zigzag32 - # Settings is a struct of settings that should be used for exporting the structure. These settings are - # identical to the last sent in the StructureBlockUpdate packet by the client. - settings: StructureBlockSettings - # RedstoneSaveMode is the mode that should be used to save the structure when used with redstone. In - # Java Edition, this is always stored in memory, but in Bedrock Edition it can be stored either to disk - # or memory. See the constants above for the options. - redstone_save_mode: zigzag32 - # ShouldTrigger specifies if the structure block should be triggered immediately after this packet - # reaches the server. - should_trigger: bool - -# ShowStoreOffer is sent by the server to show a Marketplace store offer to a player. It opens a window -# client-side that displays the item. -# The ShowStoreOffer packet only works on the partnered servers: Servers that are not partnered will not have -# a store buttons show up in the in-game pause menu and will, as a result, not be able to open store offers -# on the client side. Sending the packet does therefore not work when using a proxy that is not connected to -# with the domain of one of the partnered servers. -packet_show_store_offer: - !id: 0x5b - !bound: client - # OfferID is a string that identifies the offer for which a window should be opened. While typically a - # UUID, the ID could be anything. - offer_id: string - # ShowAll specifies if all other offers of the same 'author' as the one of the offer associated with the - # OfferID should also be displayed, alongside the target offer. - show_all: bool - - -# PurchaseReceipt is sent by the client to the server to notify the server it purchased an item from the -# Marketplace store that was offered by the server. The packet is only used for partnered servers. -packet_purchase_receipt: - !id: 0x5c - !bound: server - # Receipts is a list of receipts, or proofs of purchases, for the offers that have been purchased by the - # player. - receipts: string[]varint - -packet_player_skin: - !id: 0x5d - !bound: both - uuid: uuid - skin: Skin - skin_name: string - old_skin_name: string - is_verified: bool - -# SubClientLogin is sent when a sub-client joins the server while another client is already connected to it. -# The packet is sent as a result of split-screen game play, and allows up to four players to play using the -# same network connection. After an initial Login packet from the 'main' client, each sub-client that -# connects sends a SubClientLogin to request their own login. -packet_sub_client_login: - !id: 0x5e - !bound: client - # ConnectionRequest is a string containing information about the player and JWTs that may be used to - # verify if the player is connected to XBOX Live. The connection request also contains the necessary - # client public key to initiate encryption. - # The ConnectionRequest in this packet is identical to the one found in the Login packet. - tokens: '["encapsulated", { "lengthType": "varint", "type": "LoginTokens" }]' - -# AutomationClientConnect is used to make the client connect to a websocket server. This websocket server has -# the ability to execute commands on the behalf of the client and it can listen for certain events fired by -# the client. -packet_initiate_web_socket_connection: - !id: 0x5f - !bound: client - # ServerURI is the URI to make the client connect to. It can be, for example, 'localhost:8000/ws' to - # connect to a websocket server on the localhost at port 8000. - server: string - - -# SetLastHurtBy is sent by the server to let the client know what entity type it was last hurt by. At this -# moment, the packet is useless and should not be used. There is no behaviour that depends on if this -# packet is sent or not. -packet_set_last_hurt_by: - !id: 0x60 - !bound: client - entity_type: varint - -# BookEdit is sent by the client when it edits a book. It is sent each time a modification was made and the -# player stops its typing 'session', rather than simply after closing the book. -packet_book_edit: - !id: 0x61 - !bound: client - type: u8 => - 0: replace_page - 1: add_page - 2: delete_page - 3: swap_pages - 4: sign - slot: u8 - _: type? - if replace_page or add_page: - page_number: u8 - text: string - # Only available on Education Edition. - photo_name: string - if delete_page: - page_number: u8 - if swap_pages: - page1: u8 - page2: u8 - if sign: - title: string - author: string - xuid: string - - -# NPCRequest is sent by the client when it interacts with an NPC. -# The packet is specifically made for Education Edition, where NPCs are available to use. -packet_npc_request: - !id: 0x62 - !bound: both - # EntityRuntimeID is the runtime ID of the NPC entity that the player interacted with. It is the same - # as sent by the server when spawning the entity. - runtime_entity_id: varint64 - # RequestType is the type of the request, which depends on the permission that the player has. It will - # be either a type that indicates that the NPC should show its dialog, or that it should open the - # editing window. - request_type: u8 => - 0: set_actions - 1: execute_action - 2: execute_closing_commands - 3: set_name - 4: set_skin - 5: set_interaction_text - # CommandString is the command string set in the NPC. It may consist of multiple commands, depending on - # what the player set in it. - command: string - # ActionType is the type of the action to execute. - action_type: u8 => - 0: set_actions - 1: execute_action - 2: execute_closing_commands - 3: set_name - 4: set_skin - 5: set_interact_text - 6: execute_openining_commands - # SceneName is the name of the scene. - scene_name: string - -# PhotoTransfer is sent by the server to transfer a photo (image) file to the client. It is typically used -# to transfer photos so that the client can display it in a portfolio in Education Edition. -# While previously usable in the default Bedrock Edition, the displaying of photos in books was disabled and -# the packet now has little use anymore. -packet_photo_transfer: - !id: 0x63 - !bound: server - # PhotoName is the name of the photo to transfer. It is the exact file name that the client will download - # the photo as, including the extension of the file. - image_name: string - # PhotoData is the raw data of the photo image. The format of this data may vary: Formats such as JPEG or - # PNG work, as long as PhotoName has the correct extension. - image_data: string - # BookID is the ID of the book that the photo is associated with. If the PhotoName in a book with this ID - # is set to PhotoName, it will display the photo (provided Education Edition is used). - # The photo image is downloaded to a sub-folder with this book ID. - book_id: string - -# ModalFormRequest is sent by the server to make the client open a form. This form may be either a modal form -# which has two options, a menu form for a selection of options and a custom form for properties. -packet_modal_form_request: - !id: 0x64 - !bound: client - # FormID is an ID used to identify the form. The ID is saved by the client and sent back when the player - # submits the form, so that the server can identify which form was submitted. - form_id: varint - # FormData is a JSON encoded object of form data. The content of the object differs, depending on the - # type of the form sent, which is also set in the JSON. - data: string - -# ModalFormResponse is sent by the client in response to a ModalFormRequest, after the player has submitted -# the form sent. It contains the options/properties selected by the player, or a JSON encoded 'null' if -# the form was closed by clicking the X at the top right corner of the form. -packet_modal_form_response: - !id: 0x65 - !bound: server - # FormID is the form ID of the form the client has responded to. It is the same as the ID sent in the - # ModalFormRequest, and may be used to identify which form was submitted. - form_id: varint - # ResponseData is a JSON encoded value representing the response of the player. If the form was - # cancelled, a JSON encoded 'null' is in the response. For a modal form, the response is either true or - # false, for a menu form, the response is an integer specifying the index of the button clicked, and for - # a custom form, the response is an array containing a value for each element. - data: string - -# ServerSettingsRequest is sent by the client to request the settings specific to the server. These settings -# are shown in a separate tab client-side, and have the same structure as a custom form. -# ServerSettingsRequest has no fields. -packet_server_settings_request: - !id: 0x66 - !bound: server - -# ServerSettingsResponse is optionally sent by the server in response to a ServerSettingsRequest from the -# client. It is structured the same as a ModalFormRequest packet, and if filled out correctly, will show -# a specific tab for the server in the settings of the client. A ModalFormResponse packet is sent by the -# client in response to a ServerSettingsResponse, when the client fills out the settings and closes the -# settings again. -packet_server_settings_response: - !id: 0x67 - !bound: client - # FormID is an ID used to identify the form. The ID is saved by the client and sent back when the player - # submits the form, so that the server can identify which form was submitted. - form_id: varint - # FormData is a JSON encoded object of form data. The content of the object differs, depending on the - # type of the form sent, which is also set in the JSON. - data: string - -# ShowProfile is sent by the server to show the XBOX Live profile of one player to another. -packet_show_profile: - !id: 0x68 - !bound: client - # XUID is the XBOX Live User ID of the player whose profile should be shown to the player. If it is not - # a valid XUID, the client ignores the packet. - xuid: string - -# SetDefaultGameType is sent by the client when it toggles the default game type in the settings UI, and is -# sent by the server when it actually changes the default game type, resulting in the toggle being changed -# in the settings UI. -packet_set_default_game_type: - !id: 0x69 - !bound: client - # GameType is the new game type that is set. When sent by the client, this is the requested new default - # game type. - gamemode: GameMode - -# RemoveObjective is sent by the server to remove a scoreboard objective. It is used to stop showing a -# scoreboard to a player. -packet_remove_objective: - !id: 0x6a - !bound: client - # ObjectiveName is the name of the objective that the scoreboard currently active has. This name must - # be identical to the one sent in the SetDisplayObjective packet. - objective_name: string - -# SetDisplayObjective is sent by the server to display an object as a scoreboard to the player. Once sent, -# it should be followed up by a SetScore packet to set the lines of the packet. -packet_set_display_objective: - !id: 0x6b - !bound: client - # DisplaySlot is the slot in which the scoreboard should be displayed. Available options can be found in - # the constants above. - display_slot: string - # ObjectiveName is the name of the objective that the scoreboard displays. Filling out a random unique - # value for this field works: It is not displayed in the scoreboard. - objective_name: string - # DisplayName is the name, or title, that is displayed at the top of the scoreboard. - display_name: string - # CriteriaName is the name of the criteria that need to be fulfilled in order for the score to be - # increased. This can be any kind of string and does not show up client-side. - criteria_name: string - # SortOrder is the order in which entries on the scoreboard should be sorted. It is one of the constants - # that may be found above. - sort_order: zigzag32 - -# SetScore is sent by the server to send the contents of a scoreboard to the player. It may be used to either -# add, remove or edit entries on the scoreboard. -packet_set_score: - !id: 0x6c - !bound: client - # ActionType is the type of the action to execute upon the scoreboard with the entries that the packet - # has. If ActionType is ScoreboardActionModify, all entries will be added to the scoreboard if not yet - # present, or modified if already present. If set to ScoreboardActionRemove, all scoreboard entries set - # will be removed from the scoreboard. - action: u8 => - 0: change - 1: remove - entries: []varint - scoreboard_id: zigzag64 - objective_name: string - score: li32 - _: ../action ? - if change: - entry_type: i8 => - 1: player - 2: entity - 3: fake_player - entity_unique_id: entry_type ? - if player or entity: zigzag64 - custom_name: entry_type ? - if fake_player: string - -# LabTable is sent by the client to let the server know it started a chemical reaction in Education Edition, -# and is sent by the server to other clients to show the effects. -# The packet is only functional if Education features are enabled. -packet_lab_table: - !id: 0x6d - !bound: both - # ActionType is the type of the action that was executed. It is one of the constants above. Typically, - # only LabTableActionCombine is sent by the client, whereas LabTableActionReact is sent by the server. - action_type: u8 => - 0: combine - 1: react - # Position is the position at which the lab table used was located. - position: vec3u - # ReactionType is the type of the reaction that took place as a result of the items put into the lab - # table. The reaction type can be either that of an item or a particle, depending on whatever the result - # was of the reaction. - reaction_type: u8 - -# UpdateBlockSynced is sent by the server to synchronise the falling of a falling block entity with the -# transitioning back and forth from and to a solid block. It is used to prevent the entity from flickering, -# and is used in places such as the pushing of blocks with pistons. -packet_update_block_synced: - !id: 0x6e - !bound: client - # Position is the block position at which a block is updated. - position: BlockCoordinates - # NewBlockRuntimeID is the runtime ID of the block that is placed at Position after sending the packet - # to the client. - block_runtime_id: varint - # Flags is a combination of flags that specify the way the block is updated client-side. It is a - # combination of the flags above, but typically sending only the BlockUpdateNetwork flag is sufficient. - flags: UpdateBlockFlags - # Layer is the world layer on which the block is updated. For most blocks, this is the first layer, as - # that layer is the default layer to place blocks on, but for blocks inside of each other, this differs. - layer: varint - # EntityUniqueID is the unique ID of the falling block entity that the block transitions to or that the - # entity transitions from. - # Note that for both possible values for TransitionType, the EntityUniqueID should point to the falling - # block entity involved. - entity_unique_id: zigzag64 - # TransitionType is the type of the transition that happened. It is either BlockToEntityTransition, when - # a block placed becomes a falling entity, or EntityToBlockTransition, when a falling entity hits the - # ground and becomes a solid block again. - transition_type: varint64 => - # For falling sand, when a sand turns to an entity - 0: entity - # When sand turns back to a new block - 1: create - 2: destroy - - -# MoveActorDelta is sent by the server to move an entity. The packet is specifically optimised to save as -# much space as possible, by only writing non-zero fields. -# As of 1.16.100, this packet no longer actually contains any deltas. -packet_move_entity_delta: - !id: 0x6f - !bound: client - # EntityRuntimeID is the runtime ID of the entity that is being moved. The packet works provided a - # non-player entity with this runtime ID is present. - runtime_entity_id: varint64 - # Flags is a list of flags that specify what data is in the packet. - flags: DeltaMoveFlags - x: flags.has_x? - if true: lf32 - y: flags.has_y? - if true: lf32 - z: flags.has_z? - if true: lf32 - rot_x: flags.has_rot_x? - if true: u8 # TODO: * implement ByteFloat - rot_y: flags.has_rot_y? - if true: u8 - rot_z: flags.has_rot_z? - if true: u8 - -DeltaMoveFlags: [ "bitflags", - { - "type": "lu16", - "flags": { - "has_x": 0x01, - "has_y": 0x02, - "has_z": 0x04, - "has_rot_x": 0x08, - "has_rot_y": 0x10, - "has_rot_z": 0x20, - "on_ground": 0x40, - "teleport": 0x80, - "force_move": 0x100 - } - } -] - -# SetScoreboardIdentity is sent by the server to change the identity type of one of the entries on a -# scoreboard. This is used to change, for example, an entry pointing to a player, to a fake player when it -# leaves the server, and to change it back to a real player when it joins again. -# In non-vanilla situations, the packet is quite useless. -packet_set_scoreboard_identity: - !id: 0x70 - !bound: client - # ActionType is the type of the action to execute. The action is either ScoreboardIdentityActionRegister - # to associate an identity with the entry, or ScoreboardIdentityActionClear to remove associations with - # an entity. - action: i8 => - 0: register_identity - 1: clear_identity - # Entries is a list of all entries in the packet. Each of these entries points to one of the entries on - # a scoreboard. Depending on ActionType, their identity will either be registered or cleared. - entries: []varint - scoreboard_id: zigzag64 - entity_unique_id: ../action ? - if register_identity: zigzag64 - default: void - - -# SetLocalPlayerAsInitialised is sent by the client in response to a PlayStatus packet with the status set -# to spawn. The packet marks the moment at which the client is fully initialised and can receive any packet -# without discarding it. -packet_set_local_player_as_initialized: - !id: 0x71 - !bound: server - # EntityRuntimeID is the entity runtime ID the player was assigned earlier in the login sequence in the - # StartGame packet. - runtime_entity_id: varint64 - -packet_update_soft_enum: - !id: 0x72 - !bound: client - -# NetworkStackLatency is sent by the server (and the client, on development builds) to measure the latency -# over the entire Minecraft stack, rather than the RakNet latency. It has other usages too, such as the -# ability to be used as some kind of acknowledgement packet, to know when the client has received a certain -# other packet. -packet_network_stack_latency: - !id: 0x73 - !bound: both - # Timestamp is the timestamp of the network stack latency packet. The client will, if NeedsResponse is - # set to true, send a NetworkStackLatency packet with this same timestamp packet in response. - timestamp: lu64 - # NeedsResponse specifies if the sending side of this packet wants a response to the packet, meaning that - # the other side should send a NetworkStackLatency packet back. - needs_response: u8 - -# ScriptCustomEvent is sent by both the client and the server. It is a way to let scripts communicate with -# the server, so that the client can let the server know it triggered an event, or the other way around. -# It is essentially an RPC kind of system. -packet_script_custom_event: - !id: 0x75 - !bound: both - # EventName is the name of the event. The script and the server will use this event name to identify the - # data that is sent. - event_name: string - # EventData is the data of the event. This data is typically a JSON encoded string, that the script is - # able to encode and decode too. - event_data: string - -# SpawnParticleEffect is sent by the server to spawn a particle effect client-side. Unlike other packets that -# result in the appearing of particles, this packet can show particles that are not hardcoded in the client. -# They can be added and changed through behaviour packs to implement custom particles. -packet_spawn_particle_effect: - !id: 0x76 - !bound: client - # Dimension is the dimension that the particle is spawned in. Its exact usage is not clear, as the - # dimension has no direct effect on the particle. - dimension: u8 - # EntityUniqueID is the unique ID of the entity that the spawned particle may be attached to. If this ID - # is not -1, the Position below will be interpreted as relative to the position of the entity associated - # with this unique ID. - entity_id: zigzag64 - # Position is the position that the particle should be spawned at. If the position is too far away from - # the player, it will not show up. - # If EntityUniqueID is not -1, the position will be relative to the position of the entity. - position: vec3f - # ParticleName is the name of the particle that should be shown. This name may point to a particle effect - # that is built-in, or to one implemented by behaviour packs. - particle_name: string - -# AvailableActorIdentifiers is sent by the server at the start of the game to let the client know all -# entities that are available on the server. -packet_available_entity_identifiers: - !id: 0x77 - !bound: client - # SerialisedEntityIdentifiers is a network NBT serialised compound of all entity identifiers that are - # available in the server. - nbt: nbt - -# Not used. Use `packet_level_sound_event`. -packet_level_sound_event_v2: - !id: 0x78 - !bound: both - sound_id: u8 - position: vec3f - block_id: zigzag32 - entity_type: string - is_baby_mob: bool - is_global: bool - -# NetworkChunkPublisherUpdate is sent by the server to change the point around which chunks are and remain -# loaded. This is useful for mini-game servers, where only one area is ever loaded, in which case the -# NetworkChunkPublisherUpdate packet can be sent in the middle of it, so that no chunks ever need to be -# additionally sent during the course of the game. -# In reality, the packet is not extraordinarily useful, and most servers just send it constantly at the -# position of the player. -# If the packet is not sent at all, no chunks will be shown to the player, regardless of where they are sent. -packet_network_chunk_publisher_update: - !id: 0x79 - !bound: client - # Position is the block position around which chunks loaded will remain shown to the client. Most servers - # set this position to the position of the player itself. - coordinates: BlockCoordinates - # Radius is the radius in blocks around Position that chunks sent show up in and will remain loaded in. - # Unlike the RequestChunkRadius and ChunkRadiusUpdated packets, this radius is in blocks rather than - # chunks, so the chunk radius needs to be multiplied by 16. (Or shifted to the left by 4.) - radius: varint - -# BiomeDefinitionList is sent by the server to let the client know all biomes that are available and -# implemented on the server side. It is much like the AvailableActorIdentifiers packet, but instead -# functions for biomes. -packet_biome_definition_list: - !id: 0x7a - !bound: client - # SerialisedBiomeDefinitions is a network NBT serialised compound of all definitions of biomes that are - # available on the server. - nbt: nbt - -# LevelSoundEvent is sent by the server to make any kind of built-in sound heard to a player. It is sent to, -# for example, play a stepping sound or a shear sound. The packet is also sent by the client, in which case -# it could be forwarded by the server to the other players online. If possible, the packets from the client -# should be ignored however, and the server should play them on its own accord. -packet_level_sound_event: - !id: 0x7b - !bound: both - # SoundType is the type of the sound to play. Some of the sound types - # require additional data, which is set in the EventData field. - sound_id: SoundType - # Position is the position of the sound event. The player will be able to hear the direction of the sound - # based on what position is sent here. - position: vec3f - # ExtraData is a packed integer that some sound types use to provide extra data. An example of this is - # the note sound, which is composed of a pitch and an instrument type. - extra_data: zigzag32 - # EntityType is the string entity type of the entity that emitted the sound, for example - # 'minecraft:skeleton'. Some sound types use this entity type for additional data. - entity_type: string - # BabyMob specifies if the sound should be that of a baby mob. It is most notably used for parrot - # imitations, which will change based on if this field is set to true or not. - is_baby_mob: bool - # DisableRelativeVolume specifies if the sound should be played relatively or not. If set to true, the - # sound will have full volume, regardless of where the Position is, whereas if set to false, the sound's - # volume will be based on the distance to Position. - is_global: bool - -# LevelEventGeneric is sent by the server to send a 'generic' level event to the client. This packet sends an -# NBT serialised object and may for that reason be used for any event holding additional data. -packet_level_event_generic: - !id: 0x7c - !bound: client - # EventID is a unique identifier that identifies the event called. The data that follows has fields in - # the NBT depending on what event it is. - event_id: varint - # SerialisedEventData is a network little endian serialised object of event data, with fields that vary - # depending on EventID. - # Unlike many other NBT structures, this data is not actually in a compound but just loosely floating - # NBT tags. To decode using the nbt package, you would need to append 0x0a00 at the start (compound id - # and name length) and add 0x00 at the end, to manually wrap it in a compound. Likewise, you would have - # to remove these bytes when encoding. - nbt: nbtLoop - -# LecternUpdate is sent by the client to update the server on which page was opened in a book on a lectern, -# or if the book should be removed from it. -packet_lectern_update: - !id: 0x7d - !bound: client - # Page is the page number in the book that was opened by the player on the lectern. - page: u8 - # PageCount is the number of pages that the book opened in the lectern has. - page_count: u8 - # Position is the position of the lectern that was updated. If no lectern is at the block position, - # the packet should be ignored. - position: vec3i - # DropBook specifies if the book currently set on display in the lectern should be dropped server-side. - drop_book: bool - -# This packet was removed. -packet_video_stream_connect: - !id: 0x7e - !bound: client - server_uri: string - frame_send_frequency: lf32 - action: u8 - resolution_x: li32 - resolution_y: li32 - -# This is NOT a Minecraft entity, but an entity in the Entity Component System (ECS) -# for the game engine Minecrat Bedrock uses. Internally, all 'Minecraft entities' are -# known as Actors including in packet names and fields. However, these are irrelevant -# internal details so we don't do the renames in these protocol definitions, for simplicity we just use Entity. -# -# AddEntity is sent by the server to the client. Its function is not entirely clear: It does not add an -# entity in the sense of an in-game entity, but has to do with the ECS that Minecraft uses. -packet_add_ecs_entity: - !id: 0x7f - !bound: client - # EntityNetworkID is the network ID of the entity that should be added. - network_id: varint64 - -# RemoveEntity is sent by the server to the client. Its function is not entirely clear: It does not remove an -# entity in the sense of an in-game entity, but has to do with the ECS that Minecraft uses -packet_remove_ecs_entity: - !id: 0x80 - !bound: client - # EntityNetworkID is the network ID of the entity that should be removed. - network_id: varint64 - -# ClientCacheStatus is sent by the client to the server at the start of the game. It is sent to let the -# server know if it supports the client-side blob cache. Clients such as Nintendo Switch do not support the -# cache, and attempting to use it anyway will fail. -packet_client_cache_status: - !id: 0x81 - !bound: both - # Enabled specifies if the blob cache is enabled. If false, the server should not attempt to use the - # blob cache. If true, it may do so, but it may also choose not to use it. - enabled: bool - -# OnScreenTextureAnimation is sent by the server to show a certain animation on the screen of the player. -# The packet is used, as an example, for when a raid is triggered and when a raid is defeated. -packet_on_screen_texture_animation: - !id: 0x82 - !bound: client - # AnimationType is the type of the animation to show. The packet provides no further extra data to allow - # modifying the duration or other properties of the animation. - animation_type: lu32 - - -# MapCreateLockedCopy is sent by the server to create a locked copy of one map into another map. In vanilla, -# it is used in the cartography table to create a map that is locked and cannot be modified. -packet_map_create_locked_copy: - !id: 0x83 - !bound: client - # OriginalMapID is the ID of the map that is being copied. The locked copy will obtain all content that - # is visible on this map, except the content will not change. - original_map_id: zigzag64 - # NewMapID is the ID of the map that holds the locked copy of the map that OriginalMapID points to. Its - # contents will be impossible to change. - new_map_id: zigzag64 - - -# StructureTemplateDataRequest is sent by the client to request data of a structure. -packet_structure_template_data_export_request: - !id: 0x84 - !bound: client - # StructureName is the name of the structure that was set in the structure block's UI. This is the name - # used to export the structure to a file. - name: string - # Position is the position of the structure block that has its template data requested. - position: BlockCoordinates - # Settings is a struct of settings that should be used for exporting the structure. These settings are - # identical to the last sent in the StructureBlockUpdate packet by the client. - settings: StructureBlockSettings - # RequestType specifies the type of template data request that the player sent. - request_type: u8 => - 1: export_from_save - 2: export_from_load - 3: query_saved_structure - -# StructureTemplateDataResponse is sent by the server to send data of a structure to the client in response -# to a StructureTemplateDataRequest packet. -packet_structure_template_data_export_response: - !id: 0x85 - !bound: client - name: string - success: bool - nbt: success ? - if true: nbt - # ResponseType specifies the response type of the packet. This depends on the RequestType field sent in - # the StructureTemplateDataRequest packet and is one of the constants above. - response_type: u8 => - 1: export - 2: query - -# No longer used. -packet_update_block_properties: - !id: 0x86 - !bound: client - nbt: nbt - -# ClientCacheBlobStatus is part of the blob cache protocol. It is sent by the client to let the server know -# what blobs it needs and which blobs it already has, in an ACK type system. -packet_client_cache_blob_status: - !id: 0x87 - !bound: client - # The number of MISSes in this packet - misses: varint - # The number of HITs in this packet - haves: varint - # A list of blob hashes that the client does not have a blob available for. The server - # should send the blobs matching these hashes as soon as possible. - missing: lu64[]$misses - # A list of hashes that the client does have a cached blob for. Server doesn't need to send. - have: lu64[]$haves - -# ClientCacheMissResponse is part of the blob cache protocol. It is sent by the server in response to a -# ClientCacheBlobStatus packet and contains the blob data of all blobs that the client acknowledged not to -# have yet. -packet_client_cache_miss_response: - !id: 0x88 - !bound: client - blobs: Blob[]varint - -# EducationSettings is a packet sent by the server to update Minecraft: Education Edition related settings. -# It is unused by the normal base game. -packet_education_settings: - !id: 0x89 - !bound: client - # CodeBuilderDefaultURI is the default URI that the code builder is ran on. Using this, a Code Builder - # program can make code directly affect the server. - CodeBuilderDefaultURI: string - # CodeBuilderTitle is the title of the code builder shown when connected to the CodeBuilderDefaultURI. - CodeBuilderTitle: string - # CanResizeCodeBuilder specifies if clients connected to the world should be able to resize the code - # builder when it is opened. - CanResizeCodeBuilder: bool - HasOverrideURI: bool - OverrideURI: HasOverrideURI? - if true: string - # HasQuiz specifies if the world has a quiz connected to it. - HasQuiz: bool - -# MultiPlayerSettings is sent by the client to update multi-player related settings server-side and sent back -# to online players by the server. -# The MultiPlayerSettings packet is a Minecraft: Education Edition packet. It has no functionality for the -# base game. -packet_multiplayer_settings: - !id: 0x8b - !bound: server - # ActionType is the action that should be done when this packet is sent. It is one of the constants that - # may be found above. - action_type: zigzag32 => - 0: enable_multiplayer - 1: disable_multiplayer - 2: refresh_join_code - -# SettingsCommand is sent by the client when it changes a setting in the settings that results in the issuing -# of a command to the server, such as when Show Coordinates is enabled. -packet_settings_command: - !id: 0x8c - !bound: server - # CommandLine is the full command line that was sent to the server as a result of the setting that the - # client changed. - command_line: string - # SuppressOutput specifies if the client requests the suppressing of the output of the command that was - # executed. Generally this is set to true, as the client won't need a message to confirm the output of - # the change. - suppress_output: bool - -# AnvilDamage is sent by the client to request the dealing damage to an anvil. This packet is completely -# pointless and the server should never listen to it. -packet_anvil_damage: - !id: 0x8d - !bound: server - # Damage is the damage that the client requests to be dealt to the anvil. - damage: u8 - # AnvilPosition is the position in the world that the anvil can be found at. - position: BlockCoordinates - -# CompletedUsingItem is sent by the server to tell the client that it should be done using the item it is -# currently using. -packet_completed_using_item: - !id: 0x8e - !bound: client - # UsedItemID is the item ID of the item that the client completed using. This should typically be the - # ID of the item held in the hand. - used_item_id: li16 - # UseMethod is the method of the using of the item that was completed. It is one of the constants that - # may be found above. - use_method: li32 => - 0: equip_armor - 1: eat - 2: attack - 3: consume - 4: throw - 5: shoot - 6: place - 7: fill_bottle - 8: fill_bucket - 9: pour_bucket - 10: use_tool - 11: interact - 12: retrieved - 13: dyed - 14: traded - -# NetworkSettings is sent by the server to update a variety of network settings. These settings modify the -# way packets are sent over the network stack. -packet_network_settings: - !id: 0x8f - !bound: both - # CompressionThreshold is the minimum size of a packet that is compressed when sent. If the size of a - # packet is under this value, it is not compressed. - # When set to 0, all packets will be left uncompressed. - compression_threshold: u16 - - -# PlayerAuthInput is sent by the client to allow for server authoritative movement. It is used to synchronise -# the player input with the position server-side. -# The client sends this packet when the ServerAuthoritativeMovementMode field in the StartGame packet is set -# to true, instead of the MovePlayer packet. The client will send this packet once every tick. -packet_player_auth_input: - !id: 0x90 - !bound: server - # Pitch that the player reports it has. - pitch: lf32 - # Yaw that player reports it has. - yaw: lf32 - # Position holds the position that the player reports it has. - position: vec3f - # MoveVector is a Vec2 that specifies the direction in which the player moved, as a combination of X/Z - # values which are created using the WASD/controller stick state. - move_vector: vec2f - # HeadYaw is the horizontal rotation of the head that the player reports it has. - head_yaw: lf32 - # InputData is a combination of bit flags that together specify the way the player moved last tick. It - # is a combination of the flags above. - input_data: InputFlag - # InputMode specifies the way that the client inputs data to the screen. It is one of the constants that - # may be found above. - input_mode: varint => - 0: unknown - 1: mouse - 2: touch - 3: game_pad - 4: motion_controller - # PlayMode specifies the way that the player is playing. The values it holds, which are rather random, - # may be found above. - play_mode: varint => - 0: normal - 1: teaser - 2: screen - 3: viewer - 4: reality - 5: placement - 6: living_room - 7: exit_level - 8: exit_level_living_room - 9: num_modes - # GazeDirection is the direction in which the player is gazing, when the PlayMode is PlayModeReality: In - # other words, when the player is playing in virtual reality. - gaze_direction: play_mode ? - if reality: vec3f - # Tick is the server tick at which the packet was sent. It is used in relation to - # CorrectPlayerMovePrediction. - tick: varint64 - # Delta was the delta between the old and the new position. There isn't any practical use for this field - # as it can be calculated by the server itself. - delta: vec3f - transaction: input_data.item_interact ? - if true: - legacy: TransactionLegacy - actions: TransactionActions - data: TransactionUseItem - item_stack_request: input_data.item_stack_request ? - if true: ItemStackRequest - block_action: input_data.block_action ? - if true: []zigzag32 - action: Action - _: action? - if start_break or abort_break or crack_break or predict_break or continue_break: - # BlockPosition is the position of the target block, if the action with the ActionType set concerned a - # block. If that is not the case, the block position will be zero. - position: BlockCoordinates - # BlockFace is the face of the target block that was touched. If the action with the ActionType set - # concerned a block. If not, the face is always 0. - face: zigzag32 - -#TODO: update to use the new `shift` option in bitflags -InputFlag: [ "bitflags", { - "type": "varint64", "big": true, - "flags": [ - "ascend", - "descend", - "north_jump", - "jump_down", - "sprint_down", - "change_height", - "jumping", - "auto_jumping_in_water", - "sneaking", - "sneak_down", - "up", - "down", - "left", - "right", - "up_left", - "up_right", - "want_up", - "want_down", - "want_down_slow", - "want_up_slow", - "sprinting", - "ascend_block", - "descend_block", - "sneak_toggle_down", - "persist_sneak", - "start_sprinting", - "stop_sprinting", - "start_sneaking", - "stop_sneaking", - "start_swimming", - "stop_swimming", - "start_jumping", - "start_gliding", - "stop_gliding", - "item_interact", - "block_action", - "item_stack_request" - ] -}] - -# CreativeContent is a packet sent by the server to set the creative inventory's content for a player. -# Introduced in 1.16, this packet replaces the previous method - sending an InventoryContent packet with -# creative inventory window ID. -# As of v1.16.100, this packet must be sent during the login sequence. Not sending it will stop the client -# from joining the server. -packet_creative_content: - !id: 0x91 - !bound: client - # Items is a list of the items that should be added to the creative inventory. - items: []varint - entry_id: varint - item: ItemLegacy - -# PlayerEnchantOptions is sent by the server to update the enchantment options displayed when the user opens -# the enchantment table and puts an item in. This packet was added in 1.16 and allows the server to decide on -# the enchantments that can be selected by the player. -# The PlayerEnchantOptions packet should be sent once for every slot update of the enchantment table. The -# vanilla server sends an empty PlayerEnchantOptions packet when the player opens the enchantment table -# (air is present in the enchantment table slot) and sends the packet with actual enchantments in it when -# items are put in that can have enchantments. -packet_player_enchant_options: - !id: 0x92 - !bound: client - # Options is a list of possible enchantment options for the item that was put into the enchantment table. - options: EnchantOption[]varint - -# ItemStackRequest is sent by the client to change item stacks in an inventory. It is essentially a -# replacement of the InventoryTransaction packet added in 1.16 for inventory specific actions, such as moving -# items around or crafting. The InventoryTransaction packet is still used for actions such as placing blocks -# and interacting with entities. -packet_item_stack_request: - !id: 0x93 - !bound: server - requests: ItemStackRequest[]varint - -# ItemStackResponse is sent by the server in response to an ItemStackRequest packet from the client. This -# packet is used to either approve or reject ItemStackRequests from the client. If a request is approved, the -# client will simply continue as normal. If rejected, the client will undo the actions so that the inventory -# should be in sync with the server again. -packet_item_stack_response: - !id: 0x94 - !bound: client - # Responses is a list of responses to ItemStackRequests sent by the client before. Responses either - # approve or reject a request from the client. - # Vanilla limits the size of this slice to 4096. - responses: ItemStackResponses - -# PlayerArmourDamage is sent by the server to damage the armour of a player. It is a very efficient packet, -# but generally it's much easier to just send a slot update for the damaged armour. -packet_player_armor_damage: - !id: 0x95 - !bound: client - # Bitset holds a bitset of 4 bits that indicate which pieces of armour need to have damage dealt to them. - # The first bit, when toggled, is for a helmet, the second for the chestplate, the third for the leggings - # and the fourth for boots. - type: ArmorDamageType - helmet_damage: type.head ? - if true: zigzag32 - chestplate_damage: type.chest ? - if true: zigzag32 - leggings_damage: type.legs ? - if true: zigzag32 - boots_damage: type.feet ? - if true: zigzag32 - -ArmorDamageType: [ "bitflags", - { - "type": "u8", - "flags": { - "head": 0b1, - "chest": 0b10, - "legs": 0b100, - "feet": 0b1000 - } - } -] - -# UpdatePlayerGameType is sent by the server to change the game mode of a player. It is functionally -# identical to the SetPlayerGameType packet. -packet_update_player_game_type: - !id: 0x97 - !bound: server - # GameType is the new game type of the player. It is one of the constants that can be found in - # set_player_game_type.go. Some of these game types require additional flags to be set in an - # AdventureSettings packet for the game mode to obtain its full functionality. - gamemode: GameMode - # PlayerUniqueID is the entity unique ID of the player that should have its game mode updated. If this - # packet is sent to other clients with the player unique ID of another player, nothing happens. - player_unique_id: zigzag64 - - -# PositionTrackingDBClientRequest is a packet sent by the client to request the position and dimension of a -# 'tracking ID'. These IDs are tracked in a database by the server. In 1.16, this is used for lodestones. -# The client will send this request to find the position a lodestone compass needs to point to. If found, it -# will point to the lodestone. If not, it will start spinning around. -# A PositionTrackingDBServerBroadcast packet should be sent in response to this packet. -packet_position_tracking_db_request: - !id: 0x9a - !bound: server - # RequestAction is the action that should be performed upon the receiving of the packet. It is one of the - # constants found above. - action: u8 => - 0: query - # TrackingID is a unique ID used to identify the request. The server responds with a - # PositionTrackingDBServerBroadcast packet holding the same ID, so that the client can find out what that - # packet was in response to. - tracking_id: zigzag32 - -# PositionTrackingDBServerBroadcast is sent by the server in response to the -# PositionTrackingDBClientRequest packet. This packet is, as of 1.16, currently only used for lodestones. The -# server maintains a database with tracking IDs and their position and dimension. The client will request -# these tracking IDs, (NBT tag set on the lodestone compass with the tracking ID?) and the server will -# respond with the status of those tracking IDs. -# What is actually done with the data sent depends on what the client chooses to do with it. For the -# lodestone compass, it is used to make the compass point towards lodestones and to make it spin if the -# lodestone at a position is no longer there. -packet_position_tracking_db_broadcast: - !id: 0x99 - !bound: client - # BroadcastAction specifies the status of the position tracking DB response. It is one of the constants - # above, specifying the result of the request with the ID below. - # The Update action is sent for setting the position of a lodestone compass, the Destroy and NotFound to - # indicate that there is not (no longer) a lodestone at that position. - broadcast_action: u8 => - 0: update - 1: destory - 2: not_found - # TrackingID is the ID of the PositionTrackingDBClientRequest packet that this packet was in response to. - # The tracking ID is also present as the 'id' field in the SerialisedData field. - tracking_id: zigzag32 - nbt: nbt - -# PacketViolationWarning is sent by the client when it receives an invalid packet from the server. It holds -# some information on the error that occurred. -packet_packet_violation_warning: - !id: 0x9c - !bound: server - violation_type: zigzag32 => - 0: malformed - # Severity specifies the severity of the packet violation. The action the client takes after this - # violation depends on the severity sent. - severity: zigzag32 => - 0: warning - 1: final_warning - 2: terminating - # PacketID is the ID of the invalid packet that was received. - packet_id: zigzag32 - # ViolationContext holds a description on the violation of the packet. - reason: string - - -# MotionPredictionHints is sent by the server to the client. There is a predictive movement component for -# entities. This packet fills the "history" of that component and entity movement is computed based on the -# points. Vanilla sends this packet instead of the SetActorMotion packet when 'spatial optimisations' are -# enabled. -packet_motion_prediction_hints: - !id: 0x9d - !bound: client - # EntityRuntimeID is the runtime ID of the entity whose velocity is sent to the client. - entity_runtime_id: varint64 - # Velocity is the server-calculated velocity of the entity at the point of sending the packet. - velocity: vec3f - # OnGround specifies if the server currently thinks the entity is on the ground. - on_ground: bool - - -# AnimateEntity is sent by the server to animate an entity client-side. It may be used to play a single -# animation, or to activate a controller which can start a sequence of animations based on different -# conditions specified in an animation controller. -# Much of the documentation of this packet can be found at -# https://minecraft.gamepedia.com/Bedrock_Edition_beta_animation_documentation. -packet_animate_entity: - !id: 0x9e - !bound: client - # Animation is the name of a single animation to start playing. - animation: string - # NextState is the first state to start with. These states are declared in animation controllers (which, - # in themselves, are animations too). These states in turn may have animations and transitions to move to - # a next state. - next_state: string - # StopCondition is a MoLang expression that specifies when the animation should be stopped. - stop_condition: string - # Controller is the animation controller that is used to manage animations. These controllers decide when - # to play which animation. - controller: string - # How long to move from the previous animation to the next. - blend_out_time: lf32 - # EntityRuntimeIDs is list of runtime IDs of entities that the animation should be applied to. - runtime_entity_ids: varint64[]varint - -# CameraShake is sent by the server to make the camera shake client-side. This feature was added for map- -# making partners. -packet_camera_shake: - !id: 0x9f - !bound: client - # Intensity is the intensity of the shaking. The client limits this value to 4, so anything higher may - # not work. - intensity: lf32 - # Duration is the number of seconds the camera will shake for. - duration: lf32 - # Type is the type of shake, and is one of the constants listed above. The different type affects how - # the shake looks in game. - type: u8 - # Action is the action to be performed, and is one of the constants listed above. Currently the - # different actions will either add or stop shaking the client. - action: u8 => - 0: add - 1: stop - -# PlayerFog is sent by the server to render the different fogs in the Stack. The types of fog are controlled -# by resource packs to change how they are rendered, and the ability to create custom fog. -packet_player_fog: - !id: 0xa0 - !bound: client - # Stack is a list of fog identifiers to be sent to the client. Examples of fog identifiers are - # "minecraft:fog_ocean" and "minecraft:fog_hell". - stack: string[]varint - - -# CorrectPlayerMovePrediction is sent by the server if and only if StartGame.ServerAuthoritativeMovementMode -# is set to AuthoritativeMovementModeServerWithRewind. The packet is used to correct movement at a specific -# point in time. -packet_correct_player_move_prediction: - !id: 0xa1 - !bound: client - # Position is the position that the player is supposed to be at at the tick written in the field below. - # The client will change its current position based on movement after that tick starting from the - # Position. - position: vec3f - # Delta is the change in position compared to what the client sent as its position at that specific tick. - delta: vec3f - # OnGround specifies if the player was on the ground at the time of the tick below. - on_ground: bool - # Tick is the tick of the movement which was corrected by this packet. - tick: varint64 - -# ItemComponent is sent by the server to attach client-side components to a custom item. -packet_item_component: - !id: 0xa2 - !bound: client - # `entries` holds a list of all custom items with their respective components set. - entries: ItemComponentList - -# FilterText is sent by the both the client and the server. The client sends the packet to the server to -# allow the server to filter the text server-side. The server then responds with the same packet and the -# safer version of the text. -packet_filter_text_packet: - !id: 0xa3 - !bound: client - # Text is either the text from the client or the safer version of the text sent by the server. - text: string - # FromServer indicates if the packet was sent by the server or not. - from_server: bool - -# ClientBoundDebugRenderer is sent by the server to spawn an outlined cube on client-side. -packet_debug_renderer: - !id: 0xa4 - !bound: client - # Type is the type of action. It is one of the constants above. - type: li32 => - 1: clear - 2: add_cube - _: type ? - if clear: void - if add_cube: - # Text is the text that is displayed above the debug. - text: string - # Position is the position to spawn the debug on. - position: vec3f - # Red is the red value from the RGBA colour rendered on the debug. - red: lf32 - # Green is the green value from the RGBA colour rendered on the debug. - green: lf32 - # Blue is the blue value from the RGBA colour rendered on the debug. - blue: lf32 - # Alpha is the alpha value from the RGBA colour rendered on the debug. - alpha: lf32 - # Duration is how long the debug will last in the world for. It is measured in milliseconds. - duration: li64 - -# Sent by the server to synchronize/update entity properties as NBT, an alternative to Set Entity Data. -packet_sync_entity_property: - !id: 0xa5 - !bound: client - nbt: nbt - -# AddVolumeEntity sends a volume entity's definition and components from server to client. -packet_add_volume_entity: - !id: 0xa6 - !bound: client - # The Runtime Entity ID - entity_id: varint64 - nbt: nbt - -# RemoveVolumeEntity indicates a volume entity to be removed from server to client. -packet_remove_volume_entity: - !id: 0xa7 - !bound: client - # The Runtime Entity ID - entity_id: varint64 - -# SimulationType is an in-progress packet. We currently do not know the use case. -packet_simulation_type: - !id: 0xa8 - # SimulationType is the simulation type selected - type: u8 => - 0: game - 1: editor - 2: test - 3: invalid - -# NPCDialogue is a packet that allows the client to display dialog boxes for interacting with NPCs. -packet_npc_dialogue: - !id: 0xa9 - # ActorUniqueID is the ID of the NPC being requested. - entity_id: lu64 - # ActionType is the type of action for the packet. - action_type: varint => - 0: open - 1: close - # Dialogue is the text that the client should see. - dialogue: string - # SceneName is the scene the data was pulled from for the client. - screen_name: string - # NPCName is the name of the NPC to be displayed to the client. - npc_name: string - # ActionJSON is the JSON string of the buttons/actions the server can perform. - action_json: string \ No newline at end of file diff --git a/data/latest/types.yaml b/data/latest/types.yaml deleted file mode 100644 index f88fba0..0000000 --- a/data/latest/types.yaml +++ /dev/null @@ -1,1703 +0,0 @@ -!StartDocs: Types - -BehaviourPackInfos: []li16 - uuid: string - version: string - size: lu64 - content_key: string - sub_pack_name: string - content_identity: string - has_scripts: bool - -TexturePackInfos: []li16 - uuid: string - version: string - size: lu64 - content_key: string - sub_pack_name: string - content_identity: string - has_scripts: bool - rtx_enabled: bool - -ResourcePackIdVersions: []varint - # The ID of the resource pack. - uuid: string - # The version of the resource pack. - version: string - # The subpack name of the resource pack. - name: string - -ResourcePackIds: string[]li16 - -Experiment: - name: string - enabled: bool - -Experiments: Experiment[]li32 - -GameMode: zigzag32 => - 0: survival - 1: creative - 2: adventure - 3: survival_spectator - 4: creative_spectator - 5: fallback - -GameRule: - name: string - editable: bool - type: varint => - 1: bool - 2: int - 3: float - value: type? - if bool: bool - if int: zigzag32 - if float: lf32 - -GameRules: GameRule[]varint - -# CacheBlob represents a blob as used in the client side blob cache protocol. It holds a hash of its data and -# the full data of it. -Blob: - # Hash is the hash of the blob. The hash is computed using xxHash, and must be deterministic for the same - # chunk data. - hash: lu64 - # Payload is the data of the blob. When sent, the client will associate the Hash of the blob with the - # Payload in it. - payload: ByteArray - -BlockProperties: []varint - name: string - state: nbt - -Itemstates: []varint - name: string - runtime_id: li16 - component_based: bool - - - -ItemExtraDataWithBlockingTick: - has_nbt: lu16 => - 0xffff: 'true' - 0x0000: 'false' - nbt: has_nbt ? - if true: - version: u8 - nbt: lnbt - default: void - can_place_on: ShortArray[]li32 - can_destroy: ShortArray[]li32 - blocking_tick: li64 - -ItemExtraDataWithoutBlockingTick: - has_nbt: lu16 => - 0xffff: 'true' - 0x0000: 'false' - nbt: has_nbt ? - if true: - version: u8 - nbt: lnbt - default: void - can_place_on: ShortArray[]li32 - can_destroy: ShortArray[]li32 - -# Same as below but without a "networkStackID" boolean -ItemLegacy: - network_id: zigzag32 - _: network_id? - if 0: void - default: - count: lu16 - metadata: varint - block_runtime_id: zigzag32 - extra: network_id ? - # The Shield Item ID is sent in the StartGame packet. It is usually 355 in vanilla. - if /ShieldItemID: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' - default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]' - -# An "ItemStack" here represents an Item instance. You can think about it like a pointer -# to an item class. The data for the class gets updated with the data in the `item` field -# As of 1.16.220, now functionally the same as `Item` just without an extra boolean when -# server auth inventories is disabled. -Item: - network_id: zigzag32 - _: network_id? - if 0: void - default: - count: lu16 - metadata: varint - # When server authoritative inventory is enabled, all allocated items have a unique ID used to identify - # a specifc item instance. - has_stack_id: u8 - # StackNetworkID is the network ID of this item *instance*. If the stack is empty, 0 is always written for this - # field. If not, the field should be set to 1 if the server authoritative inventories are disabled in the - # StartGame packet, or to a unique stack ID if it is enabled. - stack_id: has_stack_id ? - if 0: void - default: zigzag32 - block_runtime_id: zigzag32 - extra: network_id ? - # The Shield Item ID is sent in the StartGame packet. It is usually 355 in vanilla. - ## Really bad compiler hack to allow us to use a global variable - if /ShieldItemID: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithBlockingTick" }]' - default: '["encapsulated", { "lengthType": "varint", "type": "ItemExtraDataWithoutBlockingTick" }]' - -vec3i: - x: zigzag32 - y: zigzag32 - z: zigzag32 - -vec3u: - x: varint - y: varint - z: varint - -vec3f: - x: lf32 - y: lf32 - z: lf32 - -vec2f: - x: lf32 - z: lf32 - -MetadataDictionary: []varint - # https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/entity/Entity.php#L101 - key: varint => - 0: flags - 1: health #int (minecart/boat) - 2: variant #int - 3: color #byte - 4: nametag #string - 5: owner_eid #long - 6: target_eid #long - 7: air #short - 8: potion_color #int (ARGB!) - 9: potion_ambient #byte - 10: jump_duration #long - 11: hurt_time #int (minecart/boat) - 12: hurt_direction #int (minecart/boat) - 13: paddle_time_left #float - 14: paddle_time_right #float - 15: experience_value #int (xp orb) - 16: minecart_display_block #int (id | (data << 16)) - 17: minecart_display_offset #int - 18: minecart_has_display #byte (must be 1 for minecart to show block inside) - 20: old_swell - 21: swell_dir - 22: charge_amount - 23: enderman_held_runtime_id #short - 24: entity_age #short - 26: player_flags - 27: player_index - 28: player_bed_position #block coords - 29: fireball_power_x #float - 30: fireball_power_y - 31: fireball_power_z - 32: aux_power - 33: fish_x - 34: fish_z - 35: fish_angle - 36: potion_aux_value #short - 37: lead_holder_eid #long - 38: scale - 39: interactive_tag #string - 40: npc_skin_id #string - 41: url_tag #string - 42: max_airdata_max_air - 43: mark_variant #int - 44: container_type #byte - 45: container_base_size #int - 46: container_extra_slots_per_strength #int - 47: block_target - 48: wither_invulnerable_ticks #int - 49: wither_target_1 #long - 50: wither_target_2 #long - 51: wither_target_3 #long - 52: aerial_attack - 53: boundingbox_width - 54: boundingbox_height - 55: fuse_length - 56: rider_seat_position #vector3f - 57: rider_rotation_locked #byte - 58: rider_max_rotation #float - 59: rider_min_rotation #float - 60: rider_rotation_offset - 61: area_effect_cloud_radius #float - 62: area_effect_cloud_waiting #int - 63: area_effect_cloud_particle_id #int - 64: shulker_peek_id #int - 65: shulker_attach_face #byte - 66: shulker_attached #short - 67: shulker_attach_pos - 68: trading_player_eid #long - 69: trading_career - 70: has_command_block - 71: command_block_command #string - 72: command_block_last_output #string - 73: command_block_track_output #byte - 74: controlling_rider_seat_number #byte - 75: strength #int - 76: max_strength #int - 77: spell_casting_color #int - 78: limited_life - 79: armor_stand_pose_index # int - 80: ender_crystal_time_offset # int - 81: always_show_nametag # byte - 82: color_2 # byte - 83: name_author - 84: score_tag #String - 85: balloon_attached_entity # long - 86: pufferfish_size - 87: bubble_time - 88: agent - 89: sitting_amount - 90: sitting_amount_previous - 91: eating_counter - 92: flags_extended - 93: laying_amount - 94: laying_amount_previous - 95: duration - 96: spawn_time - 97: change_rate - 98: change_on_pickup - 99: pickup_count - 100: interact_text - 101: trade_tier - 102: max_trade_tier - 103: trade_experience - 104: skin_id - 105: spawning_frames - 106: command_block_tick_delay - 107: command_block_execute_on_first_tick - 108: ambient_sound_interval - 109: ambient_sound_interval_range - 110: ambient_sound_event_name - 111: fall_damage_multiplier - 112: name_raw_text - 113: can_ride_target - 114: low_tier_cured_discount - 115: high_tier_cured_discount - 116: nearby_cured_discount - 117: nearby_cured_discount_timestamp - 118: hitbox - 119: is_buoyant - 120: base_runtime_id - 121: freezing_effect_strength - 122: buoyancy_data - 123: goat_horn_count - 124: update_properties - type: varint => - 0: byte - 1: short - 2: int - 3: float - 4: string - 5: compound - 6: vec3i - 7: long - 8: vec3f - value: key ? - if flags: MetadataFlags1 - if flags_extended: MetadataFlags2 - default: type ? - if byte: i8 - if short: li16 - if int: zigzag32 - if float: lf32 - if string: string - if compound: nbt - if vec3i: vec3i - if long: zigzag64 - if vec3f: vec3f - -MetadataFlags1: [ "bitflags", { - "type": "zigzag64", - "big": true, - "flags": [ - "onfire", - "sneaking", - "riding", - "sprinting", - "action", - "invisible", - "tempted", - "inlove", - "saddled", - "powered", - "ignited", - "baby", - "converting", - "critical", - "can_show_nametag", - "always_show_nametag", - "no_ai", - "silent", - "wallclimbing", - "can_climb", - "swimmer", - "can_fly", - "walker", - "resting", - "sitting", - "angry", - "interested", - "charged", - "tamed", - "orphaned", - "leashed", - "sheared", - "gliding", - "elder", - "moving", - "breathing", - "chested", - "stackable", - "showbase", - "rearing", - "vibrating", - "idling", - "evoker_spell", - "charge_attack", - "wasd_controlled", - "can_power_jump", - "linger", - "has_collision", - "affected_by_gravity", - "fire_immune", - "dancing", - "enchanted", - "show_trident_rope", # tridents show an animated rope when enchanted with loyalty after they are thrown and return to their owner. to be combined with data_owner_eid - "container_private", #inventory is private, doesn't drop contents when killed if true - "transforming", - "spin_attack", - "swimming", - "bribed", #dolphins have this set when they go to find treasure for the player - "pregnant", - "laying_egg", - "rider_can_pick", #??? - "transition_sitting", - "eating", - "laying_down" - ] -}] - -MetadataFlags2: [ "bitflags", { - "type": "zigzag64", - "big": true, - "flags": [ - "sneezing", - "trusting", - "rolling", - "scared", - "in_scaffolding", - "over_scaffolding", - "fall_through_scaffolding", - "blocking", #shield - "transition_blocking", - "blocked_using_shield", - "blocked_using_damaged_shield", - "sleeping", - "wants_to_wake", - "trade_interest", - "door_breaker", #... - "breaking_obstruction", - "door_opener", #... - "illager_captain", - "stunned", - "roaring", - "delayed_attacking", - "avoiding_mobs", - "avoiding_block", - "facing_target_to_range_attack", - "hidden_when_invisible", #?????????????????? - "is_in_ui", - "stalking", - "emoting", - "celebrating", - "admiring", - "celebrating_special", - "unknown95", # 95 - "ram_attack", - "playing_dead" - ] -}] - -Link: - ridden_entity_id: zigzag64 - rider_entity_id: zigzag64 - type: u8 - immediate: bool - rider_initiated: bool - -Links: Link[]varint - -EntityAttributes: []varint - name: string - min: lf32 - value: lf32 - max: lf32 - -Rotation: - yaw: byterot - pitch: byterot - head_yaw: byterot - -BlockCoordinates: # mojang... - x: zigzag32 - y: varint - z: zigzag32 - -PlayerAttributes: []varint - min: lf32 - max: lf32 - current: lf32 - default: lf32 - name: string - -# UseItemTransactionData represents an inventory transaction data object sent when the client uses an item on -# a block. Also used in PlayerAuthoritativeInput packet -TransactionUseItem: - # ActionType is the type of the UseItem inventory transaction. It is one of the action types found above, - # and specifies the way the player interacted with the block. - action_type: varint => - 0: click_block - 1: click_air - 2: break_block - # BlockPosition is the position of the block that was interacted with. This is only really a correct - # block position if ActionType is not UseItemActionClickAir. - block_position: vec3i - # BlockFace is the face of the block that was interacted with. When clicking the block, it is the face - # clicked. When breaking the block, it is the face that was last being hit until the block broke. - face: varint - # HotBarSlot is the hot bar slot that the player was holding while clicking the block. It should be used - # to ensure that the hot bar slot and held item are correctly synchronised with the server. - hotbar_slot: varint - # HeldItem is the item that was held to interact with the block. The server should check if this item - # is actually present in the HotBarSlot. - held_item: Item - # Position is the position of the player at the time of interaction. For clicking a block, this is the - # position at that time, whereas for breaking the block it is the position at the time of breaking. - player_pos: vec3f - # ClickedPosition is the position that was clicked relative to the block's base coordinate. It can be - # used to find out exactly where a player clicked the block. - click_pos: vec3f - # BlockRuntimeID is the runtime ID of the block that was clicked. It may be used by the server to verify - # that the player's world client-side is synchronised with the server's. - block_runtime_id: varint - -# Actions is a list of actions that took place, that form the inventory transaction together. Each of -# these actions hold one slot in which one item was changed to another. In general, the combination of -# all of these actions results in a balanced inventory transaction. This should be checked to ensure that -# no items are cheated into the inventory. -TransactionActions: []varint - source_type: varint => - 0: container - 1: global - 2: world_interaction - 3: creative - 100: craft_slot - 99999: craft - _: source_type? - if container or craft: - inventory_id: WindowIDVarint - if world_interaction: - flags: varint - if craft or craft_slot: - action: varint - default: void - slot: varint - old_item: Item - new_item: Item - -# The Minecraft bedrock inventory system was refactored, but not all inventory actions use the new packet. -# This data structure holds actions that have not been updated to the new system. -TransactionLegacy: - # LegacyRequestID is an ID that is only non-zero at times when sent by the client. The server should - # always send 0 for this. When this field is not 0, the LegacySetItemSlots slice below will have values - # in it. - # LegacyRequestID ties in with the ItemStackResponse packet. If this field is non-0, the server should - # respond with an ItemStackResponse packet. Some inventory actions such as dropping an item out of the - # hotbar are still one using this packet, and the ItemStackResponse packet needs to tie in with it. - legacy_request_id: zigzag32 - # `legacy_transactions` are only present if the LegacyRequestID is non-zero. These item slots inform the - # server of the slots that were changed during the inventory transaction, and the server should send - # back an ItemStackResponse packet with these slots present in it. (Or false with no slots, if rejected.) - legacy_transactions: legacy_request_id? - if 0: void - default: []varint - container_id: u8 - changed_slots: []varint - slot_id: u8 - -Transaction: - # Old transaction system data - legacy: TransactionLegacy - # What type of transaction took place - transaction_type: varint => - 0: normal - 1: inventory_mismatch - 2: item_use - 3: item_use_on_entity - 4: item_release - # The list of inventory internal actions in this packet, e.g. inventory GUI actions - actions: TransactionActions - # Extra data if an intenal inventory transaction did not take place, e.g. use of an item - transaction_data: transaction_type? - if normal or inventory_mismatch: void - # UseItemTransactionData represents an inventory transaction data object sent when the client uses an item on - # a block. - if item_use: TransactionUseItem - # UseItemOnEntityTransactionData represents an inventory transaction data object sent when the client uses - # an item on an entity. - if item_use_on_entity: - # TargetEntityRuntimeID is the entity runtime ID of the target that was clicked. It is the runtime ID - # that was assigned to it in the AddEntity packet. - entity_runtime_id: varint64 - # ActionType is the type of the UseItemOnEntity inventory transaction. It is one of the action types - # found in the constants above, and specifies the way the player interacted with the entity. - action_type: varint => - 0: interact - 1: attack - # HotBarSlot is the hot bar slot that the player was holding while clicking the entity. It should be used - # to ensure that the hot bar slot and held item are correctly synchronised with the server. - hotbar_slot: zigzag32 - # HeldItem is the item that was held to interact with the entity. The server should check if this item - # is actually present in the HotBarSlot. - held_item: Item - # Position is the position of the player at the time of clicking the entity. - player_pos: vec3f - # ClickedPosition is the position that was clicked relative to the entity's base coordinate. It can be - # used to find out exactly where a player clicked the entity. - click_pos: vec3f - # ReleaseItemTransactionData represents an inventory transaction data object sent when the client releases - # the item it was using, for example when stopping while eating or stopping the charging of a bow. - if item_release: - # ActionType is the type of the ReleaseItem inventory transaction. It is one of the action types found - # in the constants above, and specifies the way the item was released. - # As of 1.13, the ActionType is always 0. This field can be ignored, because releasing food (by consuming - # it) or releasing a bow (to shoot an arrow) is essentially the same. - action_type: varint => - 0: release - 1: consume - # HotBarSlot is the hot bar slot that the player was holding while releasing the item. It should be used - # to ensure that the hot bar slot and held item are correctly synchronised with the server. - hotbar_slot: zigzag32 - # HeldItem is the item that was released. The server should check if this item is actually present in the - # HotBarSlot. - held_item: Item - # HeadPosition is the position of the player's head at the time of releasing the item. This is used - # mainly for purposes such as spawning eating particles at that position. - head_pos: vec3f - -ItemStacks: Item[]varint - -RecipeIngredient: - network_id: zigzag32 - _: network_id? - if 0: void - default: - network_data: zigzag32 - count: zigzag32 - -PotionTypeRecipes: []varint - input_item_id: zigzag32 - input_item_meta: zigzag32 - ingredient_id: zigzag32 - ingredient_meta: zigzag32 - output_item_id: zigzag32 - output_item_meta: zigzag32 - -PotionContainerChangeRecipes: []varint - input_item_id: zigzag32 - ingredient_id: zigzag32 - output_item_id: zigzag32 - -Recipes: []varint - type: zigzag32 => - 0: shapeless #'ENTRY_SHAPELESS', - 1: shaped #'ENTRY_SHAPED', - 2: furnace # 'ENTRY_FURNACE', - # `furnace_with_metadata` is a recipe specifically used for furnace-type crafting stations. It is equal to - # `furnace`, except it has an input item with a specific metadata value, instead of any metadata value. - 3: furnace_with_metadata # 'ENTRY_FURNACE_DATA', // has metadata - 4: multi #'ENTRY_MULTI', //TODO - 5: shulker_box #'ENTRY_SHULKER_BOX', //TODO - 6: shapeless_chemistry #'ENTRY_SHAPELESS_CHEMISTRY', //TODO - 7: shaped_chemistry #'ENTRY_SHAPED_CHEMISTRY', //TODO - recipe: type? - if shapeless or shulker_box or shapeless_chemistry: - recipe_id: string - input: RecipeIngredient[]varint - output: ItemLegacy[]varint - uuid: uuid - block: string - priority: zigzag32 - network_id: varint - if shaped or shaped_chemistry: - recipe_id: string - width: zigzag32 - height: zigzag32 - # 2D input array, size of width*height - input: []$width - _: RecipeIngredient[]$height - output: ItemLegacy[]varint - uuid: uuid - block: string - priority: zigzag32 - network_id: varint - if furnace: - input_id: zigzag32 - output: ItemLegacy - block: string - if furnace_with_metadata: - input_id: zigzag32 - input_meta: zigzag32 - output: ItemLegacy - block: string - if multi: - uuid: uuid - network_id: varint - -SkinImage: - width: li32 - height: li32 - data: ByteArray - -Skin: - skin_id: string - play_fab_id: string - skin_resource_pack: string - skin_data: SkinImage - animations: []li32 - skin_image: SkinImage - animation_type: li32 - animation_frames: lf32 - expression_type: lf32 - cape_data: SkinImage - geometry_data: string - animation_data: string - premium: bool - persona: bool - cape_on_classic: bool - cape_id: string - full_skin_id: string - arm_size: string - skin_color: string - personal_pieces: []li32 - piece_id: string - piece_type: string - pack_id: string - is_default_piece: bool - product_id: string - piece_tint_colors: []li32 - piece_type: string - colors: string[]li32 - -PlayerRecords: - type: u8 => - 0: add - 1: remove - records_count: varint - records: []$records_count - _: type? - if add: - uuid: uuid - entity_unique_id: zigzag64 - username: string - xbox_user_id: string - platform_chat_id: string - build_platform: li32 - skin_data: Skin - is_teacher: bool - is_host: bool - if remove: - uuid: uuid - verified: type ? - if add: bool[]$records_count - -Enchant: - id: u8 - level: u8 - -EnchantOption: - cost: varint - slot_flags: li32 - equip_enchants: Enchant[]varint - held_enchants: Enchant[]varint - self_enchants: Enchant[]varint - name: string - option_id: zigzag32 - -Action: zigzag32 => - 0: start_break - 1: abort_break - 2: stop_break - 3: get_updated_block - 4: drop_item - 5: start_sleeping - 6: stop_sleeping - 7: respawn - 8: jump - 9: start_sprint - 10: stop_sprint - 11: start_sneak - 12: stop_sneak - 13: creative_player_destroy_block - # sent when spawning in a different dimension to tell the server we spawned - 14: dimension_change_ack - 15: start_glide - 16: stop_glide - 17: build_denied - 18: crack_break - 19: change_skin - # no longer used - 20: set_enchatnment_seed - 21: swimming - 22: stop_swimming - 23: start_spin_attack - 24: stop_spin_attack - 25: interact_block - 26: predict_break - 27: continue_break - -# Source and Destination point to the source slot from which Count of the item stack were taken and the -# destination slot to which this item was moved. -StackRequestSlotInfo: - # ContainerID is the ID of the container that the slot was in. - slot_type: ContainerSlotType - # Slot is the index of the slot within the container with the ContainerID above. - slot: u8 - # StackNetworkID is the unique stack ID that the client assumes to be present in this slot. The server - # must check if these IDs match. If they do not match, servers should reject the stack request that the - # action holding this info was in. - stack_id: zigzag32 - -# ItemStackRequest is sent by the client to change item stacks in an inventory. It is essentially a -# replacement of the InventoryTransaction packet added in 1.16 for inventory specific actions, such as moving -# items around or crafting. The InventoryTransaction packet is still used for actions such as placing blocks -# and interacting with entities. -ItemStackRequest: - # RequestID is a unique ID for the request. This ID is used by the server to send a response for this - # specific request in the ItemStackResponse packet. - request_id: varint - actions: []varint - type_id: u8 => - # TakeStackRequestAction is sent by the client to the server to take x amount of items from one slot in a - # container to the cursor. - 0: take - # PlaceStackRequestAction is sent by the client to the server to place x amount of items from one slot into - # another slot, such as when shift clicking an item in the inventory to move it around or when moving an item - # in the cursor into a slot. - 1: place - # SwapStackRequestAction is sent by the client to swap the item in its cursor with an item present in another - # container. The two item stacks swap places. - 2: swap - # DropStackRequestAction is sent by the client when it drops an item out of the inventory when it has its - # inventory opened. This action is not sent when a player drops an item out of the hotbar using the Q button - # (or the equivalent on mobile). The InventoryTransaction packet is still used for that action, regardless of - # whether the item stack network IDs are used or not. - 3: drop - # DestroyStackRequestAction is sent by the client when it destroys an item in creative mode by moving it - # back into the creative inventory. - 4: destroy - # ConsumeStackRequestAction is sent by the client when it uses an item to craft another item. The original - # item is 'consumed'. - 5: consume - # CreateStackRequestAction is sent by the client when an item is created through being used as part of a - # recipe. For example, when milk is used to craft a cake, the buckets are leftover. The buckets are moved to - # the slot sent by the client here. - # Note that before this is sent, an action for consuming all items in the crafting table/grid is sent. Items - # that are not fully consumed when used for a recipe should not be destroyed there, but instead, should be - # turned into their respective resulting items. - 6: create - # LabTableCombineStackRequestAction is sent by the client when it uses a lab table to combine item stacks. - 7: lab_table_combine - # BeaconPaymentStackRequestAction is sent by the client when it submits an item to enable effects from a - # beacon. These items will have been moved into the beacon item slot in advance. - 8: beacon_payment - # MineBlockStackRequestAction is sent by the client when it breaks a block. - 9: mine_block - # CraftRecipeStackRequestAction is sent by the client the moment it begins crafting an item. This is the - # first action sent, before the Consume and Create item stack request actions. - # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as - # crafting, where the old item is consumed. - 10: craft_recipe - # AutoCraftRecipeStackRequestAction is sent by the client similarly to the CraftRecipeStackRequestAction. The - # only difference is that the recipe is automatically created and crafted by shift clicking the recipe book. - 11: craft_recipe_auto #recipe book? - # CraftCreativeStackRequestAction is sent by the client when it takes an item out fo the creative inventory. - # The item is thus not really crafted, but instantly created. - 12: craft_creative - # CraftRecipeOptionalStackRequestAction is sent when using an anvil. When this action is sent, the - # CustomNames field in the respective stack request is non-empty and contains the name of the item created - # using the anvil. - 13: optional - # CraftNonImplementedStackRequestAction is an action sent for inventory actions that aren't yet implemented - # in the new system. These include, for example, anvils. - 14: non_implemented #anvils aren't fully implemented yet - # CraftResultsDeprecatedStackRequestAction is an additional, deprecated packet sent by the client after - # crafting. It holds the final results and the amount of times the recipe was crafted. It shouldn't be used. - # This action is also sent when an item is enchanted. Enchanting should be treated mostly the same way as - # crafting, where the old item is consumed. - 15: results_deprecated - _: type_id ? - if take or place: - count: u8 - source: StackRequestSlotInfo - destination: StackRequestSlotInfo - if swap: - # Source and Destination point to the source slot from which Count of the item stack were taken and the - # destination slot to which this item was moved. - source: StackRequestSlotInfo - destination: StackRequestSlotInfo - if drop: - # Count is the count of the item in the source slot that was taken towards the destination slot. - count: u8 - # Source is the source slot from which items were dropped to the ground. - source: StackRequestSlotInfo - # Randomly seems to be set to false in most cases. I'm not entirely sure what this does, but this is what - # vanilla calls this field. - randomly: bool - if destroy or consume: - # Count is the count of the item in the source slot that was destroyed. - count: u8 - # Source is the source slot from which items came that were destroyed by moving them into the creative - # inventory. - source: StackRequestSlotInfo - if create: - # ResultsSlot is the slot in the inventory in which the results of the crafting ingredients are to be - # placed. - result_slot_id: u8 - if beacon_payment: - # PrimaryEffect and SecondaryEffect are the effects that were selected from the beacon. - primary_effect: zigzag32 - secondary_effect: zigzag32 - if mine_block: - # // Unknown1 ... TODO: Find out what this is for - unknown1: zigzag32 - # PredictedDurability is the durability of the item that the client assumes to be present at the time - predicted_durability: zigzag32 - # StackNetworkID is the unique stack ID that the client assumes to be present at the time. The server - # must check if these IDs match. If they do not match, servers should reject the stack request that the - # action holding this info was in. - network_id: zigzag32 - if craft_recipe or craft_recipe_auto: - # RecipeNetworkID is the network ID of the recipe that is about to be crafted. This network ID matches - # one of the recipes sent in the CraftingData packet, where each of the recipes have a RecipeNetworkID as - # of 1.16. - recipe_network_id: varint - if craft_creative: - # The stack ID of the creative item that is being created. This is one of the - # creative item stack IDs sent in the CreativeContent packet. - item_id: varint - if optional: - # For the cartography table, if a certain MULTI recipe is being called, this points to the network ID that was assigned. - recipe_network_id: varint - # Most likely the index in the request's filter strings that this action is using - filtered_string_index: li32 - if non_implemented: void - if results_deprecated: - result_items: ItemLegacy[]varint - times_crafted: u8 - # CustomNames is a list of custom names involved in the request. This is typically filled with one string - # when an anvil is used. - # * Used for the server to determine which strings should be filtered. Used in anvils to verify a renamed item. - custom_names: string[]varint - -# ItemStackResponse is a response to an individual ItemStackRequest. -ItemStackResponses: []varint - # Status specifies if the request with the RequestID below was successful. If this is the case, the - # ContainerInfo below will have information on what slots ended up changing. If not, the container info - # will be empty. - # A non-0 status means an error occurred and will result in the action being reverted. - status: u8 => - 0: ok - 1: error - # RequestID is the unique ID of the request that this response is in reaction to. If rejected, the client - # will undo the actions from the request with this ID. - request_id: varint - _: status ? - if ok: - # ContainerInfo holds information on the containers that had their contents changed as a result of the - # request. - containers: []varint - # ContainerID is the container ID of the container that the slots that follow are in. For the main - # inventory, this value seems to be 0x1b. For the cursor, this value seems to be 0x3a. For the crafting - # grid, this value seems to be 0x0d. - # * actually, this is ContainerSlotType - used by the inventory system that specifies the type of slot - slot_type: ContainerSlotType - # SlotInfo holds information on what item stack should be present in specific slots in the container. - slots: []varint - # Slot and HotbarSlot seem to be the same value every time: The slot that was actually changed. I'm not - # sure if these slots ever differ. - slot: u8 - hotbar_slot: u8 - # Count is the total count of the item stack. This count will be shown client-side after the response is - # sent to the client. - count: u8 - # StackNetworkID is the network ID of the new stack at a specific slot. - item_stack_id: varint - # CustomName is the custom name of the item stack. It is used in relation to text filtering. - custom_name: string - # DurabilityCorrection is the current durability of the item stack. This durability will be shown - # client-side after the response is sent to the client. - durability_correction: zigzag32 - - -ItemComponentList: []varint - # Name is the name of the item, which is a name like 'minecraft:stick'. - name: string - # Data is a map containing the components and properties of the item. - nbt: nbt - -CommandOrigin: - # Origin is one of the values above that specifies the origin of the command. The origin may change, - # depending on what part of the client actually called the command. The command may be issued by a - # websocket server, for example. - type: varint => - 0: player - 1: block - 2: minecart_block - 3: dev_console - 4: test - 5: automation_player - 6: client_automation - 7: dedicated_server - 8: entity - 9: virtual - 10: game_argument - 11: entity_server - 12: precompiled - 13: game_director_entity_server # ? - 14: script - - # UUID is the UUID of the command called. This UUID is a bit odd as it is not specified by the server. It - # is not clear what exactly this UUID is meant to identify, but it is unique for each command called. - uuid: uuid - # RequestID is an ID that identifies the request of the client. The server should send a CommandOrigin - # with the same request ID to ensure it can be matched with the request by the caller of the command. - # This is especially important for websocket servers and it seems that this field is only non-empty for - # these websocket servers. - request_id: string - # PlayerUniqueID is an ID that identifies the player, the same as the one found in the AdventureSettings - # packet. Filling it out with 0 seems to work. - # PlayerUniqueID is only written if Origin is CommandOriginDevConsole or CommandOriginTest. - player_entity_id: type? - if dev_console or test: - player_entity_id: zigzag64 - -# MapTrackedObject is an object on a map that is 'tracked' by the client, such as an entity or a block. This -# object may move, which is handled client-side. -TrackedObject: - # Type is the type of the tracked object. It is either MapObjectTypeEntity or MapObjectTypeBlock. - type: li32 => - 0: entity - 1: block - # EntityUniqueID is the unique ID of the entity, if the tracked object was an entity. It needs not to be - # filled out if Type is not MapObjectTypeEntity. - entity_unique_id: type ? - if entity: zigzag64 - # BlockPosition is the position of the block, if the tracked object was a block. It needs not to be - # filled out if Type is not MapObjectTypeBlock. - block_position: type ? - if block: BlockCoordinates - -# MapDecoration is a fixed decoration on a map: Its position or other properties do not change automatically -# client-side. -MapDecoration: - type: u8 - # Rotation is the rotation of the map decoration. It is byte due to the 16 fixed directions that the - # map decoration may face. - rotation: u8 - # X is the offset on the X axis in pixels of the decoration. - x: u8 - # Y is the offset on the Y axis in pixels of the decoration. - y: u8 - # Label is the name of the map decoration. This name may be of any value. - label: string - # Colour is the colour of the map decoration. Some map decoration types have a specific colour set - # automatically, whereas others may be changed. - color_abgr: varint - - -StructureBlockSettings: - # PaletteName is the name of the palette used in the structure. Currently, it seems that this field is - # always 'default'. - palette_name: string - # IgnoreEntities specifies if the structure should ignore entities or include them. If set to false, - # entities will also show up in the exported structure. - ignore_entities: bool - # IgnoreBlocks specifies if the structure should ignore blocks or include them. If set to false, blocks - # will show up in the exported structure. - ignore_blocks: bool - # Size is the size of the area that is about to be exported. The area exported will start at the - # Position + Offset, and will extend as far as Size specifies. - size: BlockCoordinates - # Offset is the offset position that was set in the structure block. The area exported is offset by this - # position. - # **TODO**: This will be renamed to offset soon - structure_offset: BlockCoordinates - # LastEditingPlayerUniqueID is the unique ID of the player that last edited the structure block that - # these settings concern. - last_editing_player_unique_id: zigzag64 - # Rotation is the rotation that the structure block should obtain. See the constants above for available - # options. - rotation: u8 => - 0: none - 1: 90_deg - 2: 180_deg - 3: 270_deg - # Mirror specifies the way the structure should be mirrored. It is either no mirror at all, mirror on the - # x/z axis or both. - mirror: u8 => - 0: none - 1: x_axis - 2: z_axis - 3: both_axes - animation_mode: u8 => - 0: none - 1: layers - 2: blocks - # How long the duration for this animation is - animation_duration: lf32 - # Integrity is usually 1, but may be set to a number between 0 and 1 to omit blocks randomly, using - # the Seed that follows. - integrity: lf32 - # Seed is the seed used to omit blocks if Integrity is not equal to one. If the Seed is 0, a random - # seed is selected to omit blocks. - seed: lu32 - # Pivot is the pivot around which the structure may be rotated. - pivot: vec3f - -# List of Window IDs. When a new container is opened (container_open), a new sequential Window ID is created. -# Below window IDs are hard-coded and created when the game starts and the server does not -# send a `container_open` for them. -WindowID: i8 => - -100: drop_contents - -24: beacon - -23: trading_output - -22: trading_use_inputs - -21: trading_input_2 - -20: trading_input_1 - -17: enchant_output - -16: enchant_material - -15: enchant_input - -13: anvil_output - -12: anvil_result - -11: anvil_material - -10: container_input - -5: crafting_use_ingredient - -4: crafting_result - -3: crafting_remove_ingredient - -2: crafting_add_ingredient - -1: none - 0: inventory - 1: first - 100: last - 119: offhand - 120: armor - 121: creative - 122: hotbar - 123: fixed_inventory - 124: ui - -WindowIDVarint: varint => - -100: drop_contents - -24: beacon - -23: trading_output - -22: trading_use_inputs - -21: trading_input_2 - -20: trading_input_1 - -17: enchant_output - -16: enchant_material - -15: enchant_input - -13: anvil_output - -12: anvil_result - -11: anvil_material - -10: container_input - -5: crafting_use_ingredient - -4: crafting_result - -3: crafting_remove_ingredient - -2: crafting_add_ingredient - -1: none - 0: inventory - 1: first - 100: last - 119: offhand - 120: armor - 121: creative - 122: hotbar - 123: fixed_inventory - 124: ui - -WindowType: i8 => - -9: none - -1: inventory - 0: container - 1: workbench - 2: furnace - 3: enchantment - 4: brewing_stand - 5: anvil - 6: dispenser - 7: dropper - 8: hopper - 9: cauldron - 10: minecart_chest - 11: minecart_hopper - 12: horse - 13: beacon - 14: structure_editor - 15: trading - 16: command_block - 17: jukebox - 18: armor - 19: hand - 20: compound_creator - 21: element_constructor - 22: material_reducer - 23: lab_table - 24: loom - 25: lectern - 26: grindstone - 27: blast_furnace - 28: smoker - 29: stonecutter - 30: cartography - 31: hud - 32: jigsaw_editor - 33: smithing_table - -# Used in inventory transactions. -ContainerSlotType: u8 => - - anvil_input - - anvil_material - - anvil_result - - smithing_table_input - - smithing_table_material - - smithing_table_result - - armor - - container - - beacon_payment - - brewing_input - - brewing_result - - brewing_fuel - - hotbar_and_inventory - - crafting_input - - crafting_output - - recipe_construction - - recipe_nature - - recipe_items - - recipe_search - - recipe_search_bar - - recipe_equipment - - enchanting_input - - enchanting_lapis - - furnace_fuel - - furnace_ingredient - - furnace_output - - horse_equip - - hotbar - - inventory - - shulker - - trade_ingredient1 - - trade_ingredient2 - - trade_result - - offhand - - compcreate_input - - compcreate_output - - elemconstruct_output - - matreduce_input - - matreduce_output - - labtable_input - - loom_input - - loom_dye - - loom_material - - loom_result - - blast_furnace_ingredient - - smoker_ingredient - - trade2_ingredient1 - - trade2_ingredient2 - - trade2_result - - grindstone_input - - grindstone_additional - - grindstone_result - - stonecutter_input - - stonecutter_result - - cartography_input - - cartography_additional - - cartography_result - - barrel - - cursor - - creative_output - -SoundType: varint => - - ItemUseOn - - Hit - - Step - - Fly - - Jump - - Break - - Place - - HeavyStep - - Gallop - - Fall - - Ambient - - AmbientBaby - - AmbientInWater - - Breathe - - Death - - DeathInWater - - DeathToZombie - - Hurt - - HurtInWater - - Mad - - Boost - - Bow - - SquishBig - - SquishSmall - - FallBig - - FallSmall - - Splash - - Fizz - - Flap - - Swim - - Drink - - Eat - - Takeoff - - Shake - - Plop - - Land - - Saddle - - Armor - - MobArmorStandPlace - - AddChest - - Throw - - Attack - - AttackNoDamage - - AttackStrong - - Warn - - Shear - - Milk - - Thunder - - Explode - - Fire - - Ignite - - Fuse - - Stare - - Spawn - - Shoot - - BreakBlock - - Launch - - Blast - - LargeBlast - - Twinkle - - Remedy - - Infect - - LevelUp - - BowHit - - BulletHit - - ExtinguishFire - - ItemFizz - - ChestOpen - - ChestClosed - - ShulkerBoxOpen - - ShulkerBoxClosed - - EnderChestOpen - - EnderChestClosed - - PowerOn - - PowerOff - - Attach - - Detach - - Deny - - Tripod - - Pop - - DropSlot - - Note - - Thorns - - PistonIn - - PistonOut - - Portal - - Water - - LavaPop - - Lava - - Burp - - BucketFillWater - - BucketFillLava - - BucketEmptyWater - - BucketEmptyLava - - ArmorEquipChain - - ArmorEquipDiamond - - ArmorEquipGeneric - - ArmorEquipGold - - ArmorEquipIron - - ArmorEquipLeather - - ArmorEquipElytra - - Record13 - - RecordCat - - RecordBlocks - - RecordChirp - - RecordFar - - RecordMall - - RecordMellohi - - RecordStal - - RecordStrad - - RecordWard - - Record11 - - RecordWait - - unknown1 - - Flop - - ElderGuardianCurse - - MobWarning - - MobWarningBaby - - Teleport - - ShulkerOpen - - ShulkerClose - - Haggle - - HaggleYes - - HaggleNo - - HaggleIdle - - ChorusGrow - - ChorusDeath - - Glass - - PotionBrewed - - CastSpell - - PrepareAttack - - PrepareSummon - - PrepareWololo - - Fang - - Charge - - CameraTakePicture - - LeashKnotPlace - - LeashKnotBreak - - Growl - - Whine - - Pant - - Purr - - Purreow - - DeathMinVolume - - DeathMidVolume - - unknown2 - - ImitateCaveSpider - - ImitateCreeper - - ImitateElderGuardian - - ImitateEnderDragon - - ImitateEnderman - - unknown3 - - ImitateEvocationIllager - - ImitateGhast - - ImitateHusk - - ImitateIllusionIllager - - ImitateMagmaCube - - ImitatePolarBear - - ImitateShulker - - ImitateSilverfish - - ImitateSkeleton - - ImitateSlime - - ImitateSpider - - ImitateStray - - ImitateVex - - ImitateVindicationIllager - - ImitateWitch - - ImitateWither - - ImitateWitherSkeleton - - ImitateWolf - - ImitateZombie - - ImitateZombiePigman - - ImitateZombieVillager - - BlockEndPortalFrameFill - - BlockEndPortalSpawn - - RandomAnvilUse - - BottleDragonBreath - - PortalTravel - - ItemTridentHit - - ItemTridentReturn - - ItemTridentRiptide1 - - ItemTridentRiptide2 - - ItemTridentRiptide3 - - ItemTridentThrow - - ItemTridentThunder - - ItemTridentHitGround - - Default - - BlockFletchingTableUse - - ElemConstructOpen - - IceBombHit - - BalloonPop - - LtReactionIceBomb - - LtReactionBleach - - LtReactionEPaste - - LtReactionEPaste2 - - LtReactionFertilizer - - LtReactionFireball - - LtReactionMgsalt - - LtReactionMiscfire - - LtReactionFire - - LtReactionMiscexplosion - - LtReactionMiscmystical - - LtReactionMiscmystical2 - - LtReactionProduct - - SparklerUse - - GlowstickUse - - SparklerActive - - ConvertToDrowned - - BucketFillFish - - BucketEmptyFish - - BubbleUp - - BubbleDown - - BubblePop - - BubbleUpInside - - BubbleDownInside - - HurtBaby - - DeathBaby - - StepBaby - - BabySpawn - - Born - - BlockTurtleEggBreak - - BlockTurtleEggCrack - - BlockTurtleEggHatch - - TurtleLayEgg - - BlockTurtleEggAttack - - BeaconActivate - - BeaconAmbient - - BeaconDeactivate - - BeaconPower - - ConduitActivate - - ConduitAmbient - - ConduitAttack - - ConduitDeactivate - - ConduitShort - - Swoop - - BlockBambooSaplingPlace - - PreSneeze - - Sneeze - - AmbientTame - - Scared - - BlockScaffoldingClimb - - CrossbowLoadingStart - - CrossbowLoadingMiddle - - CrossbowLoadingEnd - - CrossbowShoot - - CrossbowQuickChargeStart - - CrossbowQuickChargeMiddle - - CrossbowQuickChargeEnd - - AmbientAggressive - - AmbientWorried - - CantBreed - - ItemShieldBlock - - ItemBookPut - - BlockGrindstoneUse - - BlockBellHit - - BlockCampfireCrackle - - Roar - - Stun - - BlockSweetBerryBushHurt - - BlockSweetBerryBushPick - - UICartographyTableTakeResult - - UIStoneCutterTakeResult - - BlockComposterEmpty - - BlockComposterFill - - BlockComposterFillSuccess - - BlockComposterReady - - BlockBarrelOpen - - BlockBarrelClose - - RaidHorn - - BlockLoomUse - - AmbientRaid - - UICartographyTableUse - - UIStoneCutterUse - - UILoomUse - - SmokerUse - - BlastFurnaceUse - - SmithingTableUse - - Screech - - Sleep - - FurnaceUse - - MooshroomConvert - - MilkSuspiciously - - Celebrate - - JumpPrevent - - AmbientPollinate - - BeeHiveDrip - - BeeHiveEnter - - BeeHiveExit - - BeeHiveWork - - BeeHiveShear - - HoneyBottleDrink - - AmbientCave - - Retreat - - ConvertToZombified - - Admire - - StepLava - - Tempt - - Panic - - Angry - - AmbientWarpedForest - - AmbientSoulsandValley - - AmbientNetherWastes - - AmbientBasaltDeltas - - AmbientCrimsonForest - - RespawnAnchorCharge - - RespawnAnchorDeplete - - RespawnAnchorSetSpawn - - RespawnAnchorAmbient - - SoulEscapeQuiet - - SoulEscapeLoud - - RecordPigstep - - LinkCompassToLodestone - - BlockSmithingTableUse - - EquipNetherite - - AmbientLoopWarpedForest - - AmbientLoopSoulsandValley - - AmbientLoopNetherWastes - - AmbientLoopBasaltDeltas - - AmbientLoopCrimsonForest - - AmbientAdditionWarpedForest - - AmbientAdditionSoulsandValley - - AmbientAdditionNetherWastes - - AmbientAdditionBasaltDeltas - - AmbientAdditionCrimsonForest - - SculkSensorPowerOn - - SculkSensorPowerOff - - BucketFillPowderSnow - - BucketEmptyPowderSnow - - PointedDripstoneCauldronDripWater - - PointedDripstoneCauldronDripLava - - PointedDripstoneDripWater - - PointedDripstoneDripLava - - CaveVinesPickBerries - - BigDripleafTiltDown - - BigDripleafTiltUp - - unknown335 - - unknown336 - - unknown337 - - unknown338 - - copper_wax_on - - copper_wax_off - - scrape - - player_hurt_drown - - player_hurt_on_fire - - player_hurt_freeze - - use_spyglass - - stop_using_spyglass - - amethyst_block_chime - - ambient_screamer - - hurt_screamer - - death_screamer - - milk_screamer - - jump_to_block - - pre_ram - - pre_ram_screamer - - ram_impact - - ram_impact_screamer - - squid_ink_squirt - - glow_squid_ink_squirt - - convert_to_stray - - extinguish_candle - - ambient_candle - - Undefined - -# TODO: remove? -LegacyEntityType: li32 => - 10: chicken - 11: cow - 12: pig - 13: sheep - 14: wolf - 15: villager - 16: mooshroom - 17: squid - 18: rabbit - 19: bat - 20: iron_golem - 21: snow_golem - 22: ocelot - 23: horse - 24: donkey - 25: mule - 26: skeleton_horse - 27: zombie_horse - 28: polar_bear - 29: llama - 30: parrot - 31: dolphin - 32: zombie - 33: creeper - 34: skeleton - 35: spider - 36: zombie_pigman - 37: slime - 38: enderman - 39: silverfish - 40: cave_spider - 41: ghast - 42: magma_cube - 43: blaze - 44: zombie_villager - 45: witch - 46: stray - 47: husk - 48: wither_skeleton - 49: guardian - 50: elder_guardian - 51: npc - 52: wither - 53: ender_dragon - 54: shulker - 55: endermite - 56: agent # LEARN_TO_CODE_MASCOT - 57: vindicator - 58: phantom - 61: armor_stand - 62: tripod_camera - 63: player - 64: item - 65: tnt - 66: falling_block - 67: moving_block - 68: xp_bottle - 69: xp_orb - 70: eye_of_ender_signal - 71: ender_crystal - 72: fireworks_rocket - 73: thrown_trident - 74: turtle - 75: cat - 76: shulker_bullet - 77: fishing_hook - 78: chalkboard - 79: dragon_fireball - 80: arrow - 81: snowball - 82: egg - 83: painting - 84: minecart - 85: fireball - 86: splash_potion - 87: ender_pearl - 88: leash_knot - 89: wither_skull - 90: boat - 91: wither_skull_dangerous - 93: lightning_bolt - 94: small_fireball - 95: area_effect_cloud - 96: hopper_minecart - 97: tnt_minecart - 98: chest_minecart - 100: command_block_minecart - 101: lingering_potion - 102: llama_spit - 103: evocation_fang - 104: evocation_illager - 105: vex - 106: ice_bomb - 107: balloon - 108: pufferfish - 109: salmon - 110: drowned - 111: tropicalfish - 112: cod - 113: panda \ No newline at end of file diff --git a/data/provider.js b/data/provider.js deleted file mode 100644 index 6ad1af7..0000000 --- a/data/provider.js +++ /dev/null @@ -1,44 +0,0 @@ -const { Versions } = require('../src/options') -const { getFiles } = require('../src/datatypes/util') -const { join } = require('path') - -let fileMap = {} - -// Walks all the directories for each of the supported versions in options.js -// then builds a file map for each version -// { 'protocol.json': { '1.16.200': '1.16.200/protocol.json', '1.16.210': '1.16.210/...' } } -function loadVersions () { - for (const version in Versions) { - let files = [] - try { - files = getFiles(join(__dirname, '/', version)) - } catch {} - for (const file of files) { - const rfile = file.replace(join(__dirname, '/', version) + '/', '') - fileMap[rfile] = fileMap[rfile] ?? [] - fileMap[rfile].push([Versions[version], file]) - fileMap[rfile].sort().reverse() - } - } -} - -module.exports = (protocolVersion) => { - fileMap = {} - loadVersions() - return { - // Returns the most recent file based on the specified protocolVersion - // e.g. if `version` is 1.16 and a file for 1.16 doesn't exist, load from 1.15 file - getPath (file) { - if (!fileMap[file]) { - throw Error('Unknown file ' + file) - } - for (const [pver, path] of fileMap[file]) { - if (pver <= protocolVersion) { - // console.debug('for', file, 'returining', path) - return path - } - } - throw Error('unknown file ' + file) - } - } -} diff --git a/examples/server/server.js b/examples/server/server.js index 8e4e74d..7d247a0 100644 --- a/examples/server/server.js +++ b/examples/server/server.js @@ -16,9 +16,9 @@ process.env.DEBUG = 'minecraft-protocol' // packet logging const { Server } = require('bedrock-protocol') const { hasDumps } = require('../../tools/genPacketDumps') -const DataProvider = require('../../data/provider') const { waitFor } = require('../../src/datatypes/util') const { loadWorld } = require('./serverChunks') +const { join } = require('path') async function startServer (version = '1.17.10', ok) { if (!hasDumps(version)) { @@ -30,7 +30,7 @@ async function startServer (version = '1.17.10', ok) { const server = new Server({ host: '0.0.0.0', port, version }) let loop - const getPath = (packetPath) => DataProvider(server.options.protocolVersion).getPath(packetPath) + const getPath = (packetPath) => join(__dirname, `../data/${server.options.version}/${packetPath}`) const get = (packetName) => require(getPath(`sample/packets/${packetName}.json`)) server.listen() diff --git a/package.json b/package.json index 44bdda2..a8aadfb 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "main": "index.js", "scripts": { "build": "cd tools && node compileProtocol.js", - "prepare": "npm run build", "test": "mocha --bail", "pretest": "npm run lint", "lint": "standard", @@ -24,6 +23,7 @@ "debug": "^4.3.1", "jsonwebtoken": "^8.5.1", "jsp-raknet": "^2.1.3", + "minecraft-data": "^2.89.4", "minecraft-folder-path": "^1.2.0", "prismarine-auth": "^1.1.0", "prismarine-nbt": "^1.5.0", diff --git a/src/createClient.js b/src/createClient.js index e79b9a7..4485acb 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -15,7 +15,7 @@ function createClient (options) { client.ping().then(data => { const advert = advertisement.fromServerName(data) console.log(`Connecting to server ${advert.motd} (${advert.name}), version ${advert.version}`) - client.version = options.version ?? advert.version + client.options.version = options.version ?? advert.version connect(client) }, client) } diff --git a/src/handshake/login.js b/src/handshake/login.js index e4a9be8..4fd0163 100644 --- a/src/handshake/login.js +++ b/src/handshake/login.js @@ -1,15 +1,10 @@ -const fs = require('fs') const JWT = require('jsonwebtoken') -const DataProvider = require('../../data/provider') const { nextUUID } = require('../datatypes/util') const { PUBLIC_KEY } = require('./constants') const algorithm = 'ES384' module.exports = (client, server, options) => { - const dp = DataProvider(options.protocolVersion) - const skinTex = fs.readFileSync(dp.getPath('steveSkin.bin')).toString('base64') - const skinGeom = fs.readFileSync(dp.getPath('steveGeometry.json')).toString('base64') - const skinData = JSON.parse(fs.readFileSync(dp.getPath('steve.json'), 'utf-8')) + const skinData = require('minecraft-data')('bedrock_' + options.version).defaultSkin client.createClientChain = (mojangKey, offline) => { const privateKey = client.ecdhKeyPair.privateKey @@ -60,8 +55,6 @@ module.exports = (client, server, options) => { SelfSignedId: nextUUID(), ServerAddress: `${options.host}:${options.port}`, - SkinData: skinTex, - SkinGeometryData: skinGeom, ThirdPartyName: client.profile.name, ThirdPartyNameOnly: false, diff --git a/src/options.js b/src/options.js index 32d7d93..ac06ac7 100644 --- a/src/options.js +++ b/src/options.js @@ -1,15 +1,11 @@ +const mcData = require('minecraft-data') + // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' -// Currently supported verson +// Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data const CURRENT_VERSION = '1.17.10' -const Versions = { - '1.17.10': 448, - '1.17.0': 440, - '1.16.220': 431, - '1.16.210': 428, - '1.16.201': 422 -} +const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 4a6102f..7311698 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -27,10 +27,13 @@ class Parser extends FullPacketParser { // Compiles the ProtoDef schema at runtime function createProtocol (version) { - const protocol = require(join(__dirname, `../../data/${version}/protocol.json`)).types + // Try and load from .js if available + try { require(`../../data/${version}/size.js`); return getProtocol(version) } catch {} + + const protocol = require('minecraft-data')('bedrock_' + version).protocol const compiler = new ProtoDefCompiler() - compiler.addTypesToCompile(protocol) - compiler.addTypes(require(join(__dirname, '../datatypes/compiler-minecraft'))) + compiler.addTypesToCompile(protocol.types) + compiler.addTypes(require('../datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) const compiledProto = compiler.compileProtoDefSync() @@ -54,17 +57,18 @@ function getProtocol (version) { } function createSerializer (version) { - const proto = getProtocol(version) + const proto = createProtocol(version) return new Serializer(proto, 'mcpe_packet') } function createDeserializer (version) { - const proto = getProtocol(version) + const proto = createProtocol(version) return new Parser(proto, 'mcpe_packet') } module.exports = { - createDeserializer: createDeserializer, - createSerializer: createSerializer, - createProtocol: createProtocol + createDeserializer, + createSerializer, + createProtocol, + getProtocol } diff --git a/test/internal.js b/test/internal.js index fd318c4..c03a498 100644 --- a/test/internal.js +++ b/test/internal.js @@ -1,8 +1,8 @@ const { Server, Client } = require('../') const { dumpPackets } = require('../tools/genPacketDumps') -const DataProvider = require('../data/provider') const { ping } = require('../src/createClient') const { CURRENT_VERSION } = require('../src/options') +const { join } = require('path') // First we need to dump some packets that a vanilla server would send a vanilla // client. Then we can replay those back in our custom server. @@ -17,7 +17,7 @@ async function startTest (version = CURRENT_VERSION, ok) { const server = new Server({ host: '0.0.0.0', port, version, offline: true }) function getPath (packetPath) { - return DataProvider(server.options.protocolVersion).getPath(packetPath) + return join(__dirname, `../data/${server.options.version}/${packetPath}`) } function get (packetPath) { diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index bed7b2c..079dca3 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -1,56 +1,19 @@ /** - * This is a utility script that converts the YAML here into ProtoDef schema code and (soon) docs/typescript definitions. - * It also pre-compiles JS code from the schema for easier development. - * + * Pre-compiles JS code from the schema for easier development. * You can run this with `npm run build` - * */ const fs = require('fs') const { ProtoDefCompiler } = require('protodef').Compiler -const { Versions } = require('../src/options') +const { convert } = require('minecraft-data/minecraft-data/tools/js/compileProtocol') +const mcData = require('minecraft-data') const { join } = require('path') - -function getJSON (path) { - return JSON.parse(fs.readFileSync(path, 'utf-8')) -} - -// Parse the YML files and turn to JSON -function genProtoSchema () { - const { parse, compile } = require('protodef-yaml/compiler') - - // Create the packet_map.yml from proto.yml - const parsed = parse('./proto.yml') - const version = parsed['!version'] - const packets = [] - for (const key in parsed) { - if (key.startsWith('%container')) { - const [, name] = key.split(',') - if (name.startsWith('packet_')) { - const children = parsed[key] - const packetName = name.replace('packet_', '') - const packetID = children['!id'] - packets.push([packetID, packetName, name]) - } - } - } - let l1 = '' - let l2 = '' - for (const [id, name, fname] of packets) { - l1 += ` 0x${id.toString(16).padStart(2, '0')}: ${name}\n` - l2 += ` if ${name}: ${fname}\n` - } - // TODO: skip creating packet_map.yml and just generate the ProtoDef map JSON directly - const t = `#Auto-generated from proto.yml, do not modify\n!import: types.yaml\nmcpe_packet:\n name: varint =>\n${l1}\n params: name ?\n${l2}` - fs.writeFileSync('./packet_map.yml', t) - - compile('./proto.yml', 'proto.json') - return version -} +// Filter versions we support +const versions = mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => e.minecraftVersion) // Compile the ProtoDef JSON into JS -function createProtocol () { +function createProtocol (version) { const compiler = new ProtoDefCompiler() - const protocol = getJSON('./protocol.json').types + const protocol = mcData('bedrock_' + version).protocol.types compiler.addTypes(require('../src/datatypes/compiler-minecraft')) compiler.addTypes(require('prismarine-nbt/compiler-zigzag')) compiler.addTypesToCompile(protocol) @@ -63,27 +26,19 @@ function createProtocol () { return compiledProto } -function copyLatest () { - process.chdir(join(__dirname, '/../data/latest')) - const version = genProtoSchema() - try { fs.mkdirSync(`../${version}`) } catch {} - fs.writeFileSync(`../${version}/protocol.json`, JSON.stringify({ types: getJSON('./proto.json') }, null, 2)) - fs.unlinkSync('./proto.json') // remove temp file - fs.unlinkSync('./packet_map.yml') // remove temp file - return version -} - function main (ver = 'latest') { - if (ver === 'latest') ver = copyLatest() - process.chdir(join(__dirname, '/../data/', ver)) + // Put the .js files into the data/ dir, we also use the data dir when dumping packets for tests + const dir = join(__dirname, '/../data/', ver) + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }) + process.chdir(dir) console.log('Generating JS...', ver) createProtocol(ver) } // If no argument, build everything if (!process.argv[2]) { - copyLatest() - for (const version in Versions) { + convert('latest') + for (const version of versions) { main(version) } } else { // build the specified version From 72a4743993cedaf39fcb3ee0eadcd314cda5212c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 21:22:07 +0200 Subject: [PATCH 225/458] Bump mocha from 8.4.0 to 9.1.2 (#138) Bumps [mocha](https://github.com/mochajs/mocha) from 8.4.0 to 9.1.2. - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v8.4.0...v9.1.2) --- updated-dependencies: - dependency-name: mocha dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a8aadfb..bb886ab 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "bedrock-protocol": "file:.", "bedrock-provider": "^1.0.0", "leveldb-zlib": "^1.0.1", - "mocha": "^8.3.2", + "mocha": "^9.1.2", "protodef-yaml": "^1.1.0", "standard": "^16.0.3" }, From 10feeea4cafc0fd09cdd31266ab35bb8ac557211 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 4 Oct 2021 13:27:38 -0400 Subject: [PATCH 226/458] Release 3.6.0 (#141) --- HISTORY.md | 4 ++++ README.md | 2 +- index.d.ts | 2 +- package.json | 2 +- src/options.js | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index ac57572..d63898e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## 3.6.0 +* 1.17.30 support +* minecraft-data used for protocol data + ## 3.5.1 * Fix 1.17.10 npc packet serialization (#119) diff --git a/README.md b/README.md index a4ca346..7507132 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/index.d.ts b/index.d.ts index 3e9d801..e3eeb55 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.17.32' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } diff --git a/package.json b/package.json index bb886ab..003ee35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.5.1", + "version": "3.6.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { diff --git a/src/options.js b/src/options.js index ac06ac7..776293b 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.17.10' +const CURRENT_VERSION = '1.17.30' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) From ac2e9852bef29f21a81d6a7856fb5a70d4b1808a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=B7=E6=B8=A1?= Date: Tue, 5 Oct 2021 07:20:12 +0800 Subject: [PATCH 227/458] fix `spawn` event (#139) --- docs/API.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/API.md b/docs/API.md index 35db115..5062fb6 100644 --- a/docs/API.md +++ b/docs/API.md @@ -104,7 +104,7 @@ const client = bedrock.createClient({ client.on('join', client => console.log('Player has joined!')) // The 'spawn' event is emitted. The chunks have been sent and all is well. -client.on('join', client => console.log('Player has spawned!')) +client.on('spawn', client => console.log('Player has spawned!')) // We can listen for text packets. See proto.yml for documentation. client.on('text', (packet) => { From adfa248e2d67eaf24690ba9cf39ab73429f147b2 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 8 Oct 2021 05:56:10 -0400 Subject: [PATCH 228/458] Default createClient to latest version, fix server motd version (#144) * Default createClient to latest version, fix server motd version * Update vanilla.js --- docs/API.md | 2 +- package.json | 2 +- src/createClient.js | 9 +++++---- src/server.js | 2 +- src/server/advertisement.js | 7 +++---- test/internal.js | 2 +- test/vanilla.js | 2 -- tools/genPacketDumps.js | 1 + 8 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/API.md b/docs/API.md index 5062fb6..3f9baa9 100644 --- a/docs/API.md +++ b/docs/API.md @@ -61,7 +61,7 @@ const server = bedrock.createServer({ port: 19132, // optional, port to bind to, default 19132 offline: false, // default false. verify connections with XBL motd: { - name: 'Funtime Server', // Top level message shown in server list + motd: 'Funtime Server', // Top level message shown in server list levelName: 'Wonderland' // Sub-level header } }) diff --git a/package.json b/package.json index 003ee35..c9b3b6a 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "debug": "^4.3.1", "jsonwebtoken": "^8.5.1", "jsp-raknet": "^2.1.3", - "minecraft-data": "^2.89.4", + "minecraft-data": "^2.95.0", "minecraft-folder-path": "^1.2.0", "prismarine-auth": "^1.1.0", "prismarine-nbt": "^1.5.0", diff --git a/src/createClient.js b/src/createClient.js index 4485acb..a7e9fd4 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -1,8 +1,9 @@ const { Client } = require('./client') const { RakClient } = require('./rak')(true) +const { Versions, CURRENT_VERSION } = require('./options') +const { sleep } = require('./datatypes/util') const assert = require('assert') const advertisement = require('./server/advertisement') -const { sleep } = require('./datatypes/util') /** @param {{ version?: number, host: string, port?: number, connectTimeout?: number, skipPing?: boolean }} options */ function createClient (options) { @@ -13,9 +14,9 @@ function createClient (options) { connect(client) } else { // Try to ping client.ping().then(data => { - const advert = advertisement.fromServerName(data) - console.log(`Connecting to server ${advert.motd} (${advert.name}), version ${advert.version}`) - client.options.version = options.version ?? advert.version + const ad = advertisement.fromServerName(data) + client.options.version = options.version ?? (Versions[ad.version] ? ad.version : CURRENT_VERSION) + console.log(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : undefined) connect(client) }, client) } diff --git a/src/server.js b/src/server.js index e13ca92..3a7684e 100644 --- a/src/server.js +++ b/src/server.js @@ -16,7 +16,7 @@ class Server extends EventEmitter { this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) - this.advertisement = new ServerAdvertisement(this.options.motd) + this.advertisement = new ServerAdvertisement(this.options.motd, this.options.version) this.advertisement.playersMax = options.maxPlayers ?? 3 /** @type {Object} */ this.clients = {} diff --git a/src/server/advertisement.js b/src/server/advertisement.js index 3a2fee8..3e069db 100644 --- a/src/server/advertisement.js +++ b/src/server/advertisement.js @@ -3,16 +3,15 @@ const { Versions, CURRENT_VERSION } = require('../options') class ServerAdvertisement { motd = 'Bedrock Protocol Server' levelName = 'bedrock-protocol' - protocol = Versions[CURRENT_VERSION] - version = CURRENT_VERSION playersOnline = 0 playersMax = 5 - gamemode = 'Creative' serverId = '0' - constructor (obj, version) { + constructor (obj, version = CURRENT_VERSION) { if (obj?.name) obj.motd = obj.name + this.protocol = Versions[version] + this.version = version Object.assign(this, obj) } diff --git a/test/internal.js b/test/internal.js index c03a498..de1c95f 100644 --- a/test/internal.js +++ b/test/internal.js @@ -205,5 +205,5 @@ async function timedTest (version, timeout = 1000 * 220) { console.info('✔ ok') } -if (!module.parent) timedTest() +// if (!module.parent) timedTest() module.exports = { startTest, timedTest, requestChunks } diff --git a/test/vanilla.js b/test/vanilla.js index 13c6069..5d20b89 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -3,7 +3,6 @@ const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') const { waitFor } = require('../src/datatypes/util') const { ChunkColumn, Version } = require('bedrock-provider') -const { CURRENT_VERSION } = require('../src/options') async function test (version) { // Start the server, wait for it to accept clients, throws on timeout @@ -67,5 +66,4 @@ async function test (version) { clearInterval(loop) } -if (!module.parent) test(CURRENT_VERSION) module.exports = { clientTest: test } diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index a0a676f..a6741ea 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -21,6 +21,7 @@ async function dump (version, force = true) { const random = ((Math.random() * 100) | 0) const port = 19130 + random + console.log('Starting dump server', version) const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port }) console.log('Started dump server', version) From 8569b9823fec36a0d8ccca628e47444c9b89e3c1 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 8 Oct 2021 16:13:34 -0400 Subject: [PATCH 229/458] Release 3.6.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c9b3b6a..278ca29 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.6.0", + "version": "3.6.1", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 75bf22d619f017a3b030440386ff01e482dc1a36 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 7 Nov 2021 06:47:45 -0500 Subject: [PATCH 230/458] 1.17.40 update (#150) * 1.17.40 * Update mcdata to 2.96.0 Co-authored-by: Romain Beaumont --- README.md | 2 +- index.d.ts | 2 +- package.json | 2 +- src/options.js | 2 +- test/internal.js | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7507132..a735626 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/index.d.ts b/index.d.ts index e3eeb55..7c2360e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.17.32' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } diff --git a/package.json b/package.json index 278ca29..90ab9e7 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "debug": "^4.3.1", "jsonwebtoken": "^8.5.1", "jsp-raknet": "^2.1.3", - "minecraft-data": "^2.95.0", + "minecraft-data": "^2.96.0", "minecraft-folder-path": "^1.2.0", "prismarine-auth": "^1.1.0", "prismarine-nbt": "^1.5.0", diff --git a/src/options.js b/src/options.js index 776293b..d34c302 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.17.30' +const CURRENT_VERSION = '1.17.40' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) diff --git a/test/internal.js b/test/internal.js index de1c95f..7617d28 100644 --- a/test/internal.js +++ b/test/internal.js @@ -198,7 +198,8 @@ async function requestChunks (x, z, radius) { async function timedTest (version, timeout = 1000 * 220) { await waitFor((res) => { - startTest(version, res) + // mocha eats up stack traces... + startTest(version, res).catch(console.error) }, timeout, () => { throw Error('timed out') }) From 389a68b98f26926d9f9a54886870fddb50ac90be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 Nov 2021 12:48:01 +0100 Subject: [PATCH 231/458] Bump prismarine-nbt from 1.6.0 to 2.0.0 (#148) Bumps [prismarine-nbt](https://github.com/prismarinejs/prismarine-nbt) from 1.6.0 to 2.0.0. - [Release notes](https://github.com/prismarinejs/prismarine-nbt/releases) - [Changelog](https://github.com/PrismarineJS/prismarine-nbt/blob/master/HISTORY.md) - [Commits](https://github.com/prismarinejs/prismarine-nbt/compare/1.6.0...2.0.0) --- updated-dependencies: - dependency-name: prismarine-nbt dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 90ab9e7..758fcb3 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "minecraft-data": "^2.96.0", "minecraft-folder-path": "^1.2.0", "prismarine-auth": "^1.1.0", - "prismarine-nbt": "^1.5.0", + "prismarine-nbt": "^2.0.0", "protodef": "^1.14.0", "uuid-1345": "^1.0.2" }, From 214c34c44b5f784d61f823831c1622d5a08a37d3 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sun, 7 Nov 2021 12:55:11 +0100 Subject: [PATCH 232/458] Release 3.7.0 --- HISTORY.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index d63898e..eaca46e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,6 @@ +## 3.7.0 +* 1.7.40 support + ## 3.6.0 * 1.17.30 support * minecraft-data used for protocol data diff --git a/package.json b/package.json index 758fcb3..0b5bd48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.6.1", + "version": "3.7.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 1b422ac4ceabdccc37e228c55b3ec2e5efc03c19 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 12 Nov 2021 16:14:15 -0500 Subject: [PATCH 233/458] Update prismarine-auth usage (#153) --- README.md | 4 +--- docs/API.md | 2 ++ examples/client/client.js | 4 +--- examples/createRelay.js | 3 +-- src/client/auth.js | 8 ++++++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a735626..4d4f50a 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,7 @@ const client = bedrock.createClient({ host: 'localhost', // optional port: 19132, // optional, default 19132 username: 'Notch', // the username you want to join as, optional if online mode - offline: true, // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. - // Optional for some servers which verify the title ID: - // authTitle: bedrock.title.MinecraftNintendoSwitch + offline: true // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. }) client.on('text', (packet) => { // Listen for chat messages and echo them back. diff --git a/docs/API.md b/docs/API.md index 3f9baa9..8aadf2e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -20,6 +20,8 @@ Returns a `Client` instance and connects to the server. | autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | | skipPing | *optional* | Whether pinging the server to check its version should be skipped. | | useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. | +| authTitle | *optional* | The client ID to sign in as, defaults to Minecraft for Nintendo Switch. Set false to sign in through Azure. See prismarine-auth | +| deviceType | *optional* | The device type to sign in as, defaults to "Nintendo". See prismarine-auth | ## be.createServer(options) : Server diff --git a/examples/client/client.js b/examples/client/client.js index 09a29b5..c10710a 100644 --- a/examples/client/client.js +++ b/examples/client/client.js @@ -4,9 +4,7 @@ const client = bedrock.createClient({ host: 'localhost', // optional port: 19132, // optional, default 19132 username: 'Notch', // the username you want to join as, optional if online mode - offline: false, // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. - // Optional for some servers which verify the title ID: - // authTitle: bedrock.title.MinecraftNintendoSwitch + offline: false // optional, default false. if true, do not login with Xbox Live. You will not be asked to sign-in if set to true. }) client.on('text', (packet) => { // Listen for chat messages and echo them back. diff --git a/examples/createRelay.js b/examples/createRelay.js index f99a0ee..8b910ef 100644 --- a/examples/createRelay.js +++ b/examples/createRelay.js @@ -1,4 +1,4 @@ -const { Relay, title } = require('bedrock-protocol') +const { Relay } = require('bedrock-protocol') function createRelay () { console.log('Creating relay') @@ -8,7 +8,6 @@ function createRelay () { host: '0.0.0.0', port: 19130, offline: false, - authTitle: title.MinecraftNintendoSwitch, /* Where to send upstream packets to */ destination: { host: '127.0.0.1', diff --git a/src/client/auth.js b/src/client/auth.js index 98c334d..62f2a2f 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -16,12 +16,16 @@ async function authenticate (client, options) { if (!options.profilesFolder) { options.profilesFolder = path.join(minecraftFolderPath, 'nmp-cache') } - if (!options.authTitle) { + if (options.authTitle === undefined) { options.authTitle = Titles.MinecraftNintendoSwitch + options.deviceType = 'Nintendo' } try { const Authflow = new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode) - const chains = await Authflow.getMinecraftBedrockToken(client.clientX509) + const chains = await Authflow.getMinecraftBedrockToken(client.clientX509).catch(e => { + if (options.password) console.warn('Sign in failed, try removing the password field') + throw e + }) debug('chains', chains) From b0856e0cc7d15fd51a72e0691689bab4987c0bce Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 28 Nov 2021 00:57:41 -0500 Subject: [PATCH 234/458] update docs and error handling (#155) --- docs/API.md | 11 +++++++++++ index.d.ts | 5 +++++ src/client.js | 9 +++++++++ src/handshake/keyExchange.js | 2 +- src/rakWorker.js | 2 +- src/server.js | 3 ++- src/serverPlayer.js | 3 +-- src/transforms/encryption.js | 6 ++++-- 8 files changed, 34 insertions(+), 7 deletions(-) diff --git a/docs/API.md b/docs/API.md index 8aadf2e..8900876 100644 --- a/docs/API.md +++ b/docs/API.md @@ -23,6 +23,14 @@ Returns a `Client` instance and connects to the server. | authTitle | *optional* | The client ID to sign in as, defaults to Minecraft for Nintendo Switch. Set false to sign in through Azure. See prismarine-auth | | deviceType | *optional* | The device type to sign in as, defaults to "Nintendo". See prismarine-auth | +The following events are emitted by the client: +* 'status' - When the client's login sequence status has changed +* 'join' - When the client has joined the server after authenticating +* 'spawn' - When the client has spawned into the game world, as it is getting chunks +* 'kick' - The server has kicked the client +* 'close' - The server has closed the connection +* 'error' - An recoverable exception has happened. Not catching will throw an exception + ## be.createServer(options) : Server Returns a `Server` instance and starts listening for clients. All clients will be @@ -88,6 +96,9 @@ Order of server client event emissions: * 'join' - the client is ready to recieve game packets after successful server-client handshake/encryption * 'spawn' - emitted after the client lets the server know that it has successfully spawned + +'error' event is emitted when a catchable exception happens with a client (for example receiving a bad encrypted packet). + ## Client docs You can create a server as such: diff --git a/index.d.ts b/index.d.ts index 7c2360e..a6c71a0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -92,6 +92,11 @@ declare module "bedrock-protocol" { * Close the connection, leave the server. */ close() + + /** + * Send a disconnect packet and close the connection + */ + disconnect() } /** diff --git a/src/client.js b/src/client.js index 3e4c9b6..5909667 100644 --- a/src/client.js +++ b/src/client.js @@ -141,6 +141,15 @@ class Client extends Connection { } } + disconnect (reason = 'Client leaving', hide = false) { + if (this.status === ClientStatus.Disconnected) return + this.write('disconnect', { + hide_disconnect_screen: hide, + message: reason + }) + this.close(reason) + } + close () { if (this.status !== ClientStatus.Disconnected) { this.emit('close') // Emit close once diff --git a/src/handshake/keyExchange.js b/src/handshake/keyExchange.js index a732dc8..8a90041 100644 --- a/src/handshake/keyExchange.js +++ b/src/handshake/keyExchange.js @@ -52,7 +52,7 @@ function KeyExchange (client, server, options) { debug('[encrypt] Starting serverbound encryption', token) const jwt = token?.token if (!jwt) { - throw Error('Server did not return a valid JWT, cannot start encryption!') + throw Error('Server did not return a valid JWT, cannot start encryption') } // No verification here, not needed diff --git a/src/rakWorker.js b/src/rakWorker.js index 06cd736..b67af0b 100644 --- a/src/rakWorker.js +++ b/src/rakWorker.js @@ -40,7 +40,7 @@ function main () { }) raknet.on('raw', (buffer, inetAddr) => { - console.log('Raw packet', buffer, inetAddr) + debug('Raw packet', buffer, inetAddr) }) } else if (evt.type === 'queueEncapsulated') { const sendPacket = new EncapsulatedPacket() diff --git a/src/server.js b/src/server.js index 3a7684e..3192889 100644 --- a/src/server.js +++ b/src/server.js @@ -54,7 +54,8 @@ class Server extends EventEmitter { onEncapsulated = (buffer, address) => { const client = this.clients[address] if (!client) { - throw new Error(`packet from unknown inet addr: ${address}`) + this.emit('error', new Error(`packet from unknown inet addr: ${address}`)) + return } client.handle(buffer) } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 52693b8..967a9f8 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -56,8 +56,7 @@ class Player extends Connection { try { var { key, userData, skinData } = this.decodeLoginJWT(authChain.chain, skinChain) // eslint-disable-line } catch (e) { - console.error(e) - console.debug(authChain.chain, skinChain) + debug(this.address, e) this.disconnect('Server authentication error') return } diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index c878c8d..31f9ae2 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -66,8 +66,10 @@ function createDecryptor (client, iv) { const computedCheckSum = computeCheckSum(packet, client.receiveCounter, client.secretKeyBytes) client.receiveCounter++ - if (Buffer.compare(checksum, computedCheckSum) !== 0) { - throw Error(`Checksum mismatch ${checksum.toString('hex')} != ${computedCheckSum.toString('hex')}`) + if (!checksum.equals(computedCheckSum)) { + client.emit('error', Error(`Checksum mismatch ${checksum.toString('hex')} != ${computedCheckSum.toString('hex')}`)) + client.disconnect('disconnectionScreen.badPacket') + return } Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buffer) => { From 1a1fa618e4b430a5bafe4288843018014dea3a90 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 4 Dec 2021 01:10:47 -0500 Subject: [PATCH 235/458] 1.18 update (#157) --- README.md | 2 +- src/options.js | 4 ++-- test/internal.js | 2 +- tools/startVanillaServer.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4d4f50a..4efd7ea 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/src/options.js b/src/options.js index d34c302..78b1eaa 100644 --- a/src/options.js +++ b/src/options.js @@ -3,9 +3,9 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.17.40' +const CURRENT_VERSION = '1.18.0' -const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) +const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version]).reverse()) const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 diff --git a/test/internal.js b/test/internal.js index 7617d28..7e61306 100644 --- a/test/internal.js +++ b/test/internal.js @@ -206,5 +206,5 @@ async function timedTest (version, timeout = 1000 * 220) { console.info('✔ ok') } -// if (!module.parent) timedTest() +// if (!module.parent) timedTest('1.17.40') module.exports = { startTest, timedTest, requestChunks } diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 157f458..e2ba4d9 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -12,7 +12,7 @@ const get = (url, out) => cp.execSync(`curl -o ${out} ${url}`) function fetchLatestStable () { get('https://raw.githubusercontent.com/minecraft-linux/mcpelauncher-versiondb/master/versions.json', 'versions.json') const versions = JSON.parse(fs.readFileSync('./versions.json')) - const latest = versions[versions.length - 1] + const latest = versions[0] return latest.version_name } From 572b83047c9d7d4c59ec42db73e41b57575a8282 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 4 Dec 2021 10:48:14 -0500 Subject: [PATCH 236/458] Release 3.8.0 --- HISTORY.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index eaca46e..bc4d371 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,8 @@ +## 3.8.0 +* 1.18.0 support + ## 3.7.0 -* 1.7.40 support +* 1.17.40 support ## 3.6.0 * 1.17.30 support diff --git a/package.json b/package.json index 0b5bd48..721e845 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.7.0", + "version": "3.8.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From e3e553bf91be463143b31d5e8835eb295baffca0 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 7 Dec 2021 23:23:53 -0500 Subject: [PATCH 237/458] index.d.ts: update version enum --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index a6c71a0..fe15ac4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } From bb2179a8cb9c193cd1496ede25b04042fce2bcaa Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 15 Dec 2021 23:55:32 -0500 Subject: [PATCH 238/458] Fix port collision caused by race condition in tests (#164) * Fix port collision caused by race condition in tests The ipv6 port is not randomized, if the previous ports for the last test didn't get freed in time, the server can crash on launch * try again * Update index.d.ts * Update genPacketDumps.js --- index.d.ts | 2 ++ tools/genPacketDumps.js | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index fe15ac4..5b0c8c2 100644 --- a/index.d.ts +++ b/index.d.ts @@ -24,6 +24,8 @@ declare module "bedrock-protocol" { } export interface ClientOptions extends Options { + // The username to connect to the server as + username: string, // The view distance in chunks viewDistance?: number, // Specifies which game edition to sign in as. Optional, but some servers verify this. diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index a6741ea..4176b65 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -18,11 +18,11 @@ function hasDumps (version) { let loop async function dump (version, force = true) { - const random = ((Math.random() * 100) | 0) - const port = 19130 + random + const random = (Math.random() * 1000) | 0 + const [port, v6] = [19132 + random, 19133 + random] console.log('Starting dump server', version) - const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port }) + const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port, 'server-portv6': v6 }) console.log('Started dump server', version) const client = new Client({ From 7acacc1a138381ee27abf3123bf1b9a7d10f8573 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 26 Dec 2021 09:53:49 -0500 Subject: [PATCH 239/458] Update docs (#165) * Update API.md * Update CONTRIBUTING.md --- CONTRIBUTING.md | 25 ++++++++++++++++++++----- docs/API.md | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 746f349..fd23544 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,31 @@ CONTRIBUTING.md -Contributions are always welcome :) +Contributions are always welcome :). If you have any questions, please discuss on the Discord or in a Discussion. ## Updating Good sources for the Minecraft bedrock protocol are [gophertunnel](https://github.com/Sandertv/gophertunnel/tree/master/minecraft/protocol/packet), [ClouburstMC's protocol library](https://github.com/CloudburstMC/Protocol) and [PocketMine](https://github.com/pmmp/PocketMine-MP/tree/stable/src/pocketmine/network/mcpe/protocol). +Protocol updates need to happen in two places: in minecraft-data to update the protocol schema (the actual data structures for the packets) and here in the protocol library side. If no changes to the underlying protocol are made aside from packet structure changes (add, remove, modify packets) then the only change needed in bedrock-protocol is to update the README documentation and some constants in `src/options.js` (update the CURRENT_VERSION). + Steps to update: -* Add the version to src/options.js -* Open [data/latest/proto.yml](https://github.com/PrismarineJS/bedrock-protocol/tree/new/data/latest) and add, remove or modify the updated packets (see the [Packet serialization](#Packet_serialization) notes at the bottom for info on syntax) -* Save and make sure to update the !version field at the top of the file -* Run `npm run build` and `npm test` to test +* Update the protocol data in minecraft-data : see the instructions [here](https://github.com/PrismarineJS/minecraft-data/blob/master/doc/bedrock.md). + * Find the relevant changes to the protocol for the current version + * Update the [.YML files](https://github.com/PrismarineJS/minecraft-data/tree/master/data/bedrock/latest) in minecraft-data accordingly (see the [Packet serialization](#Packet_serialization) notes at the bottom here for info on syntax) + * Then follow the steps to build the protocol .YML files into JSON + * Do a release of the minecraft-data package +* Add the version to `src/options.js` here +* Run `npm run build` and `npm test` to test that everything is OK + +### Development + +For development purposes, you can easily alter the protocol locally without a remote minecraft-data release : +* Run `npm install` on the root of this repo after git cloning +* Open `node_modules/minecraft-data/minecraft-data/data/bedrock/latest/` and update the .YML files as you need, following the schema at the bottom (make sure to update '!version' if you are changing version) +* Go back to the root of this repo and run `npm run build`. +* Then `npm test` ; the protocol changes should be automatically applied + +For example, [here](https://github.com/PrismarineJS/minecraft-data/pull/467/files) is a PR for the update to 1.17.30 in minecraft-data - [here](https://github.com/PrismarineJS/bedrock-protocol/pull/150/files) is an accompanying change for bedrock-protocol. ## Code structure diff --git a/docs/API.md b/docs/API.md index 8900876..677f12f 100644 --- a/docs/API.md +++ b/docs/API.md @@ -133,7 +133,7 @@ Order of client event emissions: ### Protocol docs -For documentation on the protocol, and packets/fields see the [proto.yml](data/latest/proto.yml) and [types.yml](data/latest/proto.yml) files. More information on syntax can be found in CONTRIBUTING.md. When sending a packet, you must fill out all of the required fields. +For documentation on the protocol, and packets/fields see the [the protocol doc](https://minecraft-data.prismarine.js.org/?v=bedrock_1.18.0&d=protocol) (the emitted event names are the Packet types in lower case without the "packet_" prefix). More information on syntax can be found in CONTRIBUTING.md. When sending a packet, you must fill out all of the required fields. ### Proxy docs From 49fd2b69ee5ad0087ba1211dab5942cc8aac2222 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 31 Dec 2021 15:16:18 +0000 Subject: [PATCH 240/458] client: make console connection logging optional --- docs/API.md | 3 ++- src/client.js | 11 ++++++++--- src/createClient.js | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/API.md b/docs/API.md index 677f12f..d6e23ed 100644 --- a/docs/API.md +++ b/docs/API.md @@ -13,12 +13,12 @@ Returns a `Client` instance and connects to the server. | version | *optional* | Version to connect as. If not specified, automatically match server version. | | offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth. | | username | Conditional | Required if `offline` set to true : Username to connect to server as. | -| authTitle | *optional* | The title ID to connect as, see the README for usage. | | connectTimeout | *optional* | default to **9000ms**. How long to wait in milliseconds while trying to connect to server. | | onMsaCode | *optional* | Callback called when signing in with a microsoft account with device code auth, `data` is an object documented [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code#device-authorization-response) | | profilesFolder | *optional* | Where to store cached authentication tokens. Defaults to .minecraft, or the node_modules folder if not found. | | autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | | skipPing | *optional* | Whether pinging the server to check its version should be skipped. | +| conLog | *optional* | Where to log connection information (server join, kick messages to). Defaults to console.log, set to `null` to not log anywhere. | | useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. | | authTitle | *optional* | The client ID to sign in as, defaults to Minecraft for Nintendo Switch. Set false to sign in through Azure. See prismarine-auth | | deviceType | *optional* | The device type to sign in as, defaults to "Nintendo". See prismarine-auth | @@ -48,6 +48,7 @@ authenticated unless offline is set to true. | kickTimeout | *[Future][1]* | How long to wait before kicking a unresponsive client. | | motd | *optional* | The "message of the day" for the server, the message shown to players in the server list. See usage below. | | advertisementFn | *optional* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | +| conLog | *optional* | Where to log connection information (server join, kick messages to). Default to log only in DEBUG mode. | ## be.ping({ host, port }) : ServerAdvertisement diff --git a/src/client.js b/src/client.js index 5909667..76e4bcb 100644 --- a/src/client.js +++ b/src/client.js @@ -41,6 +41,7 @@ class Client extends Connection { this.inLog = (...args) => debug('C ->', ...args) this.outLog = (...args) => debug('C <-', ...args) } + this.conLog = this.options.conLog === undefined ? console.log : this.options.conLog } connect () { @@ -82,7 +83,9 @@ class Client extends Connection { try { return await this.connection.ping(this.options.connectTimeout) } catch (e) { - console.warn(`Unable to connect to [${this.options.host}]/${this.options.port}. Is the server running?`) + // TODO: workaround bug in standardjs, waiting for https://github.com/standard/eslint-config-standard/pull/193 + const t = `Unable to connect to [${this.options.host}]/${this.options.port}. Is the server running?` + this.conLog?.(t) throw e } } @@ -126,7 +129,9 @@ class Client extends Connection { } onDisconnectRequest (packet) { - console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) + // TODO: workaround bug in standardjs, waiting for https://github.com/standard/eslint-config-standard/pull/193 + const t = `Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}` + this.conLog?.(t) this.emit('kick', packet) this.close() } @@ -172,7 +177,7 @@ class Client extends Connection { return } const pakData = { name: des.data.name, params: des.data.params } - this.inLog?.('-> C', pakData.name, this.options.loggging ? serialize(pakData.params) : '') + this.inLog?.('-> C', pakData.name, this.options.logging ? serialize(pakData.params) : '') this.emit('packet', des) if (debugging) { diff --git a/src/createClient.js b/src/createClient.js index a7e9fd4..59b6ceb 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -16,7 +16,7 @@ function createClient (options) { client.ping().then(data => { const ad = advertisement.fromServerName(data) client.options.version = options.version ?? (Versions[ad.version] ? ad.version : CURRENT_VERSION) - console.log(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : undefined) + if (client.conLog) client.conLog(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') connect(client) }, client) } From a1698d712fe7083e31ffd9e5f8ecc03dece50ddb Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 31 Dec 2021 15:18:46 +0000 Subject: [PATCH 241/458] relay: fix empty chunk loading issues, make chunk caching optional --- index.d.ts | 6 +++++- src/relay.js | 32 ++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/index.d.ts b/index.d.ts index 5b0c8c2..a14500d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } @@ -34,6 +34,8 @@ declare module "bedrock-protocol" { connectTimeout?: number // whether to skip initial ping and immediately connect skipPing?: boolean + // where to log connection information to (default to console.log) + conLog? } export interface ServerOptions extends Options { @@ -149,6 +151,8 @@ declare module "bedrock-protocol" { // Skip authentication connecting to the remote server? offline: false, } + // Whether to enable chunk caching (default: false) + enableChunkCaching?: boolean } export class Relay extends Server { diff --git a/src/relay.js b/src/relay.js index b78662f..6aac5a3 100644 --- a/src/relay.js +++ b/src/relay.js @@ -31,6 +31,7 @@ class RelayPlayer extends Player { this.outLog = this.downOutLog this.inLog = this.downInLog this.chunkSendCache = [] + this.sentStartGame = false this.respawnPacket = [] } @@ -52,8 +53,25 @@ class RelayPlayer extends Player { this.server.deserializer.verify(des, this.server.serializer) } - this.emit('clientbound', des.data) - this.queue(name, params) + this.emit('clientbound', des.data, des) + + if (!des.canceled) { + if (name === 'start_game') { + this.sentStartGame = true + } else if (name === 'level_chunk' && !this.sentStartGame) { + this.chunkSendCache.push(params) + return + } + + this.queue(name, params) + } + + if (this.chunkSendCache.length > 0 && this.sentStartGame) { + for (const entry of this.chunkSendCache) { + this.queue('level_chunk', entry) + } + this.chunkSendCache = [] + } } // Send queued packets to the connected client @@ -102,16 +120,17 @@ class RelayPlayer extends Player { this.server.deserializer.verify(des, this.server.serializer) } - this.emit('serverbound', des.data) + this.emit('serverbound', des.data, des) + if (des.canceled) return switch (des.data.name) { case 'client_cache_status': // Force the chunk cache off. - this.upstream.queue('client_cache_status', { enabled: false }) + this.upstream.queue('client_cache_status', { enabled: this.enableChunkCaching }) break case 'set_local_player_as_initialized': this.status = 3 - // falls through + // falls through default: // Emit the packet as-is back to the upstream server this.downInLog('Relaying', des.data) @@ -139,6 +158,7 @@ class Relay extends Server { this.forceSingle = true this.upstreams = new Map() this.conLog = debug + this.enableChunkCaching = options.enableChunkCaching } // Called after a new player joins our proxy. We first create a new Client to connect to @@ -167,7 +187,7 @@ class Relay extends Server { // Tell the server to disable chunk cache for this connection as a client. // Wait a bit for the server to ack and process, the continue with proxying // otherwise the player can get stuck in an empty world. - client.write('client_cache_status', { enabled: false }) + client.write('client_cache_status', { enabled: this.enableChunkCaching }) ds.upstream = client ds.flushUpQueue() this.conLog('Connected to upstream server') From abc14449293f0b519e0bd32f679cf2e116c3790b Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 31 Dec 2021 15:20:10 +0000 Subject: [PATCH 242/458] Add missing login field --- src/handshake/login.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/handshake/login.js b/src/handshake/login.js index 4fd0163..5035a3d 100644 --- a/src/handshake/login.js +++ b/src/handshake/login.js @@ -35,6 +35,7 @@ module.exports = (client, server, options) => { client.createClientUserChain = (privateKey) => { let payload = { ...skinData, + SkinGeometryDataEngineVersion: '', // 1.17.30 ClientRandomId: Date.now(), CurrentInputMode: 1, From 058c280b66c3361a333de964e275d4a604ee7575 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 31 Dec 2021 15:22:58 +0000 Subject: [PATCH 243/458] fix relay connection close issue --- src/relay.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/relay.js b/src/relay.js index 6aac5a3..53bd4f7 100644 --- a/src/relay.js +++ b/src/relay.js @@ -142,7 +142,7 @@ class RelayPlayer extends Player { } close (reason) { - this.upstream.close(reason) + this.upstream?.close(reason) super.close(reason) } } From eb5ebc665016b40dcb2ad24d4baee5eab04a406f Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 7 Jan 2022 18:36:38 -0500 Subject: [PATCH 244/458] Bump bedrock-provider in tests (#172) --- examples/client/clientInternal.js | 4 ++-- package.json | 2 +- test/internal.js | 29 +++++++++++++++-------------- test/vanilla.js | 5 +++-- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/examples/client/clientInternal.js b/examples/client/clientInternal.js index f30fe23..10da7f5 100644 --- a/examples/client/clientInternal.js +++ b/examples/client/clientInternal.js @@ -3,7 +3,7 @@ */ process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('bedrock-protocol') -const { ChunkColumn, Version } = require('bedrock-provider') +const ChunkColumn = require('bedrock-provider').chunk('bedrock_1.17.10') async function test () { const client = new Client({ @@ -33,7 +33,7 @@ async function test () { }) client.on('level_chunk', async packet => { - const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + const cc = new ChunkColumn(packet.x, packet.z) await cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count) const blocks = [] for (let x = 0; x < 16; x++) { diff --git a/package.json b/package.json index 721e845..f747300 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@babel/eslint-parser": "^7.13.10", "babel-eslint": "^10.1.0", "bedrock-protocol": "file:.", - "bedrock-provider": "^1.0.0", + "bedrock-provider": "^2.0.0", "leveldb-zlib": "^1.0.1", "mocha": "^9.1.2", "protodef-yaml": "^1.1.0", diff --git a/test/internal.js b/test/internal.js index 7e61306..63e492e 100644 --- a/test/internal.js +++ b/test/internal.js @@ -3,6 +3,7 @@ const { dumpPackets } = require('../tools/genPacketDumps') const { ping } = require('../src/createClient') const { CURRENT_VERSION } = require('../src/options') const { join } = require('path') +const { waitFor } = require('../src/datatypes/util') // First we need to dump some packets that a vanilla server would send a vanilla // client. Then we can replay those back in our custom server. @@ -31,7 +32,7 @@ async function startTest (version = CURRENT_VERSION, ok) { console.assert(pongData, 'did not get valid pong data from server') const respawnPacket = get('packets/respawn.json') - const chunks = await requestChunks(respawnPacket.x, respawnPacket.z, 1) + const chunks = await requestChunks(version, respawnPacket.x, respawnPacket.z, 1) let loop @@ -150,31 +151,31 @@ async function startTest (version = CURRENT_VERSION, ok) { client.connect() } -const { ChunkColumn, Version } = require('bedrock-provider') -const { waitFor } = require('../src/datatypes/util') -const mcData = require('minecraft-data')('1.16') +async function requestChunks (version, x, z, radius) { + const ChunkColumn = require('bedrock-provider').chunk('bedrock_1.17.10') + // const mcData = require('minecraft-data')('1.16') -async function requestChunks (x, z, radius) { const cxStart = (x >> 4) - radius const cxEnd = (x >> 4) + radius const czStart = (z >> 4) - radius const czEnd = (z >> 4) + radius - const stone = mcData.blocksByName.stone + // const stone = mcData.blocksByName.stone const chunks = [] for (let cx = cxStart; cx < cxEnd; cx++) { for (let cz = czStart; cz < czEnd; cz++) { console.log('reading chunk at ', cx, cz) - const cc = new ChunkColumn(Version.v1_2_0_bis, x, z) + const cc = new ChunkColumn(x, z) - for (let x = 0; x < 16; x++) { - for (let y = 0; y < 60; y++) { - for (let z = 0; z < 16; z++) { - cc.setBlock(x, y, z, stone) - } - } - } + // Temporarily disable until 1.18 PR in bedrock-provider goes through + // for (let x = 0; x < 16; x++) { + // for (let y = 0; y < 60; y++) { + // for (let z = 0; z < 16; z++) { + // cc.setBlock({ x, y, z }, stone) + // } + // } + // } if (!cc) { console.log('no chunk') diff --git a/test/vanilla.js b/test/vanilla.js index 5d20b89..41033cc 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -2,9 +2,10 @@ const vanillaServer = require('../tools/startVanillaServer') const { Client } = require('../src/client') const { waitFor } = require('../src/datatypes/util') -const { ChunkColumn, Version } = require('bedrock-provider') async function test (version) { + const ChunkColumn = require('bedrock-provider').chunk('bedrock_' + version) + // Start the server, wait for it to accept clients, throws on timeout const handle = await vanillaServer.startServerAndWait(version, 1000 * 220) console.log('Started server') @@ -45,7 +46,7 @@ async function test (version) { }, 200) client.on('level_chunk', async packet => { // Chunk read test - const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) + const cc = new ChunkColumn(packet.x, packet.z) await cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count) }) From 2aa3b9826a75d3309c41d3f94fa4f7652546047d Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 8 Jan 2022 13:40:22 -0500 Subject: [PATCH 245/458] Release 3.9.0 (#173) --- HISTORY.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index bc4d371..58c7b88 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,6 @@ +## 3.9.0 +* Proxy fixes, logging and doc updates [#169](https://github.com/PrismarineJS/bedrock-protocol/pull/169) + ## 3.8.0 * 1.18.0 support diff --git a/package.json b/package.json index f747300..c710c0a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.8.0", + "version": "3.9.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 14af5fe04fc93c1bec0e324dbed3a3b170452936 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 4 Feb 2022 20:30:21 -0500 Subject: [PATCH 246/458] Switch to sync zlib with 512k chunks, adjustable compression level (#174) * Switch to sync zlib with 512k chunks, adjustable compression level * update serverPlayer --- docs/API.md | 6 +++-- index.d.ts | 4 ++++ src/client.js | 8 ++++++- src/connection.js | 45 +++++++++++++++++++----------------- src/createClient.js | 9 +++++--- src/server.js | 1 + src/serverPlayer.js | 1 + src/transforms/encryption.js | 16 +++++-------- src/transforms/framer.js | 30 +++++++++++------------- 9 files changed, 66 insertions(+), 54 deletions(-) diff --git a/docs/API.md b/docs/API.md index d6e23ed..6401d3b 100644 --- a/docs/API.md +++ b/docs/API.md @@ -20,8 +20,8 @@ Returns a `Client` instance and connects to the server. | skipPing | *optional* | Whether pinging the server to check its version should be skipped. | | conLog | *optional* | Where to log connection information (server join, kick messages to). Defaults to console.log, set to `null` to not log anywhere. | | useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. | -| authTitle | *optional* | The client ID to sign in as, defaults to Minecraft for Nintendo Switch. Set false to sign in through Azure. See prismarine-auth | -| deviceType | *optional* | The device type to sign in as, defaults to "Nintendo". See prismarine-auth | +| compressionLevel | *optional* | What zlib compression level to use, default to **7** | +| batchingInterval | *optional* | How frequently, in milliseconds to flush and write the packet queue (default: 20ms) | The following events are emitted by the client: * 'status' - When the client's login sequence status has changed @@ -30,6 +30,8 @@ The following events are emitted by the client: * 'kick' - The server has kicked the client * 'close' - The server has closed the connection * 'error' - An recoverable exception has happened. Not catching will throw an exception +* 'connect_allowed' - Emitted after the client has pinged the server and gets version information. +* 'heartbeat' - Emitted after two successful tick_sync (keepalive) packets have been sent bidirectionally ## be.createServer(options) : Server diff --git a/index.d.ts b/index.d.ts index a14500d..6e9964f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -21,6 +21,10 @@ declare module "bedrock-protocol" { useNativeRaknet?: boolean, // If using JS implementation of RakNet, should we use workers? (This only affects the client) useRaknetWorker?: boolean + // Compression level for zlib, default to 7 + compressionLevel?: number + // How frequently the packet queue should be flushed in milliseconds, defaults to 20ms + batchingInterval?: number } export interface ClientOptions extends Options { diff --git a/src/client.js b/src/client.js index 76e4bcb..f403463 100644 --- a/src/client.js +++ b/src/client.js @@ -68,6 +68,7 @@ class Client extends Connection { if (this.options.protocolVersion < Options.MIN_VERSION) { throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) } + this.compressionLevel = this.options.compressionLevel || 7 } get entityId () { @@ -140,7 +141,12 @@ class Client extends Connection { if (this.status === ClientStatus.Initializing && this.options.autoInitPlayer === true) { if (statusPacket.status === 'player_spawn') { this.status = ClientStatus.Initialized - this.write('set_local_player_as_initialized', { runtime_entity_id: this.entityId }) + if (!this.entityId) { + // We need to wait for start_game in the rare event we get a player_spawn before start_game race condition + this.on('start_game', () => this.write('set_local_player_as_initialized', { runtime_entity_id: this.entityId })) + } else { + this.write('set_local_player_as_initialized', { runtime_entity_id: this.entityId }) + } this.emit('spawn') } } diff --git a/src/connection.js b/src/connection.js index ce15507..ddd60b1 100644 --- a/src/connection.js +++ b/src/connection.js @@ -60,7 +60,7 @@ class Connection extends EventEmitter { write (name, params) { this.outLog?.(name, params) if (name === 'start_game') this.updateItemPalette(params.itemstates) - const batch = new Framer() + const batch = new Framer(this.compressionLevel) const packet = this.serializer.createPacketBuffer({ name, params }) batch.addEncodedPacket(packet) @@ -84,21 +84,25 @@ class Connection extends EventEmitter { this.sendIds.push(name) } + _tick () { + if (this.sendQ.length) { + const batch = new Framer(this.compressionLevel) + batch.addEncodedPackets(this.sendQ) + this.sendQ = [] + this.sendIds = [] + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + } + + onTick = this._tick.bind(this) + startQueue () { this.sendQ = [] - this.loop = setInterval(() => { - if (this.sendQ.length) { - const batch = new Framer() - batch.addEncodedPackets(this.sendQ) - this.sendQ = [] - this.sendIds = [] - if (this.encryptionEnabled) { - this.sendEncryptedBatch(batch) - } else { - this.sendDecryptedBatch(batch) - } - } - }, 20) + this.loop = setInterval(this.onTick, this.options.batchingInterval || 20) } /** @@ -106,7 +110,7 @@ class Connection extends EventEmitter { */ sendBuffer (buffer, immediate = false) { if (immediate) { - const batch = new Framer() + const batch = new Framer(this.compressionLevel) batch.addEncodedPacket(buffer) if (this.encryptionEnabled) { this.sendEncryptedBatch(batch) @@ -121,7 +125,7 @@ class Connection extends EventEmitter { sendDecryptedBatch (batch) { // send to raknet - batch.encode(buf => this.sendMCPE(buf, true)) + this.sendMCPE(batch.encode(), true) } sendEncryptedBatch (batch) { @@ -158,11 +162,10 @@ class Connection extends EventEmitter { if (this.encryptionEnabled) { this.decrypt(buffer.slice(1)) } else { - Framer.decode(buffer, packets => { - for (const packet of packets) { - this.readPacket(packet) - } - }) + const packets = Framer.decode(buffer) + for (const packet of packets) { + this.readPacket(packet) + } } } } diff --git a/src/createClient.js b/src/createClient.js index 59b6ceb..7aff088 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -17,6 +17,7 @@ function createClient (options) { const ad = advertisement.fromServerName(data) client.options.version = options.version ?? (Versions[ad.version] ? ad.version : CURRENT_VERSION) if (client.conLog) client.conLog(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') + client.emit('connect_allowed') connect(client) }, client) } @@ -46,15 +47,17 @@ function connect (client) { sleep(500).then(() => client.queue('request_chunk_radius', { chunk_radius: client.viewDistance || 10 })) }) - const KEEPALIVE_INTERVAL = 10 // Send tick sync packets every 10 ticks + // Send tick sync packets every 10 ticks + const keepAliveInterval = 10 + const keepAliveIntervalBig = BigInt(keepAliveInterval) let keepalive client.tick = 0n client.once('spawn', () => { keepalive = setInterval(() => { // Client fills out the request_time and the server does response_time in its reply. client.queue('tick_sync', { request_time: client.tick, response_time: 0n }) - client.tick += BigInt(KEEPALIVE_INTERVAL) - }, 50 * KEEPALIVE_INTERVAL) + client.tick += keepAliveIntervalBig + }, 50 * keepAliveInterval) client.on('tick_sync', async packet => { client.emit('heartbeat', packet.response_time) diff --git a/src/server.js b/src/server.js index 3192889..8a2d723 100644 --- a/src/server.js +++ b/src/server.js @@ -33,6 +33,7 @@ class Server extends EventEmitter { if (this.options.protocolVersion < Options.MIN_VERSION) { throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) } + this.compressionLevel = this.options.compressionLevel || 7 } onOpenConnection = (conn) => { diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 967a9f8..906f3f2 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -15,6 +15,7 @@ class Player extends Connection { this.deserializer = server.deserializer this.connection = connection this.options = server.options + this.compressionLevel = server.compressionLevel KeyExchange(this, server, server.options) Login(this, server, server.options) diff --git a/src/transforms/encryption.js b/src/transforms/encryption.js index 31f9ae2..b02351b 100644 --- a/src/transforms/encryption.js +++ b/src/transforms/encryption.js @@ -36,12 +36,10 @@ function createEncryptor (client, iv) { // The send counter is represented as a little-endian 64-bit long and incremented after each packet. function process (chunk) { - Zlib.deflateRaw(chunk, { level: 7 }, (err, buffer) => { - if (err) throw err - const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) - client.sendCounter++ - client.cipher.write(packet) - }) + const buffer = Zlib.deflateRawSync(chunk, { level: client.compressionLevel }) + const packet = Buffer.concat([buffer, computeCheckSum(buffer, client.sendCounter, client.secretKeyBytes)]) + client.sendCounter++ + client.cipher.write(packet) } client.cipher.on('data', client.onEncryptedPacket) @@ -72,10 +70,8 @@ function createDecryptor (client, iv) { return } - Zlib.inflateRaw(chunk, { chunkSize: 1024 * 1024 * 2 }, (err, buffer) => { - if (err) throw err - client.onDecryptedPacket(buffer) - }) + const buffer = Zlib.inflateRawSync(chunk, { chunkSize: 512000 }) + client.onDecryptedPacket(buffer) } client.decipher.on('data', verify) diff --git a/src/transforms/framer.js b/src/transforms/framer.js index 77f41e9..c31b8d8 100644 --- a/src/transforms/framer.js +++ b/src/transforms/framer.js @@ -3,34 +3,30 @@ const zlib = require('zlib') // Concatenates packets into one batch packet, and adds length prefixs. class Framer { - constructor () { + constructor (compressionLevel) { // Encoding this.packets = [] - this.compressionLevel = 7 + this.compressionLevel = compressionLevel } - static decode (buf, cb) { + static decode (buf) { // Read header if (buf[0] !== 0xfe) throw Error('bad batch packet header ' + buf[0]) const buffer = buf.slice(1) - // Decode the payload - zlib.inflateRaw(buffer, { chunkSize: 1024 * 1024 * 2 }, (err, inflated) => { - if (err) { // Try to decode without compression - Framer.getPackets(buffer) - return - } - cb(Framer.getPackets(inflated)) - }) + // Decode the payload with 512kb buffer + try { + const inflated = zlib.inflateRawSync(buffer, { chunkSize: 512000 }) + return Framer.getPackets(inflated) + } catch (e) { // Try to decode without compression + return Framer.getPackets(buffer) + } } - encode (cb) { + encode () { const buf = Buffer.concat(this.packets) - zlib.deflateRaw(buf, { level: this.compressionLevel }, (err, def) => { - if (err) throw err - const ret = Buffer.concat([Buffer.from([0xfe]), def]) - cb(ret) - }) + const def = zlib.deflateRawSync(buf, { level: this.compressionLevel }) + return Buffer.concat([Buffer.from([0xfe]), def]) } addEncodedPacket (chunk) { From 957c83995ab93730ca021e9cb0886a0a60986bd6 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 9 Feb 2022 12:15:35 -0500 Subject: [PATCH 247/458] 1.18.11 (#179) * Fix js raknet client disconnection * 1.18.11 --- index.d.ts | 2 +- src/client.js | 2 +- src/options.js | 2 +- src/rak.js | 19 +++++++++++++++---- src/rakWorker.js | 9 ++++++--- src/server.js | 1 + test/internal.js | 2 +- 7 files changed, 26 insertions(+), 11 deletions(-) diff --git a/index.d.ts b/index.d.ts index 6e9964f..5b79a6f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } diff --git a/src/client.js b/src/client.js index f403463..c41aa33 100644 --- a/src/client.js +++ b/src/client.js @@ -94,7 +94,7 @@ class Client extends Connection { _connect = async (sessionData) => { debug('[client] connecting to', this.options.host, this.options.port, sessionData, this.connection) this.connection.onConnected = () => this.sendLogin() - this.connection.onCloseConnection = () => this.close() + this.connection.onCloseConnection = (reason) => this.close() this.connection.onEncapsulated = this.onEncapsulated this.connection.connect() diff --git a/src/options.js b/src/options.js index 78b1eaa..7949f85 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.18.0' +const CURRENT_VERSION = '1.18.11' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version]).reverse()) diff --git a/src/rak.js b/src/rak.js index 32a3b31..182ef09 100644 --- a/src/rak.js +++ b/src/rak.js @@ -86,6 +86,7 @@ class RakNativeServer extends EventEmitter { protocolVersion: 10, message: server.getAdvertisement().toBuffer() }) + this.onClose = () => {} this.updateAdvertisement = () => { this.raknet.setOfflineMessage(server.getAdvertisement().toBuffer()) @@ -106,6 +107,8 @@ class RakNativeServer extends EventEmitter { this.raknet.on('encapsulated', ({ buffer, address }) => { this.onEncapsulated(buffer, address) }) + + this.raknet.on('close', (reason) => this.onClose(reason)) } listen () { @@ -122,6 +125,7 @@ class RakJsClient extends EventEmitter { super() this.options = options this.onConnected = () => { } + this.onCloseConnection = () => { } this.onEncapsulated = () => { } if (options.useWorkers) { this.connect = this.workerConnect @@ -151,6 +155,10 @@ class RakJsClient extends EventEmitter { } case 'pong': this.pongCb?.(evt.args) + break + case 'disconnect': + this.onCloseConnection() + break } }) } @@ -164,7 +172,8 @@ class RakJsClient extends EventEmitter { }) this.raknet.on('connected', this.onConnected) - this.raknet.on('encapsulated', (encapsulated, addr) => this.onEncapsulated(encapsulated.buffer, addr.hash)) + this.raknet.on('encapsulated', (encapsulated, addr) => this.onEncapsulated(encapsulated, addr.hash)) + this.raknet.on('disconnect', (reason) => this.onCloseConnection(reason)) } workerSendReliable (buffer, immediate) { @@ -175,8 +184,8 @@ class RakJsClient extends EventEmitter { const sendPacket = new EncapsulatedPacket() sendPacket.reliability = Reliability.ReliableOrdered sendPacket.buffer = buffer - this.connection.addEncapsulatedToQueue(sendPacket) - if (immediate) this.connection.sendQueue() + this.raknet.connection.addEncapsulatedToQueue(sendPacket) + if (immediate) this.raknet.connection.sendQueue() } async ping (timeout = 1000) { @@ -205,8 +214,9 @@ class RakJsServer extends EventEmitter { this.onOpenConnection = () => { } this.onCloseConnection = () => { } this.onEncapsulated = (packet, address) => server.onEncapsulated(packet.buffer, address) + this.onClose = () => {} this.updateAdvertisement = () => { - // TODO + this.raknet.setPongAdvertisement(server.getAdvertisement()) } if (options.useWorkers) { throw Error('nyi') @@ -229,6 +239,7 @@ class RakJsServer extends EventEmitter { }) this.raknet.on('closeConnection', this.onCloseConnection) this.raknet.on('encapsulated', this.onEncapsulated) + this.raknet.on('close', this.onClose) } close () { diff --git a/src/rakWorker.js b/src/rakWorker.js index b67af0b..9717e62 100644 --- a/src/rakWorker.js +++ b/src/rakWorker.js @@ -34,9 +34,12 @@ function main () { }) raknet.on('encapsulated', (...args) => { - setTimeout(() => { - parentPort.postMessage({ type: 'encapsulated', args }) - }, 100) + parentPort.postMessage({ type: 'encapsulated', args }) + }) + + raknet.on('disconnect', (reason) => { + debug('[worker] disconnected!') + parentPort.postMessage({ type: 'disconnect', reason }) }) raknet.on('raw', (buffer, inetAddr) => { diff --git a/src/server.js b/src/server.js index 8a2d723..7329b63 100644 --- a/src/server.js +++ b/src/server.js @@ -81,6 +81,7 @@ class Server extends EventEmitter { this.raknet.onOpenConnection = this.onOpenConnection this.raknet.onCloseConnection = this.onCloseConnection this.raknet.onEncapsulated = this.onEncapsulated + this.raknet.onClose = (reason) => this.close(reason || 'Raknet closed') this.serverTimer = setInterval(() => { this.raknet.updateAdvertisement() diff --git a/test/internal.js b/test/internal.js index 63e492e..50335fd 100644 --- a/test/internal.js +++ b/test/internal.js @@ -207,5 +207,5 @@ async function timedTest (version, timeout = 1000 * 220) { console.info('✔ ok') } -// if (!module.parent) timedTest('1.17.40') +// if (!module.parent) timedTest('1.18.11') module.exports = { startTest, timedTest, requestChunks } From 330c819e7f8b883ad33a2122cbda959d172691fa Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 9 Feb 2022 13:07:50 -0500 Subject: [PATCH 248/458] Release 3.10.0 (#180) * Update HISTORY.md * Update package.json * Update README.md --- HISTORY.md | 4 ++++ README.md | 2 +- package.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 58c7b88..6d2017f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## 3.10.0 +* Support 1.18.11 (#179) @extremeheat +* Switch to sync zlib with 512k chunks, adjustable compression level (#174) @extremeheat + ## 3.9.0 * Proxy fixes, logging and doc updates [#169](https://github.com/PrismarineJS/bedrock-protocol/pull/169) diff --git a/README.md b/README.md index 4efd7ea..c4c67f2 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/package.json b/package.json index c710c0a..5ec29b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.9.0", + "version": "3.10.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 817fd918ce4c5cd3aa0185961b0107147b89f81e Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 21 Feb 2022 04:35:24 -0500 Subject: [PATCH 249/458] Ignore unconnected packets, remove babel (#185) * Ignore unconnected packets, remove babel * re-enable proxy test on ubuntu runner --- .eslintignore | 1 - .gitignore | 2 -- .npmignore | 1 - babel.config.js | 3 --- examples/viewer/client/ProxyProvider.js | 2 +- examples/viewer/client/movements.js | 7 +++---- examples/viewer/index.js | 2 +- index.d.ts | 2 +- package.json | 7 +------ src/client.js | 11 +++-------- src/relay.js | 13 +++++++++---- src/server.js | 3 ++- src/transforms/serializer.js | 9 +++++---- test/internal.test.js | 19 +++++++------------ 14 files changed, 33 insertions(+), 49 deletions(-) delete mode 100644 .eslintignore delete mode 100644 babel.config.js diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 61743e4..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -examples/viewer \ No newline at end of file diff --git a/.gitignore b/.gitignore index 72abbbc..bc2d2f9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,7 @@ node_modules/ npm-debug.log package-lock.json __* -src/**/*.json # Runtime generated data data/ tools/bds* -tools/*/* *.txt \ No newline at end of file diff --git a/.npmignore b/.npmignore index 1dab2b5..da98b5e 100644 --- a/.npmignore +++ b/.npmignore @@ -1,7 +1,6 @@ node_modules/ npm-debug.log __* -src/**/*.json # Runtime generated data data/ tools/bds* diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 7db9b6f..0000000 --- a/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: ['@babel/preset-env'] -} diff --git a/examples/viewer/client/ProxyProvider.js b/examples/viewer/client/ProxyProvider.js index 29f74c7..8ffc599 100644 --- a/examples/viewer/client/ProxyProvider.js +++ b/examples/viewer/client/ProxyProvider.js @@ -44,7 +44,7 @@ class ProxyProvider extends BotProvider { this.movements.pushCameraControl(params, 1) // Log Movement deltas - { + { // eslint-disable-line this.lastMovePacket = params if (this.firstPlayerMovePacket) { const id = diff(this.firstPlayerMovePacket.input_data, params.input_data) diff --git a/examples/viewer/client/movements.js b/examples/viewer/client/movements.js index d359bea..92b6630 100644 --- a/examples/viewer/client/movements.js +++ b/examples/viewer/client/movements.js @@ -187,11 +187,11 @@ class MovementManager { }, PHYSICS_INTERVAL_MS) } - get sprinting() { + get sprinting () { return this.player.sprinting } - set sprinting(val) { + set sprinting (val) { this.player.events.startSprint = val this.player.events.stopSprint = !val if (val && !this.player.sprinting) { @@ -219,7 +219,7 @@ class MovementManager { const isAxis = AXES.includes(control) let hasOtherAxisKeyDown = false for (const c of AXES) { - if (this.controls[c] && c != control) { + if (this.controls[c] && c !== control) { hasOtherAxisKeyDown = true } } @@ -278,7 +278,6 @@ class MovementManager { globalThis.debugYaw = [yaw, yawRad] } - // Called when a proxy player sends a PlayerInputPacket. We need to apply these inputs tick-by-tick // as these packets are sent by the client every tick. pushCameraControl (state, id = 1) { diff --git a/examples/viewer/index.js b/examples/viewer/index.js index 954d4b6..2147fd5 100644 --- a/examples/viewer/index.js +++ b/examples/viewer/index.js @@ -1,7 +1,7 @@ const path = require('path') const { app, BrowserWindow, globalShortcut } = require('electron') -function createMainWindow() { +function createMainWindow () { const window = new BrowserWindow({ webPreferences: { nodeIntegration: true, diff --git a/index.d.ts b/index.d.ts index 5b79a6f..b02d208 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,7 +1,7 @@ import EventEmitter from "events" declare module "bedrock-protocol" { - type Version = '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } diff --git a/package.json b/package.json index 5ec29b4..4f13295 100644 --- a/package.json +++ b/package.json @@ -34,17 +34,12 @@ "raknet-native": "^1.0.3" }, "devDependencies": { - "@babel/eslint-parser": "^7.13.10", - "babel-eslint": "^10.1.0", "bedrock-protocol": "file:.", "bedrock-provider": "^2.0.0", "leveldb-zlib": "^1.0.1", "mocha": "^9.1.2", "protodef-yaml": "^1.1.0", - "standard": "^16.0.3" - }, - "standard": { - "parser": "babel-eslint" + "standard": "^17.0.0-2" }, "repository": { "type": "git", diff --git a/src/client.js b/src/client.js index c41aa33..219dcec 100644 --- a/src/client.js +++ b/src/client.js @@ -84,9 +84,7 @@ class Client extends Connection { try { return await this.connection.ping(this.options.connectTimeout) } catch (e) { - // TODO: workaround bug in standardjs, waiting for https://github.com/standard/eslint-config-standard/pull/193 - const t = `Unable to connect to [${this.options.host}]/${this.options.port}. Is the server running?` - this.conLog?.(t) + this.conLog?.(`Unable to connect to [${this.options.host}]/${this.options.port}. Is the server running?`) throw e } } @@ -130,9 +128,7 @@ class Client extends Connection { } onDisconnectRequest (packet) { - // TODO: workaround bug in standardjs, waiting for https://github.com/standard/eslint-config-standard/pull/193 - const t = `Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}` - this.conLog?.(t) + this.conLog?.(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`) this.emit('kick', packet) this.close() } @@ -221,8 +217,7 @@ class Client extends Connection { break default: if (this.status !== ClientStatus.Initializing && this.status !== ClientStatus.Initialized) { - // TODO: standardjs bug happens here with ?.(`something ${des.data.name}`) - if (this.inLog) this.inLog(`Can't accept ${des.data.name}, client not yet authenticated : ${this.status}`) + this.inLog?.(`Can't accept ${des.data.name}, client not yet authenticated : ${this.status}`) return } } diff --git a/src/relay.js b/src/relay.js index 53bd4f7..de88107 100644 --- a/src/relay.js +++ b/src/relay.js @@ -57,7 +57,9 @@ class RelayPlayer extends Player { if (!des.canceled) { if (name === 'start_game') { - this.sentStartGame = true + setTimeout(() => { + this.sentStartGame = true + }, 500) } else if (name === 'level_chunk' && !this.sentStartGame) { this.chunkSendCache.push(params) return @@ -104,7 +106,8 @@ class RelayPlayer extends Player { if (this.startRelaying) { // Upstream is still connecting/handshaking if (!this.upstream) { - this.downInLog('Got downstream connected packet but upstream is not connected yet, added to q', this.upQ.length) + const des = this.server.deserializer.parsePacketBuffer(packet) + this.downInLog('Got downstream connected packet but upstream is not connected yet, added to q', des) this.upQ.push(packet) // Put into a queue return } @@ -178,8 +181,10 @@ class Relay extends Server { autoInitPlayer: false }) // Set the login payload unless `noLoginForward` option - if (!client.noLoginForward) client.skinData = ds.skinData - client.connect() + if (!client.noLoginForward) client.options.skinData = ds.skinData + client.ping().then(pongData => { + client.connect() + }) this.conLog('Connecting to', this.options.destination.host, this.options.destination.port) client.outLog = ds.upOutLog client.inLog = ds.upInLog diff --git a/src/server.js b/src/server.js index 7329b63..50f3ddf 100644 --- a/src/server.js +++ b/src/server.js @@ -55,7 +55,8 @@ class Server extends EventEmitter { onEncapsulated = (buffer, address) => { const client = this.clients[address] if (!client) { - this.emit('error', new Error(`packet from unknown inet addr: ${address}`)) + // Ignore packets from clients that are not connected. + debug(`ignoring packet from unknown inet addr: ${address}`) return } client.handle(buffer) diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 7311698..c763599 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -17,10 +17,11 @@ class Parser extends FullPacketParser { const oldBuffer = deserialized.fullBuffer const newBuffer = serializer.createPacketBuffer({ name, params }) if (!newBuffer.equals(oldBuffer)) { - console.warn('New', newBuffer.toString('hex')) - console.warn('Old', oldBuffer.toString('hex')) - console.log('Failed to re-encode', name, params) - process.exit(1) + const fs = require('fs') + fs.writeFileSync('new.bin', newBuffer) + fs.writeFileSync('old.bin', oldBuffer) + fs.writeFileSync('failed.json', JSON.stringify(params, (k, v) => typeof v === 'bigint' ? v.toString() : v, 2)) + console.warn('Failed to re-encode', name) } } } diff --git a/test/internal.test.js b/test/internal.test.js index 6e81c43..d6c11d8 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -17,17 +17,12 @@ describe('internal client/server test', function () { }) } - if (process.env.CI && process.platform === 'linux') { - // Don't run the test, see : - // https://github.com/PrismarineJS/bedrock-protocol/issues/124 - } else { - for (const version in Versions) { - it('proxies ' + version, async () => { - console.debug(version) - await proxyTest(version) - await sleep(5000) - console.debug('Done', version) - }) - } + for (const version in Versions) { + it('proxies ' + version, async () => { + console.debug(version) + await proxyTest(version) + await sleep(5000) + console.debug('Done', version) + }) } }) From 550b1a19b4214dad77bcbf71029a371fd6ccdf43 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 20 Mar 2022 17:51:17 -0400 Subject: [PATCH 250/458] Mark raknet-native as required dependency (#188) JS raknet implementation needs some fixes, don't allow silent fail of this dep --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4f13295..12c09c9 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,10 @@ "prismarine-auth": "^1.1.0", "prismarine-nbt": "^2.0.0", "protodef": "^1.14.0", - "uuid-1345": "^1.0.2" + "uuid-1345": "^1.0.2", + "raknet-native": "^1.0.3" }, "optionalDependencies": { - "raknet-native": "^1.0.3" }, "devDependencies": { "bedrock-protocol": "file:.", From 92785a1167bc641690e27864c6091a1a93ea852a Mon Sep 17 00:00:00 2001 From: circuit10 Date: Fri, 25 Mar 2022 16:21:47 +0000 Subject: [PATCH 251/458] Pass relay onMsaCode to client (#190) --- src/relay.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/relay.js b/src/relay.js index de88107..e77256f 100644 --- a/src/relay.js +++ b/src/relay.js @@ -178,6 +178,7 @@ class Relay extends Server { version: this.options.version, host: this.options.destination.host, port: this.options.destination.port, + onMsaCode: this.options.onMsaCode, autoInitPlayer: false }) // Set the login payload unless `noLoginForward` option From 72c07bb7a01a8bca4b71f1d1c9b90186d3d0748f Mon Sep 17 00:00:00 2001 From: circuit10 Date: Sat, 26 Mar 2022 02:25:55 +0000 Subject: [PATCH 252/458] Emit error from relay when server can't be pinged (#191) --- src/relay.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/relay.js b/src/relay.js index e77256f..080c67c 100644 --- a/src/relay.js +++ b/src/relay.js @@ -185,6 +185,8 @@ class Relay extends Server { if (!client.noLoginForward) client.options.skinData = ds.skinData client.ping().then(pongData => { client.connect() + }).catch(err => { + this.emit('error', err) }) this.conLog('Connecting to', this.options.destination.host, this.options.destination.port) client.outLog = ds.upOutLog From 0dc586db9ce4716f1975003ccb8b365daabdc146 Mon Sep 17 00:00:00 2001 From: CreeperG16 <86970314+CreeperG16@users.noreply.github.com> Date: Sat, 26 Mar 2022 19:31:54 +0100 Subject: [PATCH 253/458] Add profilesFolder to Relay (#192) --- src/relay.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/relay.js b/src/relay.js index 080c67c..086b0be 100644 --- a/src/relay.js +++ b/src/relay.js @@ -165,7 +165,7 @@ class Relay extends Server { } // Called after a new player joins our proxy. We first create a new Client to connect to - // the remote server. Then we listen to soem events and proxy them over. The queue and + // the remote server. Then we listen to some events and proxy them over. The queue and // flushing logic is more of an accessory to make sure the server or client recieves // a packet, no matter what state it's in. For example, if the client wants to send a // packet to the server but it's not connected, it will add to the queue and send as soon @@ -179,6 +179,7 @@ class Relay extends Server { host: this.options.destination.host, port: this.options.destination.port, onMsaCode: this.options.onMsaCode, + profilesFolder: this.options.profilesFolder, autoInitPlayer: false }) // Set the login payload unless `noLoginForward` option From dfff13867dfaead208fe77b729b20ea7164d4743 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sun, 27 Mar 2022 16:15:20 -0400 Subject: [PATCH 254/458] Refactor client connection sequence (#189) * Refactor client connection sequence Allow connection info to come in after Client construction, emit "connect_allowed" similar to nmp * Fix breaking ping behavior change * fix createClient connect callback * correct behavior * remove comments * refactor impl * fix incorrect use of `this` --- src/client.js | 38 +++++++++++++++++++++++--------------- src/client/auth.js | 30 ++++++++++++++++++++---------- src/createClient.js | 33 +++++++++++++++++++++------------ 3 files changed, 64 insertions(+), 37 deletions(-) diff --git a/src/client.js b/src/client.js index 219dcec..85f48df 100644 --- a/src/client.js +++ b/src/client.js @@ -4,7 +4,7 @@ const { serialize, isDebug } = require('./datatypes/util') const debug = require('debug')('minecraft-protocol') const Options = require('./options') const auth = require('./client/auth') - +const initRaknet = require('./rak') const { KeyExchange } = require('./handshake/keyExchange') const Login = require('./handshake/login') const LoginVerify = require('./handshake/loginVerify') @@ -19,20 +19,6 @@ class Client extends Connection { constructor (options) { super() this.options = { ...Options.defaultOptions, ...options } - this.validateOptions() - - const { RakClient } = require('./rak')(this.options.useNativeRaknet) - - this.serializer = createSerializer(this.options.version) - this.deserializer = createDeserializer(this.options.version) - - KeyExchange(this, null, this.options) - Login(this, null, this.options) - LoginVerify(this, null, this.options) - - const host = this.options.host - const port = this.options.port - this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port }) this.startGameData = {} this.clientRuntimeId = null @@ -42,9 +28,31 @@ class Client extends Connection { this.outLog = (...args) => debug('C <-', ...args) } this.conLog = this.options.conLog === undefined ? console.log : this.options.conLog + + if (!options.delayedInit) { + this.init() + } + } + + init () { + this.validateOptions() + this.serializer = createSerializer(this.options.version) + this.deserializer = createDeserializer(this.options.version) + + KeyExchange(this, null, this.options) + Login(this, null, this.options) + LoginVerify(this, null, this.options) + + const { RakClient } = initRaknet(this.options.useNativeRaknet) + const host = this.options.host + const port = this.options.port + this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port }) + + this.emit('connect_allowed') } connect () { + if (!this.connection) throw new Error('Connect not currently allowed') // must wait for `connect_allowed`, or use `createClient` this.on('session', this._connect) if (this.options.offline) { diff --git a/src/client/auth.js b/src/client/auth.js index 62f2a2f..72a44cc 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -4,6 +4,21 @@ const minecraftFolderPath = require('minecraft-folder-path') const debug = require('debug')('minecraft-protocol') const { uuidFrom } = require('../datatypes/util') +function validateOptions (options) { + if (!options.profilesFolder) { + options.profilesFolder = path.join(minecraftFolderPath, 'nmp-cache') + } + if (options.authTitle === undefined) { + options.authTitle = Titles.MinecraftNintendoSwitch + options.deviceType = 'Nintendo' + } +} + +async function realmAuthenticate (options) { + validateOptions(options) + throw new Error('Not implemented') +} + /** * Authenticates to Minecraft via device code based Microsoft auth, * then connects to the specified server in Client Options @@ -13,16 +28,10 @@ const { uuidFrom } = require('../datatypes/util') * @param {object} options - Client Options */ async function authenticate (client, options) { - if (!options.profilesFolder) { - options.profilesFolder = path.join(minecraftFolderPath, 'nmp-cache') - } - if (options.authTitle === undefined) { - options.authTitle = Titles.MinecraftNintendoSwitch - options.deviceType = 'Nintendo' - } + validateOptions(options) try { - const Authflow = new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode) - const chains = await Authflow.getMinecraftBedrockToken(client.clientX509).catch(e => { + const authflow = options.authflow || new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode) + const chains = await authflow.getMinecraftBedrockToken(client.clientX509).catch(e => { if (options.password) console.warn('Sign in failed, try removing the password field') throw e }) @@ -71,5 +80,6 @@ function postAuthenticate (client, profile, chains) { module.exports = { createOfflineSession, - authenticate + authenticate, + realmAuthenticate } diff --git a/src/createClient.js b/src/createClient.js index 7aff088..eec4412 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -1,27 +1,36 @@ const { Client } = require('./client') const { RakClient } = require('./rak')(true) -const { Versions, CURRENT_VERSION } = require('./options') const { sleep } = require('./datatypes/util') const assert = require('assert') +const Options = require('./options') const advertisement = require('./server/advertisement') +const auth = require('./client/auth') /** @param {{ version?: number, host: string, port?: number, connectTimeout?: number, skipPing?: boolean }} options */ function createClient (options) { assert(options) - const client = new Client({ port: 19132, ...options }) + const client = new Client({ port: 19132, ...options, delayedInit: true }) - if (options.skipPing) { - connect(client) - } else { // Try to ping - client.ping().then(data => { - const ad = advertisement.fromServerName(data) - client.options.version = options.version ?? (Versions[ad.version] ? ad.version : CURRENT_VERSION) - if (client.conLog) client.conLog(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') - client.emit('connect_allowed') - connect(client) - }, client) + function onServerInfo () { + if (options.skipPing) { + client.init() + } else { + ping(options).then(ad => { + const adVersion = ad.version?.split('.').slice(0, 3).join('.') // Only 3 version units + client.options.version = options.version ?? (Options.Versions[adVersion] ? adVersion : Options.CURRENT_VERSION) + client.conLog?.(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') + client.init() + }) + } } + if (options.realms) { + auth.realmAuthenticate(client.options).then(onServerInfo).catch(e => client.emit('error', e)) + } else { + onServerInfo() + } + + client.on('connect_allowed', () => connect(client)) return client } From cde600d51efcaaa1e6ea6222e2000b5a3e7330be Mon Sep 17 00:00:00 2001 From: LucienHH <66429271+LucienHH@users.noreply.github.com> Date: Sat, 9 Apr 2022 18:11:12 +0100 Subject: [PATCH 255/458] Implement Realm joining (#193) * Pass client options to ping * Implement RealmAPI to auth * Add Realm join example * Update package.json * Update README.md * Update index.d.ts * Show one option, remove listener * Fix wording * Explain options * Optional fields * Fix typo * Moved retry ad host/port extraction to prealms * Add docs * Fix lint * Depend on prealms release Co-authored-by: LucienHH --- README.md | 13 +++++++++++++ docs/API.md | 22 +++++++++++++++++++++- examples/client/realm.js | 13 +++++++++++++ index.d.ts | 9 +++++++++ package.json | 1 + src/client/auth.js | 31 ++++++++++++++++++++++++++++++- src/createClient.js | 2 +- 7 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 examples/client/realm.js diff --git a/README.md b/README.md index c4c67f2..752b8bd 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,19 @@ client.on('text', (packet) => { // Listen for chat messages and echo them back. }) ``` +### Client example joining a Realm + +Example to connect to a Realm that the authenticating account is owner of or has been invited to: + +```js +const bedrock = require('bedrock-protocol') +const client = bedrock.createClient({ + realms: { + pickRealm: (realms) => realms[0] // Function which recieves an array of joined/owned Realms and must return a single Realm. Can be async + } +}) +``` + ### Server example *Can't connect locally on Windows? See the [faq](docs/FAQ.md)* diff --git a/docs/API.md b/docs/API.md index 6401d3b..c1da683 100644 --- a/docs/API.md +++ b/docs/API.md @@ -8,7 +8,7 @@ Returns a `Client` instance and connects to the server. | Parameter | Optionality | Description | | ----------- | ----------- |-| -| host | **Required** | host to connect to, for example `127.0.0.1`. | +| host | Conditional | Not required if `realms` is set. host to connect to, for example `127.0.0.1`. | | port | *optional* | port to connect to, default to **19132** | | version | *optional* | Version to connect as. If not specified, automatically match server version. | | offline | *optional* | default to **false**. Set this to true to disable Microsoft/Xbox auth. | @@ -22,6 +22,10 @@ Returns a `Client` instance and connects to the server. | useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. | | compressionLevel | *optional* | What zlib compression level to use, default to **7** | | batchingInterval | *optional* | How frequently, in milliseconds to flush and write the packet queue (default: 20ms) | +| realms | *optional* | An object which should contain one of the following properties: `realmId`, `realmInvite`, `pickRealm`. When defined will attempt to join a Realm without needing to specify host/port. **The authenticated account must either own the Realm or have been invited to it** | +| realms.realmId | *optional* | The id of the Realm to join. | +| realms.realmInvite | *optional* | The invite link/code of the Realm to join. | +| realms.pickRealm | *optional* | A function which will have an array of the user Realms (joined/owned) passed to it. The function should return a Realm. | The following events are emitted by the client: * 'status' - When the client's login sequence status has changed @@ -134,6 +138,22 @@ Order of client event emissions: * 'join' - the client is ready to recieve game packets after successful server-client handshake * 'spawn' - emitted after the client has permission from the server to spawn +### Realm docs + +To make joining a Realm easier we've added an optional `realm` property to the client. It accepts the following options `realmId`, `realmInvite`, and `pickRealm`, supplying one of these will fetch host/port information for the specified Realm and then attempt to connect the bot. + - `realmId` - The id of the Realm to join. + - `realmInvite` - The invite code/link of the Realm to join. + - `pickRealm` - A function that will be called with a list of Realms to pick from. The function should return the Realm to join. + +```js +const bedrock = require('bedrock-protocol') +const client = bedrock.createClient({ + realms: { + pickRealm: (realms) => realms[0] // Function which recieves an array of joined/owned Realms and must return a single Realm. Can be async + } +}) +``` + ### Protocol docs For documentation on the protocol, and packets/fields see the [the protocol doc](https://minecraft-data.prismarine.js.org/?v=bedrock_1.18.0&d=protocol) (the emitted event names are the Packet types in lower case without the "packet_" prefix). More information on syntax can be found in CONTRIBUTING.md. When sending a packet, you must fill out all of the required fields. diff --git a/examples/client/realm.js b/examples/client/realm.js new file mode 100644 index 0000000..ac52282 --- /dev/null +++ b/examples/client/realm.js @@ -0,0 +1,13 @@ +/* eslint-disable */ +const bedrock = require('bedrock-protocol') +const client = bedrock.createClient({ + realms: { + // realmId: '1234567', // Connect the client to a Realm using the Realms ID + // realmInvite: 'https://realms.gg/AB1CD2EFA3B', // Connect the client to a Realm using the Realms invite URL or code + pickRealm: (realms) => realms.find(e => e.name === 'Realm Name') // Connect the client to a Realm using a function that returns a Realm + } +}) + +client.on('text', (packet) => { // Listen for chat messages + console.log('Received Text:', packet) +}) diff --git a/index.d.ts b/index.d.ts index b02d208..c828688 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,4 +1,5 @@ import EventEmitter from "events" +import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { type Version = '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' @@ -40,6 +41,8 @@ declare module "bedrock-protocol" { skipPing?: boolean // where to log connection information to (default to console.log) conLog? + // used to join a Realm instead of supplying a host/port + realms?: RealmsOptions } export interface ServerOptions extends Options { @@ -174,6 +177,12 @@ declare module "bedrock-protocol" { serverId: string } + export interface RealmsOptions { + realmId?: string + realmInvite?: string + pickRealm?: (realms: Realm[]) => Realm + } + export function createClient(options: ClientOptions): Client export function createServer(options: ServerOptions): Server diff --git a/package.json b/package.json index 12c09c9..b0ee475 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "minecraft-folder-path": "^1.2.0", "prismarine-auth": "^1.1.0", "prismarine-nbt": "^2.0.0", + "prismarine-realms": "^1.1.0", "protodef": "^1.14.0", "uuid-1345": "^1.0.2", "raknet-native": "^1.0.3" diff --git a/src/client/auth.js b/src/client/auth.js index 72a44cc..6e31da7 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -3,6 +3,7 @@ const { Authflow: PrismarineAuth, Titles } = require('prismarine-auth') const minecraftFolderPath = require('minecraft-folder-path') const debug = require('debug')('minecraft-protocol') const { uuidFrom } = require('../datatypes/util') +const { RealmAPI } = require('prismarine-realms') function validateOptions (options) { if (!options.profilesFolder) { @@ -16,7 +17,35 @@ function validateOptions (options) { async function realmAuthenticate (options) { validateOptions(options) - throw new Error('Not implemented') + + options.authflow = new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode) + + const api = RealmAPI.from(options.authflow, 'bedrock') + const realms = await api.getRealms() + + debug('realms', realms) + + if (!realms || !realms.length) throw Error('Couldn\'t find any Realms for the authenticated account') + + let realm + + if (options.realms.realmId) { + realm = realms.find(e => e.id === Number(options.realms.realmId)) + } else if (options.realms.realmInvite) { + realm = await api.getRealmFromInvite(options.realms.realmInvite) + } else if (options.realms.pickRealm) { + if (typeof options.realms.pickRealm !== 'function') throw Error('realms.pickRealm must be a function') + realm = await options.realms.pickRealm(realms) + } + + if (!realm) throw Error('Couldn\'t find a Realm to connect to. Authenticated account must be the owner or has been invited to the Realm.') + + const { host, port } = await realm.getAddress() + + debug('realms connection', { host, port }) + + options.host = host + options.port = port } /** diff --git a/src/createClient.js b/src/createClient.js index eec4412..3c19928 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -15,7 +15,7 @@ function createClient (options) { if (options.skipPing) { client.init() } else { - ping(options).then(ad => { + ping(client.options).then(ad => { const adVersion = ad.version?.split('.').slice(0, 3).join('.') // Only 3 version units client.options.version = options.version ?? (Options.Versions[adVersion] ? adVersion : Options.CURRENT_VERSION) client.conLog?.(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') From 9a4c7f03ea411b40b24ee5b0753547081d8de4cb Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 9 Apr 2022 20:18:11 -0400 Subject: [PATCH 256/458] Release 3.11.0 (#194) --- HISTORY.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 6d2017f..6d11679 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,12 @@ +## 3.11.0 +* Implement Realm joining (#193) @LucienHH +* Refactor client connection sequence (#189) @extremeheat +* Add profilesFolder to Relay (#192) @CreeperG16 +* Emit error from relay when server can't be pinged (#191) +* Pass relay onMsaCode to client (#190) @Heath123 +* Mark raknet-native as required dependency (#188) +* Ignore unconnected packets, remove babel (#185) + ## 3.10.0 * Support 1.18.11 (#179) @extremeheat * Switch to sync zlib with 512k chunks, adjustable compression level (#174) @extremeheat diff --git a/package.json b/package.json index b0ee475..4e4cc9e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.10.0", + "version": "3.11.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 5f90777bd717ec0a692f1bb314d1380e26e29fde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Apr 2022 14:03:54 -0400 Subject: [PATCH 257/458] Bump minecraft-data from 2.221.0 to 3.0.0 (#195) Bumps [minecraft-data](https://github.com/PrismarineJS/node-minecraft-data) from 2.221.0 to 3.0.0. - [Release notes](https://github.com/PrismarineJS/node-minecraft-data/releases) - [Changelog](https://github.com/PrismarineJS/node-minecraft-data/blob/master/doc/history.md) - [Commits](https://github.com/PrismarineJS/node-minecraft-data/compare/2.221.0...3.0.0) --- updated-dependencies: - dependency-name: minecraft-data dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e4cc9e..2ab8d85 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "debug": "^4.3.1", "jsonwebtoken": "^8.5.1", "jsp-raknet": "^2.1.3", - "minecraft-data": "^2.96.0", + "minecraft-data": "^3.0.0", "minecraft-folder-path": "^1.2.0", "prismarine-auth": "^1.1.0", "prismarine-nbt": "^2.0.0", From 930d90ea3079569ce4b4010aa15846192025865d Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 19 Apr 2022 14:07:13 -0400 Subject: [PATCH 258/458] Release 3.11.1 (#197) * Update package.json * Update HISTORY.md --- HISTORY.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 6d11679..a7737b8 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,6 @@ +## 3.11.1 +* Bump minecraft-data version + ## 3.11.0 * Implement Realm joining (#193) @LucienHH * Refactor client connection sequence (#189) @extremeheat diff --git a/package.json b/package.json index 2ab8d85..744c599 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.11.0", + "version": "3.11.1", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From dc3fb5629eb940ab8075c9b1d4c8770562af018c Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 20 Apr 2022 16:11:02 -0400 Subject: [PATCH 259/458] 1.18.30 (#198) --- src/options.js | 4 ++-- tools/compileProtocol.js | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/options.js b/src/options.js index 7949f85..ed45ddf 100644 --- a/src/options.js +++ b/src/options.js @@ -3,9 +3,9 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.18.11' +const CURRENT_VERSION = '1.18.30' -const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version]).reverse()) +const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) const defaultOptions = { // https://minecraft.gamepedia.com/Protocol_version#Bedrock_Edition_2 diff --git a/tools/compileProtocol.js b/tools/compileProtocol.js index 079dca3..a51cfc1 100644 --- a/tools/compileProtocol.js +++ b/tools/compileProtocol.js @@ -35,6 +35,8 @@ function main (ver = 'latest') { createProtocol(ver) } +require('minecraft-data/bin/generate_data') + // If no argument, build everything if (!process.argv[2]) { convert('latest') From 20c53c49d7b08fa28574bd64e27ab0cfa5a01f5a Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 21 Apr 2022 14:04:10 -0400 Subject: [PATCH 260/458] Release 3.12.0 (#199) --- HISTORY.md | 3 +++ README.md | 2 +- package.json | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index a7737b8..d50387c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,6 @@ +## 3.12.0 +* 1.18.30 support + ## 3.11.1 * Bump minecraft-data version diff --git a/README.md b/README.md index 752b8bd..8eba17c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/package.json b/package.json index 744c599..9863cd3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.11.1", + "version": "3.12.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From f2d39a071b99c9d457fbc31850a91184fa4541ac Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 21 Apr 2022 22:28:38 -0400 Subject: [PATCH 261/458] Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index c828688..83e7a9e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } From 52156a002473b9752e97bd13bf15a18645256667 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 30 Apr 2022 19:02:56 -0400 Subject: [PATCH 262/458] Add XUID field for client offline mode client chain (#203) * Add XUID field for client offline mode client chain * Update serverPlayer.js handle alternative casing * test/internal.js: randomize test port * fix * test server starting retry --- src/handshake/login.js | 3 ++- src/serverPlayer.js | 2 +- test/internal.js | 6 +++--- test/vanilla.js | 2 +- tools/startVanillaServer.js | 11 ++++++++++- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/handshake/login.js b/src/handshake/login.js index 5035a3d..cf76d96 100644 --- a/src/handshake/login.js +++ b/src/handshake/login.js @@ -15,7 +15,8 @@ module.exports = (client, server, options) => { extraData: { displayName: client.username, identity: client.profile.uuid, - titleId: '89692877' + titleId: '89692877', + XUID: '0' }, certificateAuthority: true, identityPublicKey: client.clientX509 diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 906f3f2..7edfea2 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -69,7 +69,7 @@ class Player extends Connection { this.profile = { name: userData.extraData?.displayName, uuid: userData.extraData?.identity, - xuid: userData.extraData?.xuid + xuid: userData.extraData?.xuid || userData.extraData?.XUID } this.version = clientVer this.emit('login', { user: userData.extraData }) // emit events for user diff --git a/test/internal.js b/test/internal.js index 50335fd..22c6c87 100644 --- a/test/internal.js +++ b/test/internal.js @@ -14,7 +14,7 @@ function prepare (version) { async function startTest (version = CURRENT_VERSION, ok) { await prepare(version) const Item = require('../types/Item')(version) - const port = 19130 + const port = 19130 + Math.floor(Math.random() * 100) const server = new Server({ host: '0.0.0.0', port, version, offline: true }) function getPath (packetPath) { @@ -25,6 +25,7 @@ async function startTest (version = CURRENT_VERSION, ok) { return require(getPath('sample/' + packetPath)) } + console.log('Starting internal server') server.listen() console.log('Started server') @@ -190,7 +191,6 @@ async function requestChunks (version, x, z, radius) { blobs: [], payload: cbuf }) - // console.log('Ht',cc.sectionsLen,cc.sections) } } @@ -207,5 +207,5 @@ async function timedTest (version, timeout = 1000 * 220) { console.info('✔ ok') } -// if (!module.parent) timedTest('1.18.11') +// if (!module.parent) timedTest('1.16.210') module.exports = { startTest, timedTest, requestChunks } diff --git a/test/vanilla.js b/test/vanilla.js index 41033cc..3f3aa0c 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -7,7 +7,7 @@ async function test (version) { const ChunkColumn = require('bedrock-provider').chunk('bedrock_' + version) // Start the server, wait for it to accept clients, throws on timeout - const handle = await vanillaServer.startServerAndWait(version, 1000 * 220) + const handle = await vanillaServer.startServerAndWait2(version, 1000 * 220) console.log('Started server') const client = new Client({ diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index e2ba4d9..74e4360 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -110,9 +110,18 @@ async function startServerAndWait (version, withTimeout, options) { return handle } +async function startServerAndWait2 (version, withTimeout, options) { + try { + return await startServerAndWait(version, withTimeout, options) + } catch (e) { + console.log(e, 'tring once more to start server...') + return await startServerAndWait(version, withTimeout, options) + } +} + if (!module.parent) { // if (process.argv.length < 3) throw Error('Missing version argument') startServer(process.argv[2] || '1.17.10', null, process.argv[3] ? { 'server-port': process.argv[3], 'online-mode': !!process.argv[4] } : undefined) } -module.exports = { fetchLatestStable, startServer, startServerAndWait } +module.exports = { fetchLatestStable, startServer, startServerAndWait, startServerAndWait2 } From fbe7ff79e807e8ac45185493c3f633a32671d7a8 Mon Sep 17 00:00:00 2001 From: ATXLtheAxolotl <49346095+ATXLtheAxolotl@users.noreply.github.com> Date: Sat, 30 Apr 2022 19:18:00 -0400 Subject: [PATCH 263/458] Emit generic 'packet' event for server clients (#205) * Send out an all event on ServerPlayer For debugging purposes * Add a space for linter * Changed to be similar to Client's all * A space :| * Update serverPlayer.js --- src/serverPlayer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 7edfea2..f8c9763 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -152,6 +152,7 @@ class Player extends Connection { } } this.emit(des.data.name, des.data.params) + this.emit('packet', des) } } From 63d11c24bbe200bf32b6f5ecd9d5d338a2a6a4f3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 30 Apr 2022 19:22:35 -0400 Subject: [PATCH 264/458] Update API documentation --- docs/API.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/API.md b/docs/API.md index c1da683..c1f0b7f 100644 --- a/docs/API.md +++ b/docs/API.md @@ -27,7 +27,7 @@ Returns a `Client` instance and connects to the server. | realms.realmInvite | *optional* | The invite link/code of the Realm to join. | | realms.pickRealm | *optional* | A function which will have an array of the user Realms (joined/owned) passed to it. The function should return a Realm. | -The following events are emitted by the client: +The following special events are emitted by the client on top of protocol packets: * 'status' - When the client's login sequence status has changed * 'join' - When the client has joined the server after authenticating * 'spawn' - When the client has spawned into the game world, as it is getting chunks @@ -36,6 +36,7 @@ The following events are emitted by the client: * 'error' - An recoverable exception has happened. Not catching will throw an exception * 'connect_allowed' - Emitted after the client has pinged the server and gets version information. * 'heartbeat' - Emitted after two successful tick_sync (keepalive) packets have been sent bidirectionally +* 'packet' - Emitted for all packets received by client ## be.createServer(options) : Server @@ -97,15 +98,17 @@ server.on('connect', (client) => { ``` -Order of server client event emissions: +Server event emissions: * 'connect' - emitted by `Server` after a client first joins the server. Second paramater is a `ServerPlayer` instance. -* 'login' - emitted by client after the client has been authenticated by the server -* 'join' - the client is ready to recieve game packets after successful server-client handshake/encryption -* 'spawn' - emitted after the client lets the server know that it has successfully spawned - 'error' event is emitted when a catchable exception happens with a client (for example receiving a bad encrypted packet). +A ServerPlayer instance also emits the following special events: +* 'join' - the client is ready to recieve game packets after successful server-client handshake/encryption +* 'login' - emitted by client after the client has been authenticated by the server +* 'spawn' - emitted after the client lets the server know that it has successfully spawned +* 'packet' - Emitted for all packets received by client + ## Client docs You can create a server as such: From f4bd49dca01d4c72a97d95a7626deaf95b4dc5e5 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 30 Apr 2022 19:25:33 -0400 Subject: [PATCH 265/458] Add 1.18.31 to types --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 83e7a9e..c2bc9f9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } From f7c556ec9440307ba0c07a9f8b00710c41a72e2e Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 4 May 2022 16:11:53 -0400 Subject: [PATCH 266/458] Release 3.13.0 (#208) --- HISTORY.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index d50387c..855c610 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,8 @@ +## 3.13.0 +* Update API documentation +* Emit generic 'packet' event for server clients (#205) @ATXLtheAxolotl +* Add XUID field for client offline mode client chain (#203) + ## 3.12.0 * 1.18.30 support diff --git a/package.json b/package.json index 9863cd3..f9ec44f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.12.0", + "version": "3.13.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 2d7c210acc4137d064425535581d3762292c8d5a Mon Sep 17 00:00:00 2001 From: Erik <33035080+ErikPDev@users.noreply.github.com> Date: Tue, 7 Jun 2022 10:47:21 +0300 Subject: [PATCH 267/458] Server: correct body.protocol_version to body.params.protocol_version (#221) packet.data is ```json { name: 'login', params: { protocol_version: 503, tokens: { identity: '...' } } } ``` Therefore `body.protocol_version` outputs undefined. --- src/serverPlayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serverPlayer.js b/src/serverPlayer.js index f8c9763..83f25ec 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -38,7 +38,7 @@ class Player extends Connection { const body = packet.data this.emit('loggingIn', body) - const clientVer = body.protocol_version + const clientVer = body.params.protocol_version if (this.server.options.protocolVersion) { if (this.server.options.protocolVersion < clientVer) { this.sendDisconnectStatus('failed_spawn') From df31b5d63ac20daf9ba66ed119742e85a8dfef59 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 9 Jun 2022 13:08:51 -0400 Subject: [PATCH 268/458] test/vanilla: temporary hack to allow 1.19 chunk tests to pass --- test/vanilla.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/vanilla.js b/test/vanilla.js index 3f3aa0c..ac1cdda 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -4,7 +4,7 @@ const { Client } = require('../src/client') const { waitFor } = require('../src/datatypes/util') async function test (version) { - const ChunkColumn = require('bedrock-provider').chunk('bedrock_' + version) + const ChunkColumn = require('bedrock-provider').chunk('bedrock_' + (version.includes('1.19') ? '1.18.30' : version)) // TODO: Fix prismarine-chunk // Start the server, wait for it to accept clients, throws on timeout const handle = await vanillaServer.startServerAndWait2(version, 1000 * 220) From aacd4b4256933ee68b0d9adf0f4e868c9fe43673 Mon Sep 17 00:00:00 2001 From: Stephen O'Connor Date: Thu, 9 Jun 2022 10:45:58 -0700 Subject: [PATCH 269/458] Better handle ping timeout, update documentation (#218) * Better handle ping_timeout, update documentation * Remove extra semicolon * Change ping_timeout to client.emit('error', e) for more normalized handling * Remove extra RakTimeout import --- docs/API.md | 1 + src/createClient.js | 13 +++++++------ src/rak.js | 12 +++++++----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/API.md b/docs/API.md index c1f0b7f..6955f91 100644 --- a/docs/API.md +++ b/docs/API.md @@ -37,6 +37,7 @@ The following special events are emitted by the client on top of protocol packet * 'connect_allowed' - Emitted after the client has pinged the server and gets version information. * 'heartbeat' - Emitted after two successful tick_sync (keepalive) packets have been sent bidirectionally * 'packet' - Emitted for all packets received by client +* 'session' - When the client has finished authenticating and connecting ## be.createServer(options) : Server diff --git a/src/createClient.js b/src/createClient.js index 3c19928..f48b1a3 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -12,6 +12,7 @@ function createClient (options) { const client = new Client({ port: 19132, ...options, delayedInit: true }) function onServerInfo () { + client.on('connect_allowed', () => connect(client)) if (options.skipPing) { client.init() } else { @@ -20,7 +21,7 @@ function createClient (options) { client.options.version = options.version ?? (Options.Versions[adVersion] ? adVersion : Options.CURRENT_VERSION) client.conLog?.(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') client.init() - }) + }).catch(e => client.emit('error', e)) } } @@ -29,8 +30,6 @@ function createClient (options) { } else { onServerInfo() } - - client.on('connect_allowed', () => connect(client)) return client } @@ -81,9 +80,11 @@ function connect (client) { async function ping ({ host, port }) { const con = new RakClient({ host, port }) - const ret = await con.ping() - con.close() - return advertisement.fromServerName(ret) + try { + return advertisement.fromServerName(await con.ping()) + } finally { + con.close() + } } module.exports = { createClient, ping } diff --git a/src/rak.js b/src/rak.js index 182ef09..19f313c 100644 --- a/src/rak.js +++ b/src/rak.js @@ -4,11 +4,13 @@ const { waitFor } = require('./datatypes/util') let Client, Server, PacketPriority, EncapsulatedPacket, PacketReliability, Reliability +class RakTimeout extends Error {}; + module.exports = nativeRaknet => { if (nativeRaknet) { try { ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-native')) - return { RakServer: RakNativeServer, RakClient: RakNativeClient } + return { RakServer: RakNativeServer, RakClient: RakNativeClient, RakTimeout } } catch (e) { ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) console.debug('[raknet] native not found, using js', e) @@ -17,7 +19,7 @@ module.exports = nativeRaknet => { } else { ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) } - return { RakServer: RakJsServer, RakClient: RakJsClient } + return { RakServer: RakJsServer, RakClient: RakJsClient, RakTimeout } } class RakNativeClient extends EventEmitter { @@ -54,7 +56,7 @@ class RakNativeClient extends EventEmitter { done(ret.extra.toString()) } }) - }, timeout, () => { throw new Error('Ping timed out') }) + }, timeout, () => { throw new RakTimeout('Ping timed out') }) } connect () { @@ -193,7 +195,7 @@ class RakJsClient extends EventEmitter { this.worker.postMessage({ type: 'ping' }) return waitFor(res => { this.pongCb = data => res(data) - }, timeout, () => { throw new Error('Ping timed out') }) + }, timeout, () => { throw new RakTimeout('Ping timed out') }) } else { if (!this.raknet) this.raknet = new Client(this.options.host, this.options.port) return waitFor(res => { @@ -201,7 +203,7 @@ class RakJsClient extends EventEmitter { this.raknet.close() res(data) }) - }, timeout, () => { throw new Error('Ping timed out') }) + }, timeout, () => { throw new RakTimeout('Ping timed out') }) } } } From b6d0ab3765fc5caf7933b46d40395d91840d4d61 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 9 Jun 2022 14:46:05 -0400 Subject: [PATCH 270/458] Make CI more reliable (#217) * Use 2-attempt server start method in dump test * Update startVanillaServer.js replace download from curl to nodejs https * fix syntax error * corrections * rm some logging * fix --- tools/genPacketDumps.js | 2 +- tools/startVanillaServer.js | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/genPacketDumps.js b/tools/genPacketDumps.js index 4176b65..cd28d47 100644 --- a/tools/genPacketDumps.js +++ b/tools/genPacketDumps.js @@ -22,7 +22,7 @@ async function dump (version, force = true) { const [port, v6] = [19132 + random, 19133 + random] console.log('Starting dump server', version) - const handle = await vanillaServer.startServerAndWait(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port, 'server-portv6': v6 }) + const handle = await vanillaServer.startServerAndWait2(version || CURRENT_VERSION, 1000 * 120, { 'server-port': port, 'server-portv6': v6 }) console.log('Started dump server', version) const client = new Client({ diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 74e4360..8cd1565 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -2,10 +2,23 @@ const http = require('https') const fs = require('fs') const cp = require('child_process') const debug = require('debug')('minecraft-protocol') +const https = require('https') const { getFiles, waitFor } = require('../src/datatypes/util') const head = (url) => new Promise((resolve, reject) => http.request(url, { method: 'HEAD' }, resolve).on('error', reject).end()) -const get = (url, out) => cp.execSync(`curl -o ${out} ${url}`) +function get (url, outPath) { + const file = fs.createWriteStream(outPath) + return new Promise((resolve, reject) => { + https.get(url, { timeout: 1000 * 20 }, response => { + if (response.statusCode !== 200) return reject(new Error('Server returned code ' + response.statusCode)) + response.pipe(file) + file.on('finish', () => { + file.close() + resolve() + }) + }) + }) +} // Get the latest versions // TODO: once we support multi-versions @@ -45,7 +58,7 @@ async function download (os, version, path = 'bds-') { } if (!found) throw Error('did not find server bin for ' + os + ' ' + version) console.info('🔻 Downloading', found) - get(found, 'bds.zip') + await get(found, 'bds.zip') console.info('⚡ Unzipping') // Unzip server if (process.platform === 'linux') cp.execSync('unzip bds.zip && chmod +777 ./bedrock_server') @@ -115,6 +128,8 @@ async function startServerAndWait2 (version, withTimeout, options) { return await startServerAndWait(version, withTimeout, options) } catch (e) { console.log(e, 'tring once more to start server...') + process.chdir(__dirname) + fs.rmSync('bds-' + version, { recursive: true }) return await startServerAndWait(version, withTimeout, options) } } From 9fac48e948fe5af734ebe1b5752b5fc7aada2b79 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 9 Jun 2022 15:44:20 -0400 Subject: [PATCH 271/458] 1.19 support (#224) --- src/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.js b/src/options.js index ed45ddf..db3bee2 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.18.30' +const CURRENT_VERSION = '1.19.1' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) From c7b825820e84bfd4482a49970dd2aa000584c1d6 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 9 Jun 2022 16:06:38 -0400 Subject: [PATCH 272/458] Release 3.14.0 (#225) --- HISTORY.md | 4 ++++ README.md | 2 +- package.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 855c610..c5e1156 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## 3.14.0 +* 1.19 support +* Better handle ping timeout, update documentation (#218) @stevarino + ## 3.13.0 * Update API documentation * Emit generic 'packet' event for server clients (#205) @ATXLtheAxolotl diff --git a/README.md b/README.md index 8eba17c..3707b1d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/package.json b/package.json index f9ec44f..2977877 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.13.0", + "version": "3.14.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 6e73a75138d255e0c3a12cf9c2d2bd3b34f8c446 Mon Sep 17 00:00:00 2001 From: ATXLtheAxolotl <49346095+ATXLtheAxolotl@users.noreply.github.com> Date: Fri, 17 Jun 2022 05:55:50 -0400 Subject: [PATCH 273/458] Add Realm support to Relay (#226) * add(): realm relay * fix(): Non-async solution to realm proxy * fix(): follow the guidlines of the strict linter * fix(): Use Client constructor instead of createClient function * types(): Update index.d.ts to include realms option in destination --- examples/realmRelay.js | 29 +++++++++++++++++++++++++++++ index.d.ts | 1 + src/relay.js | 16 ++++++++++++---- 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 examples/realmRelay.js diff --git a/examples/realmRelay.js b/examples/realmRelay.js new file mode 100644 index 0000000..2f40d8a --- /dev/null +++ b/examples/realmRelay.js @@ -0,0 +1,29 @@ +const { Relay } = require('bedrock-protocol') + +function createRelay () { + console.log('Creating relay') + /* Example to create a non-transparent proxy (or 'Relay') connection to destination server */ + const relay = new Relay({ + /* host and port for clients to listen to */ + host: '0.0.0.0', + port: 19130, + offline: false, + /* Where to send upstream packets to */ + destination: { + realms: { + pickRealm: (realms) => realms.find(e => e.name === 'Realm Name') + }, + offline: false + } + }) + relay.conLog = console.debug + relay.listen() + relay.on('connect', player => { + // Server is sending a message to the client. + player.on('clientbound', ({ name, params }) => { + if (name === 'text') console.log(params) + }) + }) +} + +createRelay() diff --git a/index.d.ts b/index.d.ts index c2bc9f9..746506f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -153,6 +153,7 @@ declare module "bedrock-protocol" { authTitle: title | string // Where to proxy requests to. destination: { + realms?: RealmsOptions host: string, port: number, // Skip authentication connecting to the remote server? diff --git a/src/relay.js b/src/relay.js index 086b0be..bcb1295 100644 --- a/src/relay.js +++ b/src/relay.js @@ -1,6 +1,7 @@ const { Client } = require('./client') const { Server } = require('./server') const { Player } = require('./serverPlayer') +const { realmAuthenticate } = require('./client/auth') const debug = globalThis.isElectron ? console.debug : require('debug')('minecraft-protocol') const debugging = false // Do re-encoding tests @@ -170,18 +171,25 @@ class Relay extends Server { // a packet, no matter what state it's in. For example, if the client wants to send a // packet to the server but it's not connected, it will add to the queue and send as soon // as a connection with the server is established. - openUpstreamConnection (ds, clientAddr) { - const client = new Client({ + async openUpstreamConnection (ds, clientAddr) { + const options = { authTitle: this.options.authTitle, offline: this.options.destination.offline ?? this.options.offline, username: this.options.offline ? ds.profile.name : null, version: this.options.version, + realms: this.options.destination.realms, host: this.options.destination.host, port: this.options.destination.port, onMsaCode: this.options.onMsaCode, profilesFolder: this.options.profilesFolder, autoInitPlayer: false - }) + } + + if (this.options.destination.realms) { + await realmAuthenticate(options) + } + + const client = new Client(options) // Set the login payload unless `noLoginForward` option if (!client.noLoginForward) client.options.skinData = ds.skinData client.ping().then(pongData => { @@ -189,7 +197,7 @@ class Relay extends Server { }).catch(err => { this.emit('error', err) }) - this.conLog('Connecting to', this.options.destination.host, this.options.destination.port) + this.conLog('Connecting to', options.host, options.port) client.outLog = ds.upOutLog client.inLog = ds.upInLog client.once('join', () => { From 19bc2519e7d29ce79e8d2107d42b52eaef783f96 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 22 Jun 2022 14:57:33 -0400 Subject: [PATCH 274/458] types: add 1.19.2 to versions Add 1.19.2 to versions --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 746506f..37ff132 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } From bdaf21b8edba3ecb5a02a823d2f601567fd3fe7f Mon Sep 17 00:00:00 2001 From: extremeheat Date: Fri, 24 Jun 2022 04:31:22 -0400 Subject: [PATCH 275/458] CI: increase timeout to 12min --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79e0818..da29ac7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: os: [ubuntu-latest, windows-latest] node-version: [16.x] runs-on: ${{ matrix.os }} - timeout-minutes: 10 + timeout-minutes: 12 steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} From 149b4fe182ae5c2f87065c48f90c22057adeae0e Mon Sep 17 00:00:00 2001 From: LucienHH <66429271+LucienHH@users.noreply.github.com> Date: Fri, 24 Jun 2022 23:48:33 +0100 Subject: [PATCH 276/458] Update auth.js (#231) --- src/client/auth.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/client/auth.js b/src/client/auth.js index 6e31da7..a16b41a 100644 --- a/src/client/auth.js +++ b/src/client/auth.js @@ -21,20 +21,24 @@ async function realmAuthenticate (options) { options.authflow = new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode) const api = RealmAPI.from(options.authflow, 'bedrock') - const realms = await api.getRealms() - debug('realms', realms) - - if (!realms || !realms.length) throw Error('Couldn\'t find any Realms for the authenticated account') + const getRealms = async () => { + const realms = await api.getRealms() + debug('realms', realms) + if (!realms.length) throw Error('Couldn\'t find any Realms for the authenticated account') + return realms + } let realm if (options.realms.realmId) { + const realms = await getRealms() realm = realms.find(e => e.id === Number(options.realms.realmId)) } else if (options.realms.realmInvite) { realm = await api.getRealmFromInvite(options.realms.realmInvite) } else if (options.realms.pickRealm) { if (typeof options.realms.pickRealm !== 'function') throw Error('realms.pickRealm must be a function') + const realms = await getRealms() realm = await options.realms.pickRealm(realms) } From 7263714562b72b437958ea638c7e9b88034ff33b Mon Sep 17 00:00:00 2001 From: Jonathan Nagy Date: Tue, 28 Jun 2022 11:49:54 +1000 Subject: [PATCH 277/458] Fix chat echo sample (#233) * Fix chat echo sample The `client.options.username` reference is optional for online connections. Referencing it here when it is null will not filter out the echo text, causing an infinite loop. * Update client.js --- README.md | 2 +- examples/client/client.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3707b1d..a72aea1 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ const client = bedrock.createClient({ }) client.on('text', (packet) => { // Listen for chat messages and echo them back. - if (packet.source_name != client.options.username) { + if (packet.source_name != client.username) { client.queue('text', { type: 'chat', needs_translation: false, source_name: client.username, xuid: '', platform_chat_id: '', message: `${packet.source_name} said: ${packet.message} on ${new Date().toLocaleString()}` diff --git a/examples/client/client.js b/examples/client/client.js index c10710a..7bbd028 100644 --- a/examples/client/client.js +++ b/examples/client/client.js @@ -8,10 +8,10 @@ const client = bedrock.createClient({ }) client.on('text', (packet) => { // Listen for chat messages and echo them back. - if (packet.source_name != client.options.username) { + if (packet.source_name != client.username) { client.queue('text', { type: 'chat', needs_translation: false, source_name: client.username, xuid: '', platform_chat_id: '', message: `${packet.source_name} said: ${packet.message} on ${new Date().toLocaleString()}` }) } -}) \ No newline at end of file +}) From 87a958e4abf034d225446804681c88e11edf9fb6 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 18 Jul 2022 16:33:58 -0400 Subject: [PATCH 278/458] Prereq update for 1.19.10 changes to server join flow --- test/internal.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/internal.js b/test/internal.js index 22c6c87..51e1f71 100644 --- a/test/internal.js +++ b/test/internal.js @@ -65,7 +65,10 @@ async function startTest (version = CURRENT_VERSION, ok) { client.queue('set_time', { time: 5433771 }) client.queue('set_difficulty', { difficulty: 1 }) client.queue('set_commands_enabled', { enabled: true }) - client.queue('adventure_settings', get('packets/adventure_settings.json')) + + if (client.versionLessThan('1.19.10')) { + client.queue('adventure_settings', get('packets/adventure_settings.json')) + } client.queue('biome_definition_list', get('packets/biome_definition_list.json')) client.queue('available_entity_identifiers', get('packets/available_entity_identifiers.json')) @@ -207,5 +210,5 @@ async function timedTest (version, timeout = 1000 * 220) { console.info('✔ ok') } -// if (!module.parent) timedTest('1.16.210') +// if (!module.parent) timedTest('1.19.10') module.exports = { startTest, timedTest, requestChunks } From 1542ab63d191895640730e5dc33abf263d223f4f Mon Sep 17 00:00:00 2001 From: extremeheat Date: Mon, 18 Jul 2022 22:03:01 -0400 Subject: [PATCH 279/458] Release 3.15.0 (#236) * Update options.js * Update package.json * Update README.md * Update index.d.ts * Update HISTORY.md --- HISTORY.md | 5 +++++ README.md | 2 +- index.d.ts | 2 +- package.json | 2 +- src/options.js | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index c5e1156..5528d70 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,8 @@ +## 3.15.0 +* 1.19.10 support +* Remove Realm fetch when joining via invite (#228) @LucienHH +* Add Realm support to Relay (#226) @ATXLtheAxolotl + ## 3.14.0 * 1.19 support * Better handle ping timeout, update documentation (#218) @stevarino diff --git a/README.md b/README.md index a72aea1..0c2a1db 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/index.d.ts b/index.d.ts index 37ff132..5570ae3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } diff --git a/package.json b/package.json index 2977877..f4aaeb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.14.0", + "version": "3.15.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { diff --git a/src/options.js b/src/options.js index db3bee2..a4288fb 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.19.1' +const CURRENT_VERSION = '1.19.10' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) From 370ca96f2e7e2adcf5c42672acc129b5d7cc68ea Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 21 Jul 2022 06:24:15 -0400 Subject: [PATCH 280/458] Update startVanillaServer.js Debug log on CI --- tools/startVanillaServer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 8cd1565..cbd9870 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -1,7 +1,7 @@ const http = require('https') const fs = require('fs') const cp = require('child_process') -const debug = require('debug')('minecraft-protocol') +const debug = process.env.CI ? console.debug : require('debug')('minecraft-protocol') const https = require('https') const { getFiles, waitFor } = require('../src/datatypes/util') @@ -31,6 +31,7 @@ function fetchLatestStable () { // Download + extract vanilla server and enter the directory async function download (os, version, path = 'bds-') { + debug('Downloading server', os, version, 'into', path) process.chdir(__dirname) const verStr = version.split('.').slice(0, 3).join('.') const dir = path + version From d221da76134ab867f3dac0ebc7ab2f8a4b8c529a Mon Sep 17 00:00:00 2001 From: extremeheat Date: Tue, 26 Jul 2022 21:05:51 -0400 Subject: [PATCH 281/458] Update version list for 1.19.11 Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 5570ae3..e03ef61 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } From b36c55e11237d025118b298a6c6062a1b92fecf3 Mon Sep 17 00:00:00 2001 From: b23r0 Date: Tue, 9 Aug 2022 15:39:27 +0800 Subject: [PATCH 282/458] Add new raknet library option (raknet-node) (#211) * add new raknet library option (raknet-node) * fix lint * fix lint & add new options * fix lint * fix user option & add rust-raknet test. * fix lint. * add raknet backend option. * remove useNativeRaknet option. * add not found log. * add test timeout size. * fix js raknet return error. * restore useNativeRaknet option. * update doc. * update options handling, back compat * fix server doc * Fix tests * fix tests. * fix lint. * delay timeout. * Update rak.js * update raknet-node version. * increase timeout. * Update vanilla.js * Update proxy.js * Update internal.js * update raknet-node version. * update rust-raknet version. * increase timeout test time * increase timeout test time * update backend version. * change timeout Co-authored-by: extremeheat --- docs/API.md | 7 ++++++- package.json | 5 +++-- src/client.js | 13 ++----------- src/createClient.js | 2 +- src/options.js | 21 ++++++++++++++++++--- src/rak.js | 21 +++++++++++---------- src/relay.js | 1 + src/server.js | 12 ++---------- test/proxy.js | 11 +++++++---- test/vanilla.js | 1 + 10 files changed, 52 insertions(+), 42 deletions(-) diff --git a/docs/API.md b/docs/API.md index 6955f91..8d0b545 100644 --- a/docs/API.md +++ b/docs/API.md @@ -19,7 +19,7 @@ Returns a `Client` instance and connects to the server. | autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | | skipPing | *optional* | Whether pinging the server to check its version should be skipped. | | conLog | *optional* | Where to log connection information (server join, kick messages to). Defaults to console.log, set to `null` to not log anywhere. | -| useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. | +| raknetBackend | *optional* | Specifies the raknet implementation to use. Possible options are 'raknet-native' (default, original C++ implementation), 'jsp-raknet' (JS port), and 'raknet-node' (Rust port). Please note when using the non-JS implementation you may the need approporate build tools on your system (for example a C++ or Rust compiler). | | compressionLevel | *optional* | What zlib compression level to use, default to **7** | | batchingInterval | *optional* | How frequently, in milliseconds to flush and write the packet queue (default: 20ms) | | realms | *optional* | An object which should contain one of the following properties: `realmId`, `realmInvite`, `pickRealm`. When defined will attempt to join a Realm without needing to specify host/port. **The authenticated account must either own the Realm or have been invited to it** | @@ -27,6 +27,8 @@ Returns a `Client` instance and connects to the server. | realms.realmInvite | *optional* | The invite link/code of the Realm to join. | | realms.pickRealm | *optional* | A function which will have an array of the user Realms (joined/owned) passed to it. The function should return a Realm. | +*`useNativeRaknet` is deprecated. Setting to true will use 'raknet-native' for `raknetBackend` and setting it to false will use a JavaScript implemenation (jsp-raknet)* + The following special events are emitted by the client on top of protocol packets: * 'status' - When the client's login sequence status has changed * 'join' - When the client has joined the server after authenticating @@ -57,6 +59,9 @@ authenticated unless offline is set to true. | motd | *optional* | The "message of the day" for the server, the message shown to players in the server list. See usage below. | | advertisementFn | *optional* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | | conLog | *optional* | Where to log connection information (server join, kick messages to). Default to log only in DEBUG mode. | +| raknetBackend | *optional* | Specifies the raknet implementation to use. Possible options are 'raknet-native' (default, original C++ implementation), 'jsp-raknet' (JS port), and 'raknet-node' (Rust port). Please note when using the non-JS implementation you may the need approporate build tools on your system (for example a C++ or Rust compiler). | + +*`useNativeRaknet` is deprecated. Setting to true will use 'raknet-native' for `raknetBackend` and setting it to false will use a JavaScript implemenation (jsp-raknet)* ## be.ping({ host, port }) : ServerAdvertisement diff --git a/package.json b/package.json index f4aaeb6..d29f497 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,11 @@ "prismarine-nbt": "^2.0.0", "prismarine-realms": "^1.1.0", "protodef": "^1.14.0", - "uuid-1345": "^1.0.2", - "raknet-native": "^1.0.3" + "raknet-native": "^1.0.3", + "uuid-1345": "^1.0.2" }, "optionalDependencies": { + "raknet-node": "^0.4.6" }, "devDependencies": { "bedrock-protocol": "file:.", diff --git a/src/client.js b/src/client.js index 85f48df..7ec612b 100644 --- a/src/client.js +++ b/src/client.js @@ -43,7 +43,7 @@ class Client extends Connection { Login(this, null, this.options) LoginVerify(this, null, this.options) - const { RakClient } = initRaknet(this.options.useNativeRaknet) + const { RakClient } = initRaknet(this.options.raknetBackend) const host = this.options.host const port = this.options.port this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port }) @@ -67,16 +67,7 @@ class Client extends Connection { validateOptions () { if (!this.options.host || this.options.port == null) throw Error('Invalid host/port') - - if (!Options.Versions[this.options.version]) { - console.warn('Supported versions: ', Options.Versions) - throw Error(`Unsupported version ${this.options.version}`) - } - this.options.protocolVersion = Options.Versions[this.options.version] - if (this.options.protocolVersion < Options.MIN_VERSION) { - throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) - } - this.compressionLevel = this.options.compressionLevel || 7 + Options.validateOptions(this.options) } get entityId () { diff --git a/src/createClient.js b/src/createClient.js index f48b1a3..a642c7c 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -1,5 +1,5 @@ const { Client } = require('./client') -const { RakClient } = require('./rak')(true) +const { RakClient } = require('./rak')('raknet-native') const { sleep } = require('./datatypes/util') const assert = require('assert') const Options = require('./options') diff --git a/src/options.js b/src/options.js index a4288fb..ae57abe 100644 --- a/src/options.js +++ b/src/options.js @@ -18,10 +18,25 @@ const defaultOptions = { offline: false, // Milliseconds to wait before aborting connection attempt connectTimeout: 9000, - // Whether or not to use C++ version of RakNet - useNativeRaknet: true, + // Specifies the raknet implementation to use + raknetBackend: 'raknet-native', // If using JS implementation of RakNet, should we use workers? (This only affects the client) useRaknetWorkers: true } -module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } +function validateOptions (options) { + if (!Versions[options.version]) { + console.warn('Supported versions', Versions) + throw Error(`Unsupported version ${options.version}`) + } + + options.protocolVersion = Versions[options.version] + if (options.protocolVersion < MIN_VERSION) { + throw new Error(`Protocol version < ${MIN_VERSION} : ${options.protocolVersion}, too old`) + } + this.compressionLevel = options.compressionLevel || 7 + if (options.useNativeRaknet === true) options.raknetBackend = 'raknet-native' + if (options.useNativeRaknet === false) options.raknetBackend = 'jsp-raknet' +} + +module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions, validateOptions } diff --git a/src/rak.js b/src/rak.js index 19f313c..7b1e2f1 100644 --- a/src/rak.js +++ b/src/rak.js @@ -3,21 +3,22 @@ const ConnWorker = require('./rakWorker') const { waitFor } = require('./datatypes/util') let Client, Server, PacketPriority, EncapsulatedPacket, PacketReliability, Reliability - class RakTimeout extends Error {}; -module.exports = nativeRaknet => { - if (nativeRaknet) { - try { - ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-native')) - return { RakServer: RakNativeServer, RakClient: RakNativeClient, RakTimeout } - } catch (e) { +module.exports = (backend) => { + try { + if (backend === 'jsp-raknet') { ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) - console.debug('[raknet] native not found, using js', e) - console.debug('You can suppress the error above by disabling `useNativeRaknet` in your options') + return { RakServer: RakJsServer, RakClient: RakJsClient, RakTimeout } } - } else { + // We need to explicitly name the require()s for bundlers + if (backend === 'raknet-node') ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-node')) + if (backend === 'raknet-native') ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-native')) + else ({ Client, Server, PacketPriority, PacketReliability } = require(backend)) + return { RakServer: RakNativeServer, RakClient: RakNativeClient, RakTimeout } + } catch (e) { ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) + console.debug('[raknet] ' + backend + ' library not found, defaulting to jsp-raknet. Correct the "raknetBackend" option to avoid this error.', e) } return { RakServer: RakJsServer, RakClient: RakJsClient, RakTimeout } } diff --git a/src/relay.js b/src/relay.js index bcb1295..8f8ba1b 100644 --- a/src/relay.js +++ b/src/relay.js @@ -182,6 +182,7 @@ class Relay extends Server { port: this.options.destination.port, onMsaCode: this.options.onMsaCode, profilesFolder: this.options.profilesFolder, + backend: this.options.backend, autoInitPlayer: false } diff --git a/src/server.js b/src/server.js index 50f3ddf..ffa5d77 100644 --- a/src/server.js +++ b/src/server.js @@ -12,7 +12,7 @@ class Server extends EventEmitter { this.options = { ...Options.defaultOptions, ...options } this.validateOptions() - this.RakServer = require('./rak')(this.options.useNativeRaknet).RakServer + this.RakServer = require('./rak')(this.options.raknetBackend).RakServer this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) @@ -25,15 +25,7 @@ class Server extends EventEmitter { } validateOptions () { - if (!Options.Versions[this.options.version]) { - console.warn('Supported versions', Options.Versions) - throw Error(`Unsupported version ${this.options.version}`) - } - this.options.protocolVersion = Options.Versions[this.options.version] - if (this.options.protocolVersion < Options.MIN_VERSION) { - throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) - } - this.compressionLevel = this.options.compressionLevel || 7 + Options.validateOptions(this.options) } onOpenConnection = (conn) => { diff --git a/test/proxy.js b/test/proxy.js index 2d94e05..a69b93c 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -1,7 +1,8 @@ const { createClient, createServer, Relay } = require('bedrock-protocol') const { sleep, waitFor } = require('../src/datatypes/util') -function proxyTest (version, timeout = 1000 * 40) { +function proxyTest (version, raknetBackend = 'raknet-node', timeout = 1000 * 40) { + console.log('with raknet backend', raknetBackend) return waitFor(res => { const SERVER_PORT = 19000 + ((Math.random() * 100) | 0) const CLIENT_PORT = 19000 + ((Math.random() * 100) | 0) @@ -9,6 +10,7 @@ function proxyTest (version, timeout = 1000 * 40) { host: '0.0.0.0', // optional port: SERVER_PORT, // optional offline: true, + raknetBackend, version // The server version }) @@ -34,14 +36,15 @@ function proxyTest (version, timeout = 1000 * 40) { destination: { host: '127.0.0.1', port: SERVER_PORT - } + }, + raknetBackend }) relay.conLog = console.debug relay.listen() console.debug('Proxy started', server.options.version) - const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true }) + const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true, raknetBackend }) console.debug('Client started') @@ -59,7 +62,7 @@ function proxyTest (version, timeout = 1000 * 40) { } if (!module.parent) { - proxyTest('1.16.220') + proxyTest('1.16.220', 'raknet-native') } module.exports = { proxyTest } diff --git a/test/vanilla.js b/test/vanilla.js index ac1cdda..e67bdaa 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -15,6 +15,7 @@ async function test (version) { port: 19130, username: 'Notch', version, + raknetBackend: 'raknet-node', offline: true }) From d1ba61978813ed65f8e3a26af2fa43300a2e1e06 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 10 Aug 2022 13:29:46 -0400 Subject: [PATCH 283/458] Fix proxy test waiting condition (#250) * Fix proxy test waiting condition * update test command * Update proxy.js * Update proxy.js * Update proxy.js --- package.json | 2 +- test/proxy.js | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index d29f497..ac756e1 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "build": "cd tools && node compileProtocol.js", - "test": "mocha --bail", + "test": "mocha --bail --exit", "pretest": "npm run lint", "lint": "standard", "vanillaServer": "node tools/startVanillaServer.js", diff --git a/test/proxy.js b/test/proxy.js index a69b93c..a1df25e 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -1,18 +1,19 @@ -const { createClient, createServer, Relay } = require('bedrock-protocol') +const { createClient, Server, Relay } = require('bedrock-protocol') const { sleep, waitFor } = require('../src/datatypes/util') function proxyTest (version, raknetBackend = 'raknet-node', timeout = 1000 * 40) { console.log('with raknet backend', raknetBackend) - return waitFor(res => { + return waitFor(async res => { const SERVER_PORT = 19000 + ((Math.random() * 100) | 0) const CLIENT_PORT = 19000 + ((Math.random() * 100) | 0) - const server = createServer({ + const server = new Server({ host: '0.0.0.0', // optional port: SERVER_PORT, // optional offline: true, raknetBackend, version // The server version }) + await server.listen() server.on('connect', client => { console.debug('Client has connected') @@ -40,16 +41,14 @@ function proxyTest (version, raknetBackend = 'raknet-node', timeout = 1000 * 40) raknetBackend }) relay.conLog = console.debug - relay.listen() + await relay.listen() console.debug('Proxy started', server.options.version) - const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true, raknetBackend }) - + const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true, raknetBackend, skipPing: true }) console.debug('Client started') - + client.on('error', console.log) client.on('packet', console.log) - client.on('disconnect', packet => { console.assert(packet.message === 'Hello world !') From 0c77d8e25240de60bba15b75e801992ba82bf78d Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 11 Aug 2022 21:16:32 -0400 Subject: [PATCH 284/458] 1.19.20 support (#251) * Update options.js * Update README.md --- README.md | 2 +- src/options.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0c2a1db..4333feb 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10, 1.19.20 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/src/options.js b/src/options.js index ae57abe..3289893 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.19.10' +const CURRENT_VERSION = '1.19.20' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) From e10c6133ec831c95a9d22b147905cbb1404a97bc Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 11 Aug 2022 21:49:53 -0400 Subject: [PATCH 285/458] Release 3.16.0 (#252) * Update package.json * Update HISTORY.md --- HISTORY.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 5528d70..0faaedb 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## 3.16.0 +* 1.19.20 support (#251) +* Add new raknet library option (raknet-node) (#211) @b23r0 + ## 3.15.0 * 1.19.10 support * Remove Realm fetch when joining via invite (#228) @LucienHH diff --git a/package.json b/package.json index ac756e1..3f4d628 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.15.0", + "version": "3.16.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 3a0071f0ef027b9c2f7a8b746b2c05b826de021b Mon Sep 17 00:00:00 2001 From: CleSucre <47931504+CleSucre@users.noreply.github.com> Date: Wed, 17 Aug 2022 05:25:24 +0200 Subject: [PATCH 286/458] Add fields from 1.19.20 to login chain data (#259) * Update Properties * Ci Fix --- src/handshake/login.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/handshake/login.js b/src/handshake/login.js index cf76d96..3c47e47 100644 --- a/src/handshake/login.js +++ b/src/handshake/login.js @@ -60,7 +60,10 @@ module.exports = (client, server, options) => { ThirdPartyName: client.profile.name, ThirdPartyNameOnly: false, - UIProfile: 0 + UIProfile: 0, + + IsEditorMode: false, + TrustedSkin: false } const customPayload = options.skinData || {} payload = { ...payload, ...customPayload } From ce06762dce92079426bdc99e0fc93dfe827faf27 Mon Sep 17 00:00:00 2001 From: Miniontoby <47940064+Miniontoby@users.noreply.github.com> Date: Wed, 24 Aug 2022 06:34:14 +0200 Subject: [PATCH 287/458] test: Add -u flag unzipping vanilla server (#262) * Fixed startVanillaServer.js I fixed the CI by editing startVanillaServer.js and adding -u to unzip and tar * Update startVanillaServer.js --- tools/startVanillaServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index cbd9870..4740bef 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -62,7 +62,7 @@ async function download (os, version, path = 'bds-') { await get(found, 'bds.zip') console.info('⚡ Unzipping') // Unzip server - if (process.platform === 'linux') cp.execSync('unzip bds.zip && chmod +777 ./bedrock_server') + if (process.platform === 'linux') cp.execSync('unzip -u bds.zip && chmod +777 ./bedrock_server') else cp.execSync('tar -xf bds.zip') return verStr } From c395f0b05b1ba820aa172995c19bb89ecd0fc9ba Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 24 Aug 2022 00:41:12 -0400 Subject: [PATCH 288/458] relay: Add multi-user login support (#258) * relay: add multi-user login support * relay: Fix close handling, connect username --- docs/API.md | 2 +- index.d.ts | 12 ++++++++++++ src/relay.js | 29 +++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/docs/API.md b/docs/API.md index 8d0b545..2f23b2d 100644 --- a/docs/API.md +++ b/docs/API.md @@ -170,7 +170,7 @@ For documentation on the protocol, and packets/fields see the [the protocol doc] ### Proxy docs -You can create a proxy ("Relay") to create a machine-in-the-middle (MITM) connection to a server. You can observe and intercept packets as they go through. The Relay is a server+client combo with some special packet handling and forwarding that takes care of the authentication and encryption on the server side. You'll be asked to login if `offline` is not specified once you connect. +You can create a proxy ("Relay") to create a machine-in-the-middle (MITM) connection to a server. You can observe and intercept packets as they go through. The Relay is a server+client combo with some special packet handling and forwarding that takes care of the authentication and encryption on the server side. Clients will be asked to login if `offline` is not specified on connection. ```js const { Relay } = require('bedrock-protocol') diff --git a/index.d.ts b/index.d.ts index e03ef61..140a05a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -131,6 +131,10 @@ declare module "bedrock-protocol" { * Close the connection. Already called by disconnect. Call this to manually close RakNet connection. */ close() + + on(event: 'login', cb: () => void) + on(event: 'join', cb: () => void) + on(event: 'close', cb: (reason: string) => void) } export class Server extends EventEmitter { @@ -161,6 +165,14 @@ declare module "bedrock-protocol" { } // Whether to enable chunk caching (default: false) enableChunkCaching?: boolean + + // Only allow one client to connect at a time (default: false) + forceSinge: boolean + + // Dispatched when a new client has logged in, and we need authentication + // tokens to join the backend server. Cached after the first login. + // If this is not specified, the client will be disconnected with a login prompt. + onMsaCode(data, client) } export class Relay extends Server { diff --git a/src/relay.js b/src/relay.js index 8f8ba1b..385ebf3 100644 --- a/src/relay.js +++ b/src/relay.js @@ -159,7 +159,7 @@ class Relay extends Server { constructor (options) { super(options) this.RelayPlayer = options.relayPlayer || RelayPlayer - this.forceSingle = true + this.forceSingle = options.forceSingle this.upstreams = new Map() this.conLog = debug this.enableChunkCaching = options.enableChunkCaching @@ -175,12 +175,18 @@ class Relay extends Server { const options = { authTitle: this.options.authTitle, offline: this.options.destination.offline ?? this.options.offline, - username: this.options.offline ? ds.profile.name : null, + username: this.options.offline ? ds.profile.name : ds.profile.xuid, version: this.options.version, realms: this.options.destination.realms, host: this.options.destination.host, port: this.options.destination.port, - onMsaCode: this.options.onMsaCode, + onMsaCode: (code) => { + if (this.options.onMsaCode) { + this.options.onMsaCode(code, ds) + } else { + ds.disconnect("It's your first time joining. Please sign in and reconnect to join this server:\n\n" + code.message) + } + }, profilesFolder: this.options.profilesFolder, backend: this.options.backend, autoInitPlayer: false @@ -213,6 +219,16 @@ class Relay extends Server { this.emit('join', /* client connected to proxy */ ds, /* backend server */ client) }) + client.on('error', (err) => { + ds.disconnect('Server error: ' + err.message) + debug(clientAddr, 'was disconnected because of error', err) + this.upstreams.delete(clientAddr.hash) + }) + client.on('close', (reason) => { + ds.disconnect('Backend server closed connection') + this.upstreams.delete(clientAddr.hash) + }) + this.upstreams.set(clientAddr.hash, client) } @@ -225,7 +241,7 @@ class Relay extends Server { this.conLog('closed upstream connection', clientAddr) } - // Called when a new player connects to our proxy server. Once the player has authenticted, + // Called when a new player connects to our proxy server. Once the player has authenticated, // we can open an upstream connection to the backend server. onOpenConnection = (conn) => { if (this.forceSingle && this.clientCount > 0) { @@ -240,6 +256,11 @@ class Relay extends Server { player.on('login', () => { this.openUpstreamConnection(player, conn.address) }) + player.on('close', (reason) => { + this.conLog('player disconnected', conn.address, reason) + this.clientCount-- + delete this.clients[conn.address] + }) } } From f5c91ba1c920860162389eb2fcbd5871c4b6467c Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 24 Aug 2022 00:50:01 -0400 Subject: [PATCH 289/458] Fix nbt encoding size on single null tag NBT (#264) --- src/datatypes/minecraft.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/datatypes/minecraft.js b/src/datatypes/minecraft.js index a52d9c8..5b93bc0 100644 --- a/src/datatypes/minecraft.js +++ b/src/datatypes/minecraft.js @@ -39,17 +39,21 @@ function sizeOfNbt (value) { function readNbtLE (buffer, offset) { const r = protoLE.read(buffer, offset, 'nbt') - if (r.value.type === 'end') return { value: r.value, size: 0 } + // End size is 3 for some reason + if (r.value.type === 'end') return { value: r.value, size: 1 } return r } function writeNbtLE (value, buffer, offset) { - if (value.type === 'end') return offset + if (value.type === 'end') { + buffer.writeInt8(0, offset) + return offset + 1 + } return protoLE.write(value, buffer, offset, 'nbt') } function sizeOfNbtLE (value) { - if (value.type === 'end') return 0 + if (value.type === 'end') return 1 return protoLE.sizeOf(value, 'nbt') } From 262a4eee00fd0cbce7280b934c8413b1e971730c Mon Sep 17 00:00:00 2001 From: extremeheat Date: Wed, 24 Aug 2022 04:45:44 -0400 Subject: [PATCH 290/458] Release 3.17.0 (#265) --- HISTORY.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 0faaedb..b6c84f2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,9 @@ +## 3.17.0 +* relay: Add multi-user login support (#258) +* Add fields from 1.19.20 to login chain data (#259) @CleSucre +* Fix nbt encoding size on single null tag NBT (#264) +* test: Add -u flag unzipping vanilla server (#262) + ## 3.16.0 * 1.19.20 support (#251) * Add new raknet library option (raknet-node) (#211) @b23r0 diff --git a/package.json b/package.json index 3f4d628..860ba94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.16.0", + "version": "3.17.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From 7264cbe31267196994706d55fa85394c3c794f7e Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Aug 2022 12:06:57 -0400 Subject: [PATCH 291/458] 1.19.21 support (#266) * Update options.js * Update README.md --- README.md | 2 +- src/options.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4333feb..7acad89 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10, 1.19.20 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10, 1.19.20, 1.19.21 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/src/options.js b/src/options.js index 3289893..e081536 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.19.20' +const CURRENT_VERSION = '1.19.21' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) From 8913d48f42cd1a89ed78f1a99426dbefb2667927 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Aug 2022 12:49:43 -0400 Subject: [PATCH 292/458] Release 3.18.0 (#267) * Update HISTORY.md * Update package.json --- HISTORY.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index b6c84f2..eef8822 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,6 @@ +## 3.18.0 +* 1.19.21 support (#266) + ## 3.17.0 * relay: Add multi-user login support (#258) * Add fields from 1.19.20 to login chain data (#259) @CleSucre diff --git a/package.json b/package.json index 860ba94..bcd4e44 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.17.0", + "version": "3.18.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From ffe0fb42b5849d63ff8f8315ff4fb377d0491219 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 25 Aug 2022 14:05:14 -0400 Subject: [PATCH 293/458] Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 140a05a..91e491b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.19.21' | '1.19.20' | '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } From 9d717744b6441791f67c680d3bef086d3fd2514d Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 1 Sep 2022 15:37:45 -0400 Subject: [PATCH 294/458] Add 1.19.22 to types --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 91e491b..54a44be 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.19.21' | '1.19.20' | '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.19.22' | '1.19.21' | '1.19.20' | '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } From bf2de1dcf4f44e33f72a06480aa851055de1eab8 Mon Sep 17 00:00:00 2001 From: Stephen O'Connor Date: Sun, 11 Sep 2022 20:19:32 -0700 Subject: [PATCH 295/458] Add Get-AppxPackage command to FAQ.md (#276) --- docs/FAQ.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 556eedf..852d884 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -5,6 +5,21 @@ This issue occurs due to loopback restrictions on Windows 10 UWP apps. To lift t ```ps CheckNetIsolation LoopbackExempt -a -n="Microsoft.MinecraftUWP_8wekyb3d8bbwe" ``` + +If you are running a preview or beta release, you can run the following command to unlock that version: + +```ps +CheckNetIsolation LoopbackExempt -a -n="Microsoft.MinecraftWindowsBeta" +``` + +If that still doesn't work, you can inspect what Minecraft versions are available on your system with: + +```ps +Get-AppxPackage -AllUsers | Where Name -Match ".*Minecraft.*" | Select Name,InstallLocation,PackageFullName +``` + +Use the PackageFullName field in place of the `Microsoft.MinecraftUWP_8wekyb3d8bbwe` for the command above. + ## Kicked during login -Some servers can kick you if you don't set `authTitle` as explained in the README. \ No newline at end of file +Some servers can kick you if you don't set `authTitle` as explained in the README. From d3a085a2606a0424d6c8e584570e0cc429f01c7f Mon Sep 17 00:00:00 2001 From: Stephen O'Connor Date: Wed, 14 Sep 2022 19:31:31 -0700 Subject: [PATCH 296/458] Add Port Redirect Functionality (#278) --- src/createClient.js | 7 ++++++- src/server/advertisement.js | 12 ++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/createClient.js b/src/createClient.js index a642c7c..7fe0d9b 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -19,7 +19,12 @@ function createClient (options) { ping(client.options).then(ad => { const adVersion = ad.version?.split('.').slice(0, 3).join('.') // Only 3 version units client.options.version = options.version ?? (Options.Versions[adVersion] ? adVersion : Options.CURRENT_VERSION) - client.conLog?.(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') + + if (ad.port) { + client.options.port = ad.port + } + + client.conLog?.(`Connecting to ${client.options.host}:${client.options.port} ${ad.motd} (${ad.levelName}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') client.init() }).catch(e => client.emit('error', e)) } diff --git a/src/server/advertisement.js b/src/server/advertisement.js index 3e069db..ff5f08a 100644 --- a/src/server/advertisement.js +++ b/src/server/advertisement.js @@ -7,6 +7,9 @@ class ServerAdvertisement { playersMax = 5 gamemode = 'Creative' serverId = '0' + gamemodeId = 1 + port = undefined + portV6 = undefined constructor (obj, version = CURRENT_VERSION) { if (obj?.name) obj.motd = obj.name @@ -16,8 +19,13 @@ class ServerAdvertisement { } fromString (str) { - const [header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode] = str.split(';') - Object.assign(this, { header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode }) + const [header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode, gamemodeId, port, portV6] = str.split(';') + Object.assign(this, { header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode, gamemodeId, port, portV6 }) + for (const numeric of ['playersOnline', 'playersMax', 'gamemodeId', 'port', 'portV6']) { + if (this[numeric] !== undefined) { + this[numeric] = parseInt(this[numeric]) + } + } return this } From 99153c2de296a46880f637f9c10f8b6dc9dd66fd Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 22 Sep 2022 15:14:49 -0400 Subject: [PATCH 297/458] Add option for port redirection, fix Realm handling (#282) * Port Redirect Fix - Only Redirect on Unspecified Port * Update to use `followPort` option Co-authored-by: Stephen O'Connor --- docs/API.md | 3 ++- index.d.ts | 2 ++ src/createClient.js | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/API.md b/docs/API.md index 2f23b2d..97b616f 100644 --- a/docs/API.md +++ b/docs/API.md @@ -16,8 +16,9 @@ Returns a `Client` instance and connects to the server. | connectTimeout | *optional* | default to **9000ms**. How long to wait in milliseconds while trying to connect to server. | | onMsaCode | *optional* | Callback called when signing in with a microsoft account with device code auth, `data` is an object documented [here](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code#device-authorization-response) | | profilesFolder | *optional* | Where to store cached authentication tokens. Defaults to .minecraft, or the node_modules folder if not found. | -| autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | | skipPing | *optional* | Whether pinging the server to check its version should be skipped. | +| followPort | *optional* | Update the options' port parameter to match the port broadcast on the server's ping data (default to true if `realms` not specified) | +| autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | | conLog | *optional* | Where to log connection information (server join, kick messages to). Defaults to console.log, set to `null` to not log anywhere. | | raknetBackend | *optional* | Specifies the raknet implementation to use. Possible options are 'raknet-native' (default, original C++ implementation), 'jsp-raknet' (JS port), and 'raknet-node' (Rust port). Please note when using the non-JS implementation you may the need approporate build tools on your system (for example a C++ or Rust compiler). | | compressionLevel | *optional* | What zlib compression level to use, default to **7** | diff --git a/index.d.ts b/index.d.ts index 54a44be..a439d28 100644 --- a/index.d.ts +++ b/index.d.ts @@ -39,6 +39,8 @@ declare module "bedrock-protocol" { connectTimeout?: number // whether to skip initial ping and immediately connect skipPing?: boolean + // Update the options' port parameter to match the port broadcast on the server's ping data (default to true if `realms` not specified) + followPort?: boolean // where to log connection information to (default to console.log) conLog? // used to join a Realm instead of supplying a host/port diff --git a/src/createClient.js b/src/createClient.js index 7fe0d9b..17b9d31 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -9,7 +9,7 @@ const auth = require('./client/auth') /** @param {{ version?: number, host: string, port?: number, connectTimeout?: number, skipPing?: boolean }} options */ function createClient (options) { assert(options) - const client = new Client({ port: 19132, ...options, delayedInit: true }) + const client = new Client({ port: 19132, followPort: !options.realms, ...options, delayedInit: true }) function onServerInfo () { client.on('connect_allowed', () => connect(client)) @@ -20,11 +20,11 @@ function createClient (options) { const adVersion = ad.version?.split('.').slice(0, 3).join('.') // Only 3 version units client.options.version = options.version ?? (Options.Versions[adVersion] ? adVersion : Options.CURRENT_VERSION) - if (ad.port) { + if (ad.port && options.followPort) { client.options.port = ad.port } - client.conLog?.(`Connecting to ${client.options.host}:${client.options.port} ${ad.motd} (${ad.levelName}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '') + client.conLog?.(`Connecting to ${client.options.host}:${client.options.port} ${ad.motd} (${ad.levelName}), version ${ad.version} ${client.options.version !== ad.version ? ` (as ${client.options.version})` : ''}`) client.init() }).catch(e => client.emit('error', e)) } From 30c583fcf3bf9f86764cedc616afd434343a8a73 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Thu, 22 Sep 2022 22:47:17 -0400 Subject: [PATCH 298/458] Release 3.19.0 (#283) * Update HISTORY.md * Update package.json * Remove viewer example * Update HISTORY.md --- HISTORY.md | 6 + examples/viewer/client/BotProvider.js | 58 ----- examples/viewer/client/BotViewer.js | 150 ----------- examples/viewer/client/Chunk.js | 18 -- examples/viewer/client/ClientProvider.js | 114 --------- examples/viewer/client/ProxyProvider.js | 89 ------- examples/viewer/client/app.css | 22 -- examples/viewer/client/index.html | 22 -- examples/viewer/client/index.js | 4 - examples/viewer/client/movements.js | 304 ----------------------- examples/viewer/client/preload.js | 9 - examples/viewer/client/util.js | 22 -- examples/viewer/client/worker.js | 2 - examples/viewer/index.js | 44 ---- examples/viewer/package.json | 15 -- package.json | 2 +- 16 files changed, 7 insertions(+), 874 deletions(-) delete mode 100644 examples/viewer/client/BotProvider.js delete mode 100644 examples/viewer/client/BotViewer.js delete mode 100644 examples/viewer/client/Chunk.js delete mode 100644 examples/viewer/client/ClientProvider.js delete mode 100644 examples/viewer/client/ProxyProvider.js delete mode 100644 examples/viewer/client/app.css delete mode 100644 examples/viewer/client/index.html delete mode 100644 examples/viewer/client/index.js delete mode 100644 examples/viewer/client/movements.js delete mode 100644 examples/viewer/client/preload.js delete mode 100644 examples/viewer/client/util.js delete mode 100644 examples/viewer/client/worker.js delete mode 100644 examples/viewer/index.js delete mode 100644 examples/viewer/package.json diff --git a/HISTORY.md b/HISTORY.md index eef8822..8ac1d94 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,9 @@ +## 3.19.0 +* Add option for port redirection, fix Realm handling (#282) +* Add Port Redirect Functionality (#278) @stevarino +* Add Get-AppxPackage command to FAQ.md (#276) @stevarino +* Remove viewer example + ## 3.18.0 * 1.19.21 support (#266) diff --git a/examples/viewer/client/BotProvider.js b/examples/viewer/client/BotProvider.js deleted file mode 100644 index 4d23377..0000000 --- a/examples/viewer/client/BotProvider.js +++ /dev/null @@ -1,58 +0,0 @@ -const { Version } = require('bedrock-provider') -const { WorldView } = require('prismarine-viewer/viewer') -const World = require('prismarine-world')() -const ChunkColumn = require('./Chunk')() -const { MovementManager } = require('./movements') - -class BotProvider extends WorldView { - chunks = {} - lastSentPos - positionUpdated = true - - constructor () { - super() - this.connect() - this.listenToBot() - this.world = new World() - this.movements = new MovementManager(this) - - this.onKeyDown = () => {} - this.onKeyUp = () => {} - - this.removeAllListeners('mouseClick') - } - - raycast () { - // TODO : fix - } - - get entity () { return this.movements.player.entity } - - handleChunk (packet, render = true) { - const hash = (packet.x << 4) + ',' + (packet.z << 4) - if (this.loadChunk[hash]) return - const cc = new ChunkColumn(Version.v1_4_0, packet.x, packet.z) - cc.networkDecodeNoCache(packet.payload, packet.sub_chunk_count).then(() => { - this.loadedChunks[hash] = true - this.world.setColumn(packet.x, packet.z, cc) - const chunk = cc.serialize() - // console.log('Chunk', chunk) - if (render) this.emitter.emit('loadChunk', { x: packet.x << 4, z: packet.z << 4, chunk }) - }) - } - - updatePlayerCamera (id, position, yaw, pitch, updateState) { - this.emit('playerMove', id, { position, yaw, pitch }) - - if (updateState) { - this.movements.updatePosition(position, yaw, pitch) - } - } - - stopBot () { - clearInterval(this.tickLoop) - this.movements.stopPhys() - } -} - -module.exports = { BotProvider } diff --git a/examples/viewer/client/BotViewer.js b/examples/viewer/client/BotViewer.js deleted file mode 100644 index 57f9d16..0000000 --- a/examples/viewer/client/BotViewer.js +++ /dev/null @@ -1,150 +0,0 @@ -/* global THREE */ -const { Viewer, MapControls } = require('prismarine-viewer/viewer') -// const { Vec3 } = require('vec3') -const { ClientProvider } = require('./ClientProvider') -// const { ProxyProvider } = require('./ProxyProvider') -global.THREE = require('three') - -const MCVER = '1.16.1' - -class BotViewer { - start () { - this.bot = new ClientProvider() - // this.bot = new ProxyProvider() - // Create three.js context, add to page - this.renderer = new THREE.WebGLRenderer() - this.renderer.setPixelRatio(window.devicePixelRatio || 1) - this.renderer.setSize(window.innerWidth, window.innerHeight) - document.body.appendChild(this.renderer.domElement) - - // Create viewer - this.viewer = new Viewer(this.renderer) - this.viewer.setVersion(MCVER) - // Attach controls to viewer - this.controls = new MapControls(this.viewer.camera, this.renderer.domElement) - // Enable damping (inertia) on movement - this.controls.enableDamping = true - this.controls.dampingFactor = 0.09 - console.info('Registered handlers') - // Link WorldView and Viewer - this.viewer.listen(this.bot) - - this.bot.on('spawn', ({ position, firstPerson }) => { - // Initialize viewer, load chunks - this.bot.init(position) - // Start listening for keys - this.registerBrowserEvents() - - if (firstPerson && this.bot.movements) { - this.viewer.camera.position.set(position.x, position.y, position.z) - this.firstPerson = true - this.controls.enabled = false - } else { - this.viewer.camera.position.set(position.x, position.y, position.z) - } - }) - - this.bot.on('playerMove', (id, pos) => { - if (this.firstPerson && id < 10) { - this.setFirstPersonCamera(pos) - return - } - - window.viewer.viewer.entities.update({ - name: 'player', - id, - pos: pos.position, - width: 0.6, - height: 1.8, - yaw: pos.yaw, - pitch: pos.pitch - }) - }) - - const oldFov = this.viewer.camera.fov - const sprintFov = this.viewer.camera.fov + 20 - const sneakFov = this.viewer.camera.fov - 10 - - const onSprint = () => { - this.viewer.camera.fov = sprintFov - this.viewer.camera.updateProjectionMatrix() - } - - const onSneak = () => { - this.viewer.camera.fov = sneakFov - this.viewer.camera.updateProjectionMatrix() - } - - const onRelease = () => { - this.viewer.camera.fov = oldFov - this.viewer.camera.updateProjectionMatrix() - } - - this.bot.on('startSprint', onSprint) - this.bot.on('startSneak', onSneak) - this.bot.on('stopSprint', onRelease) - this.bot.on('stopSneak', onRelease) - - this.controls.update() - - // Browser animation loop - const animate = () => { - window.requestAnimationFrame(animate) - if (this.controls && !this.firstPerson) this.controls.update() - this.viewer.update() - this.renderer.render(this.viewer.scene, this.viewer.camera) - } - animate() - - window.addEventListener('resize', () => { - this.viewer.camera.aspect = window.innerWidth / window.innerHeight - this.viewer.camera.updateProjectionMatrix() - this.renderer.setSize(window.innerWidth, window.innerHeight) - }) - } - - onMouseMove = (e) => { - if (this.firstPerson) { - this.bot.entity.pitch -= e.movementY * 0.005 - this.bot.entity.yaw -= e.movementX * 0.004 - } - } - - onPointerLockChange = () => { - const e = this.renderer.domElement - if (document.pointerLockElement === e) { - e.parentElement.addEventListener('mousemove', this.onMouseMove, { passive: true }) - } else { - e.parentElement.removeEventListener('mousemove', this.onMouseMove, false) - } - } - - onMouseDown = () => { - if (this.firstPerson && !document.pointerLockElement) { - this.renderer.domElement.requestPointerLock() - } - } - - registerBrowserEvents () { - const e = this.renderer.domElement - e.parentElement.addEventListener('keydown', this.bot.onKeyDown) - e.parentElement.addEventListener('keyup', this.bot.onKeyUp) - e.parentElement.addEventListener('mousedown', this.onMouseDown) - document.addEventListener('pointerlockchange', this.onPointerLockChange, false) - } - - unregisterBrowserEvents () { - const e = this.renderer.domElement - e.parentElement.removeEventListener('keydown', this.bot.onKeyDown) - e.parentElement.removeEventListener('keyup', this.bot.onKeyUp) - e.parentElement.removeEventListener('mousemove', this.onMouseMove) - e.parentElement.removeEventListener('mousedown', this.onMouseDown) - document.removeEventListener('pointerlockchange', this.onPointerLockChange, false) - } - - setFirstPersonCamera (entity) { - this.viewer.setFirstPersonCamera(entity.position, entity.yaw, entity.pitch * 2) - } -} - -module.exports = { BotViewer } diff --git a/examples/viewer/client/Chunk.js b/examples/viewer/client/Chunk.js deleted file mode 100644 index 7733cc3..0000000 --- a/examples/viewer/client/Chunk.js +++ /dev/null @@ -1,18 +0,0 @@ -const { ChunkColumn } = require('bedrock-provider') - -const Block = require('prismarine-block')('1.16.1') - -class ChunkColumnWrapped extends ChunkColumn { // pchunk compatiblity wrapper - // Block access - setBlockStateId (pos, stateId) { - super.setBlock(pos.x, pos.y, pos.z, Block.fromStateId(stateId)) - } - - getBlockStateId (pos) { - return super.getBlock(pos.x, pos.y, pos.z)?.stateId - } -} - -module.exports = (version) => { - return ChunkColumnWrapped -} diff --git a/examples/viewer/client/ClientProvider.js b/examples/viewer/client/ClientProvider.js deleted file mode 100644 index 73d7b8f..0000000 --- a/examples/viewer/client/ClientProvider.js +++ /dev/null @@ -1,114 +0,0 @@ -const { Client } = require('bedrock-protocol') -const { BotProvider } = require('./BotProvider') - -const controlMap = { - forward: ['KeyW', 'KeyZ'], - back: 'KeyS', - left: ['KeyA', 'KeyQ'], - right: 'KeyD', - sneak: 'ShiftLeft', - jump: 'Space' -} - -class ClientProvider extends BotProvider { - downKeys = new Set() - - connect () { - const client = new Client({ host: '127.0.0.1', version: '1.16.210', username: 'notch', offline: true, port: 19132, connectTimeout: 100000 }) - - client.once('resource_packs_info', (packet) => { - client.write('resource_pack_client_response', { - response_status: 'completed', - resourcepackids: [] - }) - - client.once('resource_pack_stack', (stack) => { - client.write('resource_pack_client_response', { - response_status: 'completed', - resourcepackids: [] - }) - }) - - client.queue('client_cache_status', { enabled: false }) - client.queue('request_chunk_radius', { chunk_radius: 1 }) - - this.heartbeat = setInterval(() => { - client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) - }) - }) - - this.client = client - } - - close () { - this.client?.close() - } - - listenToBot () { - this.client.on('connect', () => { - console.log('Bot has connected!') - }) - this.client.on('start_game', packet => { - this.updatePosition(packet.player_position) - this.movements.init('server', packet.player_position, /* vel */ null, packet.rotation.z || 0, packet.rotation.x || 0, 0) - }) - - this.client.on('spawn', () => { - this.movements.startPhys() - // server allows client to render chunks & spawn in world - this.emit('spawn', { position: this.lastPos, firstPerson: true }) - - this.tickLoop = setInterval(() => { - this.client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n }) - }) - }) - - this.client.on('level_chunk', packet => { - this.handleChunk(packet) - }) - - this.client.on('move_player', packet => { - if (packet.runtime_id === this.client.entityId) { - this.movements.updatePosition(packet.position, packet.yaw, packet.pitch, packet.head_yaw, packet.tick) - } - }) - - this.client.on('set_entity_motion', packet => { - // if (packet.runtime_id === this.client.entityId) this.updatePosition(packet.position) - }) - - this.client.on('tick_sync', (packet) => { - this.lastTick = packet.response_time - }) - } - - onKeyDown = (evt) => { - const code = evt.code - for (const control in controlMap) { - if (controlMap[control].includes(code)) { - this.movements.setControlState(control, true) - break - } - if (evt.ctrlKey) { - this.movements.setControlState('sprint', true) - } - } - this.downKeys.add(code) - } - - onKeyUp = (evt) => { - const code = evt.code - if (code === 'ControlLeft' && this.downKeys.has('ControlLeft')) { - this.movements.setControlState('sprint', false) - } - for (const control in controlMap) { - if (controlMap[control].includes(code)) { - this.movements.setControlState(control, false) - break - } - } - this.downKeys.delete(code) - } -} - -module.exports = { ClientProvider } diff --git a/examples/viewer/client/ProxyProvider.js b/examples/viewer/client/ProxyProvider.js deleted file mode 100644 index 8ffc599..0000000 --- a/examples/viewer/client/ProxyProvider.js +++ /dev/null @@ -1,89 +0,0 @@ -const { Relay } = require('bedrock-protocol') -const { BotProvider } = require('./BotProvider') -const { diff } = require('./util') - -class ProxyProvider extends BotProvider { - lastPlayerMovePacket - - connect () { - const proxy = new Relay({ - host: '0.0.0.0', - port: 19130, - // logging: true, - destination: { - host: '127.0.0.1', - port: 19132 - } - }) - proxy.listen() - console.info('Waiting for connect') - - proxy.on('join', (client, server) => { - client.on('clientbound', ({ name, params }) => { - if (name === 'level_chunk') { - this.handleChunk(params, true) - } else if (name === 'start_game') { - this.movements.init('', params.player_position, null, params.rotation.z, params.rotation.x, 0) - } else if (name === 'play_status') { - this.movements.startPhys() - this.emit('spawn', { position: this.movements.lastPos, firstPerson: true }) - console.info('Started physics!') - } else if (name === 'move_player') { - console.log('move_player', params) - this.movements.updatePosition(params.position, params.yaw, params.pitch, params.head_yaw, params.tick) - } - - if (name.includes('entity') || name.includes('network_chunk_publisher_update') || name.includes('tick') || name.includes('level')) return - console.log('CB', name) - }) - - client.on('serverbound', ({ name, params }) => { - // { name, params } - if (name === 'player_auth_input') { - this.movements.pushInputState(params.input_data, params.yaw, params.pitch) - this.movements.pushCameraControl(params, 1) - - // Log Movement deltas - { // eslint-disable-line - this.lastMovePacket = params - if (this.firstPlayerMovePacket) { - const id = diff(this.firstPlayerMovePacket.input_data, params.input_data) - const md = diff(this.firstPlayerMovePacket.move_vector, params.move_vector) - const dd = diff(this.firstPlayerMovePacket.delta, params.delta) - if (id || md) { - if (globalThis.logging) console.log('Move', params.position, id, md, dd) - globalThis.movements ??= [] - globalThis.movements.push(params) - } - } - if (!this.firstPlayerMovePacket) { - this.firstPlayerMovePacket = params - for (const key in params.input_data) { - params.input_data[key] = false - } - params.input_data._value = 0n - params.move_vector = { x: 0, z: 0 } - params.delta = { x: 0, y: 0, z: 0 } - } - } - } else if (!name.includes('tick') && !name.includes('level')) { - console.log('Sending', name) - } - }) - console.info('Client and Server Connected!') - }) - - this.proxy = proxy - } - - listenToBot () { - - } - - close () { - this.proxy?.close() - } -} - -module.exports = { ProxyProvider } -globalThis.logging = true diff --git a/examples/viewer/client/app.css b/examples/viewer/client/app.css deleted file mode 100644 index 44c6bea..0000000 --- a/examples/viewer/client/app.css +++ /dev/null @@ -1,22 +0,0 @@ -html { - overflow: hidden; -} - -html, body { - height: 100%; - margin: 0; - padding: 0; - font-family: sans-serif; -} - -a { - text-decoration: none; -} - -canvas { - height: 100%; - width: 100%; - font-size: 0; - margin: 0; - padding: 0; -} diff --git a/examples/viewer/client/index.html b/examples/viewer/client/index.html deleted file mode 100644 index 537be49..0000000 --- a/examples/viewer/client/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Prismarine Viewer - - - - - -
-
Prismarine Viewer
- -
-
Connecting to 127.0.0.1, port 19132...
-
-
- - - - - \ No newline at end of file diff --git a/examples/viewer/client/index.js b/examples/viewer/client/index.js deleted file mode 100644 index 1b0334d..0000000 --- a/examples/viewer/client/index.js +++ /dev/null @@ -1,4 +0,0 @@ -const { BotViewer } = require('./BotViewer') - -global.viewer = new BotViewer() -global.viewer.start() diff --git a/examples/viewer/client/movements.js b/examples/viewer/client/movements.js deleted file mode 100644 index 92b6630..0000000 --- a/examples/viewer/client/movements.js +++ /dev/null @@ -1,304 +0,0 @@ -const { Physics, PlayerState } = require('prismarine-physics') -const { performance } = require('perf_hooks') -const { d2r, r2d } = require('./util') -const vec3 = require('vec3') - -const PHYSICS_INTERVAL_MS = 50 -const PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000 -const AXES = ['forward', 'back', 'left', 'right'] - -class MovementManager { - // Server auth movement : we send inputs, server calculates position & sends back - serverMovements = false - - constructor (bot) { - this.bot = bot - this.world = bot.world - // Physics tick - this.tick = 0n - } - - get lastPos () { return this.player.entity.position.clone() } - set lastPos (newPos) { this.player.entity.position.set(newPos.x, newPos.y, newPos.z) } - get lastRot () { return vec3(this.player.entity.yaw, this.player.entity.pitch, this.player.entity.headYaw) } - set lastRot (rot) { - if (!isNaN(rot.x)) this.player.entity.yaw = rot.x - if (!isNaN(rot.y)) this.player.entity.pitch = rot.y - if (!isNaN(rot.z)) this.player.entity.headYaw = rot.z - } - - // Ask the server to be in a new position - requestPosition (time, inputState) { - const positionUpdated = !this.lastSentPos || !this.lastPos.equals(this.lastSentPos) - const rotationUpdated = !this.lastSentRot || !this.lastRot.equals(this.lastSentRot) - - if (positionUpdated || rotationUpdated) { - this.lastSentPos = this.lastPos.clone() - // console.log('We computed', this.lastPos) - this.bot.updatePlayerCamera(2, this.lastSentPos, this.playerState.yaw, this.playerState.pitch || this.player.entity.pitch) - if (this.serverMovements) { - globalThis.movePayload = { - pitch: r2d(this.player.entity.pitch), - yaw: r2d(this.player.entity.yaw), - position: { - x: this.lastPos.x, - y: this.lastPos.y + 1.62, - z: this.lastPos.z - }, - move_vector: { // Minecraft coords, N: Z+1, S: Z-1, W: X+1, E: X-1 - x: inputState.left ? 1 : (inputState.right ? -1 : 0), - z: inputState.up ? 1 : (inputState.down ? -1 : 0) - }, - head_yaw: r2d(this.player.entity.yaw), - input_data: inputState, - input_mode: 'mouse', - play_mode: 'screen', - tick: this.tick, - delta: this.lastSentPos?.minus(this.lastPos) ?? { x: 0, y: 0, z: 0 } - } - this.bot.client.queue('player_auth_input', globalThis.movePayload) - } - - this.positionUpdated = false - this.lastSentPos = this.lastPos - this.lastSentRot = this.lastRot - } - } - - init (movementAuthority, position, velocity, yaw = 0, pitch = 0, headYaw = 0) { - if (movementAuthority.includes('server')) { - this.serverMovements = true - } - this.player = { - version: '1.16.1', - inventory: { - slots: [] - }, - entity: { - effects: {}, - position: vec3(position), - velocity: vec3(velocity), - onGround: false, - isInWater: false, - isInLava: false, - isInWeb: false, - isCollidedHorizontally: false, - isCollidedVertically: false, - yaw, - pitch, - headYaw // bedrock - }, - events: { // Control events to send next tick - startSprint: false, - stopSprint: false, - startSneak: false, - stopSneak: false - }, - sprinting: false, - jumpTicks: 0, - jumpQueued: false, - downJump: false - } - - const mcData = require('minecraft-data')('1.16.1') - this.physics = Physics(mcData, this.world) - this.controls = { - forward: false, - back: false, - left: false, - right: false, - jump: false, - sprint: false, - sneak: false - } - } - - // This function should be executed each tick (every 0.05 seconds) - // How it works: https://gafferongames.com/post/fix_your_timestep/ - timeAccumulator = 0 - lastPhysicsFrameTime = null - inputQueue = [] - doPhysics () { - const now = performance.now() - const deltaSeconds = (now - this.lastPhysicsFrameTime) / 1000 - this.lastPhysicsFrameTime = now - - this.timeAccumulator += deltaSeconds - - while (this.timeAccumulator >= PHYSICS_TIMESTEP) { - const q = this.inputQueue.shift() - if (q) { - Object.assign(this.playerState.control, q) - if (!isNaN(q.yaw)) this.player.entity.yaw = q.yaw - if (!isNaN(q.pitch)) this.player.entity.pitch = q.pitch - } - this.playerState = new PlayerState(this.player, this.controls) - this.physics.simulatePlayer(this.playerState, this.world.sync).apply(this.player) - this.lastPos = this.playerState.pos - this.requestPosition(PHYSICS_TIMESTEP, { - ascend: false, - descend: false, - // Players bob up and down in water, north jump is true when going up. - // In water this is only true after the player has reached max height before bobbing back down. - north_jump: this.player.jumpTicks > 0, // Jump - jump_down: this.controls.jump, // Jump - sprint_down: this.controls.sprint, - change_height: false, - jumping: this.controls.jump, // Jump - auto_jumping_in_water: false, - sneaking: false, - sneak_down: false, - up: this.controls.forward, - down: this.controls.back, - left: this.controls.right, - right: this.controls.left, - up_left: false, - up_right: false, - want_up: this.controls.jump, // Jump - want_down: false, - want_down_slow: false, - want_up_slow: false, - sprinting: false, - ascend_scaffolding: false, - descend_scaffolding: false, - sneak_toggle_down: false, - persist_sneak: false, - start_sprinting: this.player.events.startSprint || false, - stop_sprinting: this.player.events.stopSprint || false, - start_sneaking: this.player.events.startSneak || false, - stop_sneaking: this.player.events.stopSneak || false, - // Player is Update Aqatic swimming - start_swimming: false, - // Player stops Update Aqatic swimming - stop_swimming: false, - start_jumping: this.player.jumpTicks === 1, // Jump - start_gliding: false, - stop_gliding: false - }) - this.timeAccumulator -= PHYSICS_TIMESTEP - this.tick++ - } - } - - startPhys () { - console.log('Start phys') - this.physicsLoop = setInterval(() => { - this.doPhysics() - }, PHYSICS_INTERVAL_MS) - } - - get sprinting () { - return this.player.sprinting - } - - set sprinting (val) { - this.player.events.startSprint = val - this.player.events.stopSprint = !val - if (val && !this.player.sprinting) { - this.bot.emit('startSprint') - } else { - this.bot.emit('stopSprint') - } - this.player.sprinting = val - } - - _lastInput = { control: '', time: 0 } - - /** - * Sets the active control state and also keeps track of key toggles. - * @param {'forward' | 'back' | 'left' | 'right' | 'jump' | 'sprint' | 'sneak'} control - * @param {boolean} state - */ - setControlState (control, state, time = Date.now()) { - // HACK ! switch left and right, fixes control issue - if (control === 'left') control = 'right' - else if (control === 'right') control = 'left' - - if (this.controls[control] === state) return - - const isAxis = AXES.includes(control) - let hasOtherAxisKeyDown = false - for (const c of AXES) { - if (this.controls[c] && c !== control) { - hasOtherAxisKeyDown = true - } - } - - if (control === 'sprint') { - if (state && hasOtherAxisKeyDown) { // sprint down + a axis movement key - this.sprinting = true - } else if ((!state || !hasOtherAxisKeyDown) && this.sprinting) { // sprint up or movement key up & current sprinting - this.bot.emit('stopSprint') - this.sprinting = false - } - } else if (isAxis && this.controls.sprint) { - if (!state && !hasOtherAxisKeyDown) { - this.sprinting = false - } else if (state && !hasOtherAxisKeyDown) { - this.sprinting = true - } - } else if (control === 'sneak') { - if (state) { - this.player.events.startSneak = true - this.bot.emit('startSneak') - } else { - this.player.events.stopSneak = true - this.bot.emit('stopSneak') - } - } else if (control === 'forward' && this._lastInput.control === 'forward' && (Date.now() - this._lastInput.time) < 100 && !this.controls.sprint) { - // double tap forward within 0.5 seconds, toggle sprint - // this.controls.sprint = true - // this.sprinting = true - } - - this._lastInput = { control, time } - this.controls[control] = state - } - - stopPhys () { - clearInterval(this.physicsLoop) - } - - // Called when a proxy player sends a PlayerInputPacket. We need to apply these inputs tick-by-tick - // as these packets are sent by the client every tick. - pushInputState (state, yaw, pitch) { - const yawRad = d2r(yaw) - const pitchRad = d2r(pitch) - this.inputQueue.push({ - forward: state.up, - back: state.down, // TODO: left and right switched ??? - left: state.right, - right: state.left, - jump: state.jump_down, - sneak: state.sneak_down, - yaw: yawRad, - pitch: pitchRad - }) - // debug - globalThis.debugYaw = [yaw, yawRad] - } - - // Called when a proxy player sends a PlayerInputPacket. We need to apply these inputs tick-by-tick - // as these packets are sent by the client every tick. - pushCameraControl (state, id = 1) { - let { x, y, z } = state.position - if (id === 1) y -= 1.62 // account for player bb - const adjPos = vec3({ x, y, z }) - // Sneak resyncs the position for easy testing - this.bot.updatePlayerCamera(id, adjPos, d2r(state.yaw), d2r(state.pitch), state.input_data.sneak_down) - } - - // Server gives us a new position - updatePosition (pos, yaw, pitch, headYaw, tick) { - this.lastPos = pos - this.lastRot = { x: yaw, y: pitch, z: headYaw } - if (tick) this.tick = tick - } - - // User has moved the camera. Update the movements stored. - onViewerCameraMove (newYaw, newPitch, newHeadYaw) { - this.lastRot = { x: newYaw, y: newPitch, z: newHeadYaw } - } -} - -module.exports = { MovementManager } diff --git a/examples/viewer/client/preload.js b/examples/viewer/client/preload.js deleted file mode 100644 index 58594b5..0000000 --- a/examples/viewer/client/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -// Required to detect electron in prismarine-viewer -globalThis.isElectron = true - -// If you need to disable node integration: -// * Node.js APIs will only be avaliable in this file -// * Use this file to load a viewer manager class -// based on one of the examples -// * Expose this class to the global window -// * Interact with the class in your code diff --git a/examples/viewer/client/util.js b/examples/viewer/client/util.js deleted file mode 100644 index c947af9..0000000 --- a/examples/viewer/client/util.js +++ /dev/null @@ -1,22 +0,0 @@ -const difference = (o1, o2) => Object.keys(o2).reduce((diff, key) => { - if (o1[key] === o2[key]) return diff - return { - ...diff, - [key]: o2[key] - } -}, {}) - -const diff = (o1, o2) => { const dif = difference(o1, o2); return Object.keys(dif).length ? dif : null } - -const d2r = deg => (180 - (deg < 0 ? (360 + deg) : deg)) * (Math.PI / 180) -const r2d = rad => { - let deg = rad * (180 / Math.PI) - deg = deg % 360 - return 180 - deg -} - -module.exports = { - diff, - d2r, - r2d -} diff --git a/examples/viewer/client/worker.js b/examples/viewer/client/worker.js deleted file mode 100644 index 23ff320..0000000 --- a/examples/viewer/client/worker.js +++ /dev/null @@ -1,2 +0,0 @@ -// hack for path resolving -require('prismarine-viewer/viewer/lib/worker') diff --git a/examples/viewer/index.js b/examples/viewer/index.js deleted file mode 100644 index 2147fd5..0000000 --- a/examples/viewer/index.js +++ /dev/null @@ -1,44 +0,0 @@ -const path = require('path') -const { app, BrowserWindow, globalShortcut } = require('electron') - -function createMainWindow () { - const window = new BrowserWindow({ - webPreferences: { - nodeIntegration: true, - nodeIntegrationInWorker: true, - contextIsolation: false, - preload: path.join(__dirname, './client/preload.js') - } - }) - - // Open dev tools on load - window.webContents.openDevTools() - - window.loadFile(path.join(__dirname, './client/index.html')) - - window.webContents.on('devtools-opened', () => { - window.focus() - setImmediate(() => { - window.focus() - }) - }) - - return window -} - -app.on('ready', () => { - const win = createMainWindow() - - globalShortcut.register('CommandOrControl+W', () => { - win.webContents.sendInputEvent({ - type: 'keyDown', - keyCode: 'W' - }) - }) -}) - -app.on('window-all-closed', function () { - app.quit() -}) - -app.allowRendererProcessReuse = false diff --git a/examples/viewer/package.json b/examples/viewer/package.json deleted file mode 100644 index 9895117..0000000 --- a/examples/viewer/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "bedrock-protocol-viewer", - "description": "bedrock-protocol prismarine-viewer example", - "scripts": { - "start": "electron ." - }, - "dependencies": { - "bedrock-protocol": "file:../../", - "browserify-cipher": "^1.0.1", - "electron": "^12.0.2", - "patch-package": "^6.4.7", - "prismarine-physics": "^1.2.2", - "prismarine-viewer": "^1.19.1" - } -} diff --git a/package.json b/package.json index bcd4e44..46c0b1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bedrock-protocol", - "version": "3.18.0", + "version": "3.19.0", "description": "Minecraft Bedrock Edition protocol library", "main": "index.js", "scripts": { From f88c8d0bc4ed252ad24ec3f9ad25da603dbc4db3 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 24 Sep 2022 13:53:26 -0400 Subject: [PATCH 299/458] 1.19.30 support, improve error handling and server pong data (#284) * Update server advertisement * 1.19.30 protocol support * Handle configurable compressor * Support updated 1.19.30 login flow with NetworkSettings * Improve serialization error handling on client * refactor compressor handling * Fix client on older versions, fix internal error handling * Improve error handling * Log console connection errors; use raknet-native for proxy test --- src/client.js | 43 ++++++++++++++++++++++++++--- src/connection.js | 21 +++++++++------ src/datatypes/util.js | 4 +-- src/options.js | 10 +++++-- src/rak.js | 7 ++--- src/server.js | 35 ++++++++++++++++++++++-- src/server/advertisement.js | 27 ++++++++++++------- src/serverPlayer.js | 52 +++++++++++++++++++++++++++++------- src/transforms/framer.js | 44 +++++++++++++++++++++--------- src/transforms/serializer.js | 7 +---- test/internal.js | 4 +-- test/proxy.js | 8 +++--- tools/startVanillaServer.js | 11 +++++--- 13 files changed, 205 insertions(+), 68 deletions(-) diff --git a/src/client.js b/src/client.js index 7ec612b..ed287aa 100644 --- a/src/client.js +++ b/src/client.js @@ -8,6 +8,7 @@ const initRaknet = require('./rak') const { KeyExchange } = require('./handshake/keyExchange') const Login = require('./handshake/login') const LoginVerify = require('./handshake/loginVerify') +const fs = require('fs') const debugging = false @@ -22,6 +23,10 @@ class Client extends Connection { this.startGameData = {} this.clientRuntimeId = null + // Start off without compression on 1.19.30, zlib on below + this.compressionAlgorithm = this.versionGreaterThanOrEqualTo('1.19.30') ? 'none' : 'deflate' + this.compressionThreshold = 512 + this.compressionLevel = this.options.compressionLevel if (isDebug) { this.inLog = (...args) => debug('C ->', ...args) @@ -46,7 +51,7 @@ class Client extends Connection { const { RakClient } = initRaknet(this.options.raknetBackend) const host = this.options.host const port = this.options.port - this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port }) + this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port }, this) this.emit('connect_allowed') } @@ -76,7 +81,7 @@ class Client extends Connection { onEncapsulated = (encapsulated, inetAddr) => { const buffer = Buffer.from(encapsulated.buffer) - this.handle(buffer) + process.nextTick(() => this.handle(buffer)) } async ping () { @@ -90,8 +95,18 @@ class Client extends Connection { _connect = async (sessionData) => { debug('[client] connecting to', this.options.host, this.options.port, sessionData, this.connection) - this.connection.onConnected = () => this.sendLogin() - this.connection.onCloseConnection = (reason) => this.close() + this.connection.onConnected = () => { + this.status = ClientStatus.Connecting + if (this.versionGreaterThanOrEqualTo('1.19.30')) { + this.queue('request_network_settings', { client_protocol: this.options.protocolVersion }) + } else { + this.sendLogin() + } + } + this.connection.onCloseConnection = (reason) => { + if (this.status === ClientStatus.Disconnected) this.conLog?.(`Server closed connection: ${reason}`) + this.close() + } this.connection.onEncapsulated = this.onEncapsulated this.connection.connect() @@ -103,6 +118,11 @@ class Client extends Connection { }, this.options.connectTimeout || 9000) } + updateCompressorSettings (packet) { + this.compressionAlgorithm = packet.compression_algorithm || 'deflate' + this.compressionThreshold = packet.compression_threshold + } + sendLogin () { this.status = ClientStatus.Authenticating this.createClientChain(null, this.options.offline) @@ -174,6 +194,15 @@ class Client extends Connection { try { var des = this.deserializer.parsePacketBuffer(packet) // eslint-disable-line } catch (e) { + // Dump information about the packet only if user is not handling error event. + if (this.listenerCount('error') === 0) { + if (packet.length > 1000) { + fs.writeFileSync('packetReadError.txt', packet.toString('hex')) + console.log(`Deserialization failure for packet 0x${packet.slice(0, 1).toString('hex')}. Packet buffer saved in ./packetReadError.txt as buffer was too large (${packet.length} bytes).`) + } else { + console.log('Read failure for 0x' + packet.slice(0, 1).toString('hex'), packet.slice(0, 1000)) + } + } this.emit('error', e) return } @@ -193,6 +222,12 @@ class Client extends Connection { case 'server_to_client_handshake': this.emit('client.server_handshake', des.data.params) break + case 'network_settings': + this.updateCompressorSettings(des.data.params) + if (this.status === ClientStatus.Connecting) { + this.sendLogin() + } + break case 'disconnect': // Client kicked this.emit(des.data.name, des.data.params) // Emit before we kill all listeners. this.onDisconnectRequest(des.data.params) diff --git a/src/connection.js b/src/connection.js index ddd60b1..bc1d56b 100644 --- a/src/connection.js +++ b/src/connection.js @@ -1,14 +1,15 @@ -const Framer = require('./transforms/framer') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') const { Versions } = require('./options') const debug = require('debug')('minecraft-protocol') +const { Framer } = require('./transforms/framer') const ClientStatus = { Disconnected: 0, - Authenticating: 1, // Handshaking - Initializing: 2, // Authed, need to spawn - Initialized: 3 // play_status spawn sent by server, client responded with SetPlayerInit packet + Connecting: 1, + Authenticating: 2, // Handshaking + Initializing: 3, // Authed, need to spawn + Initialized: 4 // play_status spawn sent by server, client responded with SetPlayerInit packet } class Connection extends EventEmitter { @@ -34,6 +35,10 @@ class Connection extends EventEmitter { return this.options.protocolVersion > (typeof version === 'string' ? Versions[version] : version) } + versionGreaterThanOrEqualTo (version) { + return this.options.protocolVersion >= (typeof version === 'string' ? Versions[version] : version) + } + startEncryption (iv) { this.encryptionEnabled = true this.inLog?.('Started encryption', this.sharedSecret, iv) @@ -60,7 +65,7 @@ class Connection extends EventEmitter { write (name, params) { this.outLog?.(name, params) if (name === 'start_game') this.updateItemPalette(params.itemstates) - const batch = new Framer(this.compressionLevel) + const batch = new Framer(this.compressionAlgorithm, this.compressionLevel, this.compressionThreshold) const packet = this.serializer.createPacketBuffer({ name, params }) batch.addEncodedPacket(packet) @@ -86,7 +91,7 @@ class Connection extends EventEmitter { _tick () { if (this.sendQ.length) { - const batch = new Framer(this.compressionLevel) + const batch = new Framer(this.compressionAlgorithm, this.compressionLevel, this.compressionThreshold) batch.addEncodedPackets(this.sendQ) this.sendQ = [] this.sendIds = [] @@ -110,7 +115,7 @@ class Connection extends EventEmitter { */ sendBuffer (buffer, immediate = false) { if (immediate) { - const batch = new Framer(this.compressionLevel) + const batch = new Framer(this.compressionAlgorithm, this.compressionLevel, this.compressionThreshold) batch.addEncodedPacket(buffer) if (this.encryptionEnabled) { this.sendEncryptedBatch(batch) @@ -162,7 +167,7 @@ class Connection extends EventEmitter { if (this.encryptionEnabled) { this.decrypt(buffer.slice(1)) } else { - const packets = Framer.decode(buffer) + const packets = Framer.decode(this.compressionAlgorithm, buffer) for (const packet of packets) { this.readPacket(packet) } diff --git a/src/datatypes/util.js b/src/datatypes/util.js index 4b29d57..7070ce5 100644 --- a/src/datatypes/util.js +++ b/src/datatypes/util.js @@ -23,11 +23,11 @@ function sleep (ms) { async function waitFor (cb, withTimeout, onTimeout) { let t const ret = await Promise.race([ - new Promise(resolve => cb(resolve)), + new Promise((resolve, reject) => cb(resolve, reject)), new Promise(resolve => { t = setTimeout(() => resolve('timeout'), withTimeout) }) ]) clearTimeout(t) - if (ret === 'timeout') onTimeout() + if (ret === 'timeout') await onTimeout() return ret } diff --git a/src/options.js b/src/options.js index e081536..bd1282f 100644 --- a/src/options.js +++ b/src/options.js @@ -21,7 +21,14 @@ const defaultOptions = { // Specifies the raknet implementation to use raknetBackend: 'raknet-native', // If using JS implementation of RakNet, should we use workers? (This only affects the client) - useRaknetWorkers: true + useRaknetWorkers: true, + + // server: What compression algorithm to use by default, either `none`, `deflate` or `snappy` + compressionAlgorithm: 'deflate', + // server and client: On Deflate, what compression level to use, between 1 and 9 + compressionLevel: 7, + // server: If true, only compress if a payload is larger than compressionThreshold + compressionThreshold: 512 } function validateOptions (options) { @@ -34,7 +41,6 @@ function validateOptions (options) { if (options.protocolVersion < MIN_VERSION) { throw new Error(`Protocol version < ${MIN_VERSION} : ${options.protocolVersion}, too old`) } - this.compressionLevel = options.compressionLevel || 7 if (options.useNativeRaknet === true) options.raknetBackend = 'raknet-native' if (options.useNativeRaknet === false) options.raknetBackend = 'jsp-raknet' } diff --git a/src/rak.js b/src/rak.js index 7b1e2f1..35e82cf 100644 --- a/src/rak.js +++ b/src/rak.js @@ -24,14 +24,15 @@ module.exports = (backend) => { } class RakNativeClient extends EventEmitter { - constructor (options) { + constructor (options, client) { super() this.connected = false this.onConnected = () => { } this.onCloseConnection = () => { } this.onEncapsulated = () => { } - this.raknet = new Client(options.host, options.port, { protocolVersion: 10 }) + const protocolVersion = client?.versionGreaterThanOrEqualTo('1.19.30') ? 11 : 10 + this.raknet = new Client(options.host, options.port, { protocolVersion }) this.raknet.on('encapsulated', ({ buffer, address }) => { if (this.connected) { // Discard packets that are queued to be sent to us after close this.onEncapsulated(buffer, address) @@ -86,7 +87,7 @@ class RakNativeServer extends EventEmitter { this.onEncapsulated = () => { } this.raknet = new Server(options.host, options.port, { maxConnections: options.maxPlayers || 3, - protocolVersion: 10, + protocolVersion: server.versionLessThan('1.19.30') ? 10 : 11, message: server.getAdvertisement().toBuffer() }) this.onClose = () => {} diff --git a/src/server.js b/src/server.js index ffa5d77..bbefdae 100644 --- a/src/server.js +++ b/src/server.js @@ -16,18 +16,49 @@ class Server extends EventEmitter { this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) - this.advertisement = new ServerAdvertisement(this.options.motd, this.options.version) + this.advertisement = new ServerAdvertisement(this.options.motd, this.options.port, this.options.version) this.advertisement.playersMax = options.maxPlayers ?? 3 /** @type {Object} */ this.clients = {} this.clientCount = 0 this.conLog = debug + + this.setCompressor(this.options.compressionAlgorithm, this.options.compressionLevel, this.options.compressionThreshold) + } + + setCompressor (algorithm, level = 1, threshold = 256) { + if (algorithm === 'none') { + this.compressionAlgorithm = 'none' + this.compressionLevel = 0 + } else if (algorithm === 'deflate') { + this.compressionAlgorithm = 'deflate' + this.compressionLevel = level + this.compressionThreshold = threshold + } else if (algorithm === 'snappy') { + this.compressionAlgorithm = 'snappy' + this.compressionLevel = level + this.compressionThreshold = threshold + } else { + throw new Error(`Unknown compression algorithm ${algorithm}`) + } } validateOptions () { Options.validateOptions(this.options) } + versionLessThan (version) { + return this.options.protocolVersion < (typeof version === 'string' ? Options.Versions[version] : version) + } + + versionGreaterThan (version) { + return this.options.protocolVersion > (typeof version === 'string' ? Options.Versions[version] : version) + } + + versionGreaterThanOrEqualTo (version) { + return this.options.protocolVersion >= (typeof version === 'string' ? Options.Versions[version] : version) + } + onOpenConnection = (conn) => { this.conLog('new connection', conn?.address) const player = new Player(this, conn) @@ -51,7 +82,7 @@ class Server extends EventEmitter { debug(`ignoring packet from unknown inet addr: ${address}`) return } - client.handle(buffer) + process.nextTick(() => client.handle(buffer)) } getAdvertisement () { diff --git a/src/server/advertisement.js b/src/server/advertisement.js index ff5f08a..c7210d9 100644 --- a/src/server/advertisement.js +++ b/src/server/advertisement.js @@ -6,24 +6,26 @@ class ServerAdvertisement { playersOnline = 0 playersMax = 5 gamemode = 'Creative' - serverId = '0' + serverId = Date.now().toString() gamemodeId = 1 - port = undefined + portV4 = undefined portV6 = undefined - constructor (obj, version = CURRENT_VERSION) { + constructor (obj, port, version = CURRENT_VERSION) { if (obj?.name) obj.motd = obj.name this.protocol = Versions[version] this.version = version + this.portV4 = port + this.portV6 = port Object.assign(this, obj) } fromString (str) { - const [header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode, gamemodeId, port, portV6] = str.split(';') - Object.assign(this, { header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode, gamemodeId, port, portV6 }) - for (const numeric of ['playersOnline', 'playersMax', 'gamemodeId', 'port', 'portV6']) { + const [header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode, gamemodeId, portV4, portV6] = str.split(';') + Object.assign(this, { header, motd, protocol, version, playersOnline, playersMax, serverId, levelName, gamemode, gamemodeId, portV4, portV6 }) + for (const numeric of ['playersOnline', 'playersMax', 'gamemodeId', 'portV4', 'portV6']) { if (this[numeric] !== undefined) { - this[numeric] = parseInt(this[numeric]) + this[numeric] = this[numeric] ? parseInt(this[numeric]) : null } } return this @@ -39,13 +41,20 @@ class ServerAdvertisement { this.playersMax, this.serverId, this.levelName, - this.gamemode + this.gamemode, + this.gamemodeId, + this.portV4, + this.portV6, + '0' ].join(';') + ';' } toBuffer (version) { const str = this.toString(version) - return Buffer.concat([Buffer.from([0, str.length]), Buffer.from(str)]) + const buf = Buffer.alloc(2 + str.length) + buf.writeUInt16BE(str.length, 0) + buf.write(str, 2) + return buf } } diff --git a/src/serverPlayer.js b/src/serverPlayer.js index 83f25ec..ffb1961 100644 --- a/src/serverPlayer.js +++ b/src/serverPlayer.js @@ -4,7 +4,6 @@ const { serialize, isDebug } = require('./datatypes/util') const { KeyExchange } = require('./handshake/keyExchange') const Login = require('./handshake/login') const LoginVerify = require('./handshake/loginVerify') -const fs = require('fs') const debug = require('debug')('minecraft-protocol') class Player extends Connection { @@ -15,7 +14,6 @@ class Player extends Connection { this.deserializer = server.deserializer this.connection = connection this.options = server.options - this.compressionLevel = server.compressionLevel KeyExchange(this, server, server.options) Login(this, server, server.options) @@ -28,24 +26,49 @@ class Player extends Connection { this.inLog = (...args) => debug('S ->', ...args) this.outLog = (...args) => debug('S <-', ...args) } + + // Compression is server-wide + this.compressionAlgorithm = this.server.compressionAlgorithm + this.compressionLevel = this.server.compressionLevel + this.compressionThreshold = this.server.compressionThreshold + + this._sentNetworkSettings = false // 1.19.30+ } getUserData () { return this.userData } + sendNetworkSettings () { + this.write('network_settings', { + compression_threshold: this.server.compressionThreshold, + compression_algorithm: this.server.compressionAlgorithm, + client_throttle: false, + client_throttle_threshold: 0, + client_throttle_scalar: 0 + }) + this._sentNetworkSettings = true + } + + handleClientProtocolVersion (clientVersion) { + if (this.server.options.protocolVersion) { + if (this.server.options.protocolVersion < clientVersion) { + this.sendDisconnectStatus('failed_spawn') // client too new + return false + } + } else if (clientVersion < Options.MIN_VERSION) { + this.sendDisconnectStatus('failed_client') // client too old + return false + } + return true + } + onLogin (packet) { const body = packet.data this.emit('loggingIn', body) const clientVer = body.params.protocol_version - if (this.server.options.protocolVersion) { - if (this.server.options.protocolVersion < clientVer) { - this.sendDisconnectStatus('failed_spawn') - return - } - } else if (clientVer < Options.MIN_VERSION) { - this.sendDisconnectStatus('failed_client') + if (!this.handleClientProtocolVersion(clientVer)) { return } @@ -125,15 +148,24 @@ class Player extends Connection { var des = this.server.deserializer.parsePacketBuffer(packet) // eslint-disable-line } catch (e) { this.disconnect('Server error') - fs.writeFile(`packetdump_${this.connection.address}_${Date.now()}.bin`, packet) + debug('Dropping packet from', this.connection.address, e) return } this.inLog?.(des.data.name, serialize(des.data.params).slice(0, 200)) switch (des.data.name) { + // This is the first packet on 1.19.30 & above + case 'request_network_settings': + if (this.handleClientProtocolVersion(des.data.params.client_protocol)) { + this.sendNetworkSettings() + this.compressionLevel = this.server.compressionLevel + } + return + // Below 1.19.30, this is the first packet. case 'login': this.onLogin(des) + if (!this._sentNetworkSettings) this.sendNetworkSettings() return case 'client_to_server_handshake': // Emit the 'join' event diff --git a/src/transforms/framer.js b/src/transforms/framer.js index c31b8d8..2452f01 100644 --- a/src/transforms/framer.js +++ b/src/transforms/framer.js @@ -3,30 +3,48 @@ const zlib = require('zlib') // Concatenates packets into one batch packet, and adds length prefixs. class Framer { - constructor (compressionLevel) { + constructor (compressor, compressionLevel, compressionThreshold) { // Encoding this.packets = [] + this.compressor = compressor || 'none' this.compressionLevel = compressionLevel + this.compressionThreshold = compressionThreshold } - static decode (buf) { + // No compression in base class + compress (buffer) { + switch (this.compressor) { + case 'deflate': return zlib.deflateRawSync(buffer, { level: this.compressionLevel }) + case 'snappy': throw Error('Snappy compression not implemented') + case 'none': return buffer + } + } + + static decompress (algorithm, buffer) { + try { + switch (algorithm) { + case 'deflate': return zlib.inflateRawSync(buffer, { chunkSize: 512000 }) + case 'snappy': throw Error('Snappy compression not implemented') + case 'none': return buffer + default: throw Error('Unknown compression type ' + this.compressor) + } + } catch { + return buffer + } + } + + static decode (compressor, buf) { // Read header if (buf[0] !== 0xfe) throw Error('bad batch packet header ' + buf[0]) const buffer = buf.slice(1) - - // Decode the payload with 512kb buffer - try { - const inflated = zlib.inflateRawSync(buffer, { chunkSize: 512000 }) - return Framer.getPackets(inflated) - } catch (e) { // Try to decode without compression - return Framer.getPackets(buffer) - } + const decompressed = this.decompress(compressor, buffer) + return Framer.getPackets(decompressed) } encode () { const buf = Buffer.concat(this.packets) - const def = zlib.deflateRawSync(buf, { level: this.compressionLevel }) - return Buffer.concat([Buffer.from([0xfe]), def]) + const compressed = (buf.length > this.compressionThreshold) ? this.compress(buf) : buf + return Buffer.concat([Buffer.from([0xfe]), compressed]) } addEncodedPacket (chunk) { @@ -71,4 +89,4 @@ class Framer { } } -module.exports = Framer +module.exports = { Framer } diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index c763599..f6b1918 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -4,12 +4,7 @@ const { join } = require('path') class Parser extends FullPacketParser { parsePacketBuffer (buffer) { - try { - return super.parsePacketBuffer(buffer) - } catch (e) { - console.error('While decoding', buffer.toString('hex')) - throw e - } + return super.parsePacketBuffer(buffer) } verify (deserialized, serializer) { diff --git a/test/internal.js b/test/internal.js index 51e1f71..15131a9 100644 --- a/test/internal.js +++ b/test/internal.js @@ -201,9 +201,9 @@ async function requestChunks (version, x, z, radius) { } async function timedTest (version, timeout = 1000 * 220) { - await waitFor((res) => { + await waitFor((resolve, reject) => { // mocha eats up stack traces... - startTest(version, res).catch(console.error) + startTest(version, resolve).catch(reject) }, timeout, () => { throw Error('timed out') }) diff --git a/test/proxy.js b/test/proxy.js index a1df25e..d6b169f 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -1,7 +1,7 @@ const { createClient, Server, Relay } = require('bedrock-protocol') const { sleep, waitFor } = require('../src/datatypes/util') -function proxyTest (version, raknetBackend = 'raknet-node', timeout = 1000 * 40) { +function proxyTest (version, raknetBackend = 'raknet-native', timeout = 1000 * 40) { console.log('with raknet backend', raknetBackend) return waitFor(async res => { const SERVER_PORT = 19000 + ((Math.random() * 100) | 0) @@ -60,8 +60,8 @@ function proxyTest (version, raknetBackend = 'raknet-node', timeout = 1000 * 40) }, timeout, () => { throw Error('timed out') }) } -if (!module.parent) { - proxyTest('1.16.220', 'raknet-native') -} +// if (!module.parent) { +// proxyTest('1.16.220', 'raknet-native') +// } module.exports = { proxyTest } diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index 4740bef..be63b47 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -87,6 +87,8 @@ function run (inheritStdout = true) { return cp.spawn(exe, inheritStdout ? { stdio: 'inherit' } : {}) } +let lastHandle + // Run the server async function startServer (version, onStart, options = {}) { const os = process.platform === 'win32' ? 'win' : process.platform @@ -95,7 +97,7 @@ async function startServer (version, onStart, options = {}) { } await download(os, version, options.path) configure(options) - const handle = run(!onStart) + const handle = lastHandle = run(!onStart) handle.on('error', (...a) => { console.warn('*** THE MINECRAFT PROCESS CRASHED ***', a) handle.kill('SIGKILL') @@ -126,9 +128,12 @@ async function startServerAndWait (version, withTimeout, options) { async function startServerAndWait2 (version, withTimeout, options) { try { - return await startServerAndWait(version, withTimeout, options) + return await startServerAndWait(version, 1000 * 60, options) } catch (e) { - console.log(e, 'tring once more to start server...') + console.log(e) + console.log('^ Tring once more to start server in 10 seconds...') + lastHandle?.kill() + await new Promise(resolve => setTimeout(resolve, 10000)) process.chdir(__dirname) fs.rmSync('bds-' + version, { recursive: true }) return await startServerAndWait(version, withTimeout, options) From dbf15c4feb06bdd088fa667b4f9bbdd1828bc690 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 24 Sep 2022 15:25:47 -0400 Subject: [PATCH 300/458] use raknet-native for tests (#285) --- test/internal.test.js | 10 ---------- test/proxy.js | 6 +++--- test/proxy.test.js | 18 ++++++++++++++++++ test/vanilla.js | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 test/proxy.test.js diff --git a/test/internal.test.js b/test/internal.test.js index d6c11d8..06e0ae3 100644 --- a/test/internal.test.js +++ b/test/internal.test.js @@ -1,7 +1,6 @@ /* eslint-env jest */ const { timedTest } = require('./internal') -const { proxyTest } = require('./proxy') const { Versions } = require('../src/options') const { sleep } = require('../src/datatypes/util') @@ -16,13 +15,4 @@ describe('internal client/server test', function () { await sleep(100) }) } - - for (const version in Versions) { - it('proxies ' + version, async () => { - console.debug(version) - await proxyTest(version) - await sleep(5000) - console.debug('Done', version) - }) - } }) diff --git a/test/proxy.js b/test/proxy.js index d6b169f..1489a01 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -26,6 +26,7 @@ function proxyTest (version, raknetBackend = 'raknet-native', timeout = 1000 * 4 }) console.debug('Server started', server.options.version) + await new Promise(resolve => setTimeout(resolve, 1000)) const relay = new Relay({ version, @@ -44,6 +45,7 @@ function proxyTest (version, raknetBackend = 'raknet-native', timeout = 1000 * 4 await relay.listen() console.debug('Proxy started', server.options.version) + await new Promise(resolve => setTimeout(resolve, 1000)) const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true, raknetBackend, skipPing: true }) console.debug('Client started') @@ -60,8 +62,6 @@ function proxyTest (version, raknetBackend = 'raknet-native', timeout = 1000 * 4 }, timeout, () => { throw Error('timed out') }) } -// if (!module.parent) { -// proxyTest('1.16.220', 'raknet-native') -// } +// if (!module.parent) { proxyTest('1.16.220', 'raknet-native') } module.exports = { proxyTest } diff --git a/test/proxy.test.js b/test/proxy.test.js new file mode 100644 index 0000000..d6e2abe --- /dev/null +++ b/test/proxy.test.js @@ -0,0 +1,18 @@ +/* eslint-env jest */ +const { proxyTest } = require('./proxy') +const { Versions } = require('../src/options') +const { sleep } = require('../src/datatypes/util') + +describe('proxies client/server', function () { + const vcount = Object.keys(Versions).length + this.timeout(vcount * 30 * 1000) + + for (const version in Versions) { + it('proxies ' + version, async () => { + console.debug(version) + await proxyTest(version) + await sleep(5000) + console.debug('Done', version) + }) + } +}) diff --git a/test/vanilla.js b/test/vanilla.js index e67bdaa..94cdc11 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -15,7 +15,7 @@ async function test (version) { port: 19130, username: 'Notch', version, - raknetBackend: 'raknet-node', + raknetBackend: 'raknet-native', offline: true }) From 72dd749717ecdd4a769bed36bbfbe06dc0056772 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 24 Sep 2022 15:46:33 -0400 Subject: [PATCH 301/458] tools/vanillaServer: add HEAD request timeout prevent long hangs --- tools/startVanillaServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/startVanillaServer.js b/tools/startVanillaServer.js index be63b47..3d408c1 100644 --- a/tools/startVanillaServer.js +++ b/tools/startVanillaServer.js @@ -5,7 +5,7 @@ const debug = process.env.CI ? console.debug : require('debug')('minecraft-proto const https = require('https') const { getFiles, waitFor } = require('../src/datatypes/util') -const head = (url) => new Promise((resolve, reject) => http.request(url, { method: 'HEAD' }, resolve).on('error', reject).end()) +const head = (url) => new Promise((resolve, reject) => http.request(url, { method: 'HEAD', timeout: 500 }, resolve).on('error', reject).end()) function get (url, outPath) { const file = fs.createWriteStream(outPath) return new Promise((resolve, reject) => { From 7c716b92323721a839ddaff6a7e8233b6efe2f62 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 24 Sep 2022 16:47:03 -0400 Subject: [PATCH 302/458] 1.19.30 support (#286) --- README.md | 2 +- index.d.ts | 2 +- src/options.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7acad89..10ea1a4 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication ## Features - - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10, 1.19.20, 1.19.21 + - Supports Minecraft Bedrock version 1.16.201, 1.16.210, 1.16.220, 1.17.0, 1.17.10, 1.17.30, 1.17.40, 1.18.0, 1.18.11, 1.18.30, 1.19.1, 1.19.10, 1.19.20, 1.19.21, 1.19.30 - Parse and serialize packets as JavaScript objects - Automatically respond to keep-alive packets - [Proxy and mitm connections](docs/API.md#proxy-docs) diff --git a/index.d.ts b/index.d.ts index a439d28..2353220 100644 --- a/index.d.ts +++ b/index.d.ts @@ -2,7 +2,7 @@ import EventEmitter from "events" import { Realm } from "prismarine-realms" declare module "bedrock-protocol" { - type Version = '1.19.22' | '1.19.21' | '1.19.20' | '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' + type Version = '1.19.30' | '1.19.22' | '1.19.21' | '1.19.20' | '1.19.11' | '1.19.10' | '1.19.2' | '1.19.1' | '1.18.31' | '1.18.30' | '1.18.12' | '1.18.11' | '1.18.10' | '1.18.2' | '1.18.1' | '1.18.0' | '1.17.41' | '1.17.40' | '1.17.34' | '1.17.30' | '1.17.11' | '1.17.10' | '1.17.0' | '1.16.220' | '1.16.210' | '1.16.201' enum title { MinecraftNintendoSwitch, MinecraftJava } diff --git a/src/options.js b/src/options.js index bd1282f..d8cb18a 100644 --- a/src/options.js +++ b/src/options.js @@ -3,7 +3,7 @@ const mcData = require('minecraft-data') // Minimum supported version (< will be kicked) const MIN_VERSION = '1.16.201' // Currently supported verson. Note, clients with newer versions can still connect as long as data is in minecraft-data -const CURRENT_VERSION = '1.19.21' +const CURRENT_VERSION = '1.19.30' const Versions = Object.fromEntries(mcData.versions.bedrock.filter(e => e.releaseType === 'release').map(e => [e.minecraftVersion, e.version])) From 3295c0ddd9419739baec19ebf7119cb8926f1f01 Mon Sep 17 00:00:00 2001 From: extremeheat Date: Sat, 24 Sep 2022 16:55:12 -0400 Subject: [PATCH 303/458] Update doc (#288) * Update API.md * Update README.md * Update API.md --- README.md | 8 ++++---- docs/API.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 10ea1a4..b5c91e4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Minecraft Bedrock Edition (aka MCPE) protocol library, supporting authentication and encryption. Help [contribute](CONTRIBUTING.md). -[Protocol doc](https://minecraft-data.prismarine.js.org/?v=bedrock_1.17.10&d=protocol) +[Protocol doc](https://minecraft-data.prismarine.js.org/?v=bedrock_1.19.10&d=protocol) ## Features @@ -102,11 +102,11 @@ ping({ host: 'play.cubecraft.net', port: 19132 }).then(res => { ## Documentation -For documentation on the protocol, and packets/fields see the [proto.yml](data/latest/proto.yml) and [types.yml](data/latest/proto.yml) files. +For documentation on the protocol, and packets/fields see the [protocol documentation](https://minecraft-data.prismarine.js.org/protocol/). -See [API documentation](docs/API.md) +* See [API documentation](docs/API.md) -See [faq](docs/FAQ.md) +* See [frequently asked questions and answers](docs/FAQ.md)