├── .gitignore ├── LICENSE ├── README.md ├── plugin.yml ├── resources ├── config.yml ├── icon.png └── vanilla │ ├── block_id_map.json │ ├── canonical_block_states_1_16_220.nbt │ ├── canonical_block_states_1_17_0.nbt │ ├── canonical_block_states_1_17_10.nbt │ ├── canonical_block_states_1_17_30.nbt │ ├── canonical_block_states_1_17_40.nbt │ ├── r12_to_current_block_map_1_16_220.bin │ ├── r12_to_current_block_map_1_17_10.bin │ ├── r12_to_current_block_map_1_17_30.bin │ ├── required_item_list_1_16_220.json │ ├── required_item_list_1_17_0.json │ ├── required_item_list_1_17_10.json │ ├── required_item_list_1_17_30.json │ ├── required_item_list_1_17_40.json │ └── required_item_list_1_18_0.json └── src └── AkmalFairuz └── MultiVersion ├── Config.php ├── EventListener.php ├── Loader.php ├── MultiVersion.php ├── MultiVersionPacketSender.php ├── command └── MultiVersionCommand.php ├── compressor └── MultiVersionZlibCompressor.php ├── network ├── Chunk112.php ├── MultiVersionSessionAdapter.php ├── ProtocolConstants.php ├── Serializer.php ├── Translator.php ├── convert │ ├── MultiVersionCraftingManager.php │ ├── MultiVersionGlobalItemTypeDictionary.php │ ├── MultiVersionItemTranslator.php │ ├── MultiVersionItemTypeDictionary.php │ ├── MultiVersionLegacyBlockIdMap.php │ └── MultiVersionRuntimeBlockMapping.php └── translator │ ├── AddItemActorPacketTranslator.php │ ├── AddPlayerPacketTranslator.php │ ├── AnimateEntityPacketTranslator.php │ ├── AvailableCommandsPacketTranslator.php │ ├── CraftingDataPacketTranslator.php │ ├── CreativeContentPacketTranslator.php │ ├── GameRulesChangedPacketTranslator.php │ ├── InventoryContentPacketTranslator.php │ ├── InventorySlotPacketTranslator.php │ ├── InventoryTransactionPacketTranslator.php │ ├── MobArmorEquipmentPacketTranslator.php │ ├── MobEquipmentPacketTranslator.php │ ├── NpcRequestPacketTranslator.php │ ├── PlayerListPacketTranslator.php │ ├── PlayerSkinPacketTranslator.php │ ├── ResourcePacksInfoPacketTranslator.php │ ├── SetTitlePacketTranslator.php │ └── StartGamePacketTranslator.php ├── session ├── Session.php └── SessionManager.php ├── task ├── CheckUpdateTask.php ├── CompressTask.php └── DecompressTask.php └── utils └── Utils.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MultiVersion-Continued 2 | a multiversion plugin for pocketmine 4 3 | 4 | #### Status: in-dev 5 | -------------------------------------------------------------------------------- /plugin.yml: -------------------------------------------------------------------------------- 1 | name: MultiVersion 2 | api: 4.0.0 3 | main: AkmalFairuz\MultiVersion\Loader 4 | version: 0.486.2 5 | description: A plugin to allows older Minecraft client versions to connect to newer server versions. 6 | authors: [AkmalFairuz, Laith98Dev, VaxPex] 7 | 8 | permissions: 9 | multiversion.command: 10 | default: op 11 | -------------------------------------------------------------------------------- /resources/config.yml: -------------------------------------------------------------------------------- 1 | # If async compression/decompression enabled packet will be delayed 1-2 tick and reduce lag in the main thread. 2 | async_batch_decompression: true 3 | async_batch_compress: true 4 | async_batch_threshold: 1024 5 | 6 | # example= 7 | # disabled_protocols: [448, 440] 8 | disabled_protocols: [] -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/icon.png -------------------------------------------------------------------------------- /resources/vanilla/block_id_map.json: -------------------------------------------------------------------------------- 1 | {"minecraft:air":0,"minecraft:stone":1,"minecraft:grass":2,"minecraft:dirt":3,"minecraft:cobblestone":4,"minecraft:planks":5,"minecraft:sapling":6,"minecraft:bedrock":7,"minecraft:flowing_water":8,"minecraft:water":9,"minecraft:flowing_lava":10,"minecraft:lava":11,"minecraft:sand":12,"minecraft:gravel":13,"minecraft:gold_ore":14,"minecraft:iron_ore":15,"minecraft:coal_ore":16,"minecraft:log":17,"minecraft:leaves":18,"minecraft:sponge":19,"minecraft:glass":20,"minecraft:lapis_ore":21,"minecraft:lapis_block":22,"minecraft:dispenser":23,"minecraft:sandstone":24,"minecraft:noteblock":25,"minecraft:bed":26,"minecraft:golden_rail":27,"minecraft:detector_rail":28,"minecraft:sticky_piston":29,"minecraft:web":30,"minecraft:tallgrass":31,"minecraft:deadbush":32,"minecraft:piston":33,"minecraft:pistonArmCollision":34,"minecraft:wool":35,"minecraft:element_0":36,"minecraft:yellow_flower":37,"minecraft:red_flower":38,"minecraft:brown_mushroom":39,"minecraft:red_mushroom":40,"minecraft:gold_block":41,"minecraft:iron_block":42,"minecraft:double_stone_slab":43,"minecraft:stone_slab":44,"minecraft:brick_block":45,"minecraft:tnt":46,"minecraft:bookshelf":47,"minecraft:mossy_cobblestone":48,"minecraft:obsidian":49,"minecraft:torch":50,"minecraft:fire":51,"minecraft:mob_spawner":52,"minecraft:oak_stairs":53,"minecraft:chest":54,"minecraft:redstone_wire":55,"minecraft:diamond_ore":56,"minecraft:diamond_block":57,"minecraft:crafting_table":58,"minecraft:wheat":59,"minecraft:farmland":60,"minecraft:furnace":61,"minecraft:lit_furnace":62,"minecraft:standing_sign":63,"minecraft:wooden_door":64,"minecraft:ladder":65,"minecraft:rail":66,"minecraft:stone_stairs":67,"minecraft:wall_sign":68,"minecraft:lever":69,"minecraft:stone_pressure_plate":70,"minecraft:iron_door":71,"minecraft:wooden_pressure_plate":72,"minecraft:redstone_ore":73,"minecraft:lit_redstone_ore":74,"minecraft:unlit_redstone_torch":75,"minecraft:redstone_torch":76,"minecraft:stone_button":77,"minecraft:snow_layer":78,"minecraft:ice":79,"minecraft:snow":80,"minecraft:cactus":81,"minecraft:clay":82,"minecraft:reeds":83,"minecraft:jukebox":84,"minecraft:fence":85,"minecraft:pumpkin":86,"minecraft:netherrack":87,"minecraft:soul_sand":88,"minecraft:glowstone":89,"minecraft:portal":90,"minecraft:lit_pumpkin":91,"minecraft:cake":92,"minecraft:unpowered_repeater":93,"minecraft:powered_repeater":94,"minecraft:invisibleBedrock":95,"minecraft:trapdoor":96,"minecraft:monster_egg":97,"minecraft:stonebrick":98,"minecraft:brown_mushroom_block":99,"minecraft:red_mushroom_block":100,"minecraft:iron_bars":101,"minecraft:glass_pane":102,"minecraft:melon_block":103,"minecraft:pumpkin_stem":104,"minecraft:melon_stem":105,"minecraft:vine":106,"minecraft:fence_gate":107,"minecraft:brick_stairs":108,"minecraft:stone_brick_stairs":109,"minecraft:mycelium":110,"minecraft:waterlily":111,"minecraft:nether_brick":112,"minecraft:nether_brick_fence":113,"minecraft:nether_brick_stairs":114,"minecraft:nether_wart":115,"minecraft:enchanting_table":116,"minecraft:brewing_stand":117,"minecraft:cauldron":118,"minecraft:end_portal":119,"minecraft:end_portal_frame":120,"minecraft:end_stone":121,"minecraft:dragon_egg":122,"minecraft:redstone_lamp":123,"minecraft:lit_redstone_lamp":124,"minecraft:dropper":125,"minecraft:activator_rail":126,"minecraft:cocoa":127,"minecraft:sandstone_stairs":128,"minecraft:emerald_ore":129,"minecraft:ender_chest":130,"minecraft:tripwire_hook":131,"minecraft:tripWire":132,"minecraft:emerald_block":133,"minecraft:spruce_stairs":134,"minecraft:birch_stairs":135,"minecraft:jungle_stairs":136,"minecraft:command_block":137,"minecraft:beacon":138,"minecraft:cobblestone_wall":139,"minecraft:flower_pot":140,"minecraft:carrots":141,"minecraft:potatoes":142,"minecraft:wooden_button":143,"minecraft:skull":144,"minecraft:anvil":145,"minecraft:trapped_chest":146,"minecraft:light_weighted_pressure_plate":147,"minecraft:heavy_weighted_pressure_plate":148,"minecraft:unpowered_comparator":149,"minecraft:powered_comparator":150,"minecraft:daylight_detector":151,"minecraft:redstone_block":152,"minecraft:quartz_ore":153,"minecraft:hopper":154,"minecraft:quartz_block":155,"minecraft:quartz_stairs":156,"minecraft:double_wooden_slab":157,"minecraft:wooden_slab":158,"minecraft:stained_hardened_clay":159,"minecraft:stained_glass_pane":160,"minecraft:leaves2":161,"minecraft:log2":162,"minecraft:acacia_stairs":163,"minecraft:dark_oak_stairs":164,"minecraft:slime":165,"minecraft:iron_trapdoor":167,"minecraft:prismarine":168,"minecraft:seaLantern":169,"minecraft:hay_block":170,"minecraft:carpet":171,"minecraft:hardened_clay":172,"minecraft:coal_block":173,"minecraft:packed_ice":174,"minecraft:double_plant":175,"minecraft:standing_banner":176,"minecraft:wall_banner":177,"minecraft:daylight_detector_inverted":178,"minecraft:red_sandstone":179,"minecraft:red_sandstone_stairs":180,"minecraft:double_stone_slab2":181,"minecraft:stone_slab2":182,"minecraft:spruce_fence_gate":183,"minecraft:birch_fence_gate":184,"minecraft:jungle_fence_gate":185,"minecraft:dark_oak_fence_gate":186,"minecraft:acacia_fence_gate":187,"minecraft:repeating_command_block":188,"minecraft:chain_command_block":189,"minecraft:hard_glass_pane":190,"minecraft:hard_stained_glass_pane":191,"minecraft:chemical_heat":192,"minecraft:spruce_door":193,"minecraft:birch_door":194,"minecraft:jungle_door":195,"minecraft:acacia_door":196,"minecraft:dark_oak_door":197,"minecraft:grass_path":198,"minecraft:frame":199,"minecraft:chorus_flower":200,"minecraft:purpur_block":201,"minecraft:colored_torch_rg":202,"minecraft:purpur_stairs":203,"minecraft:colored_torch_bp":204,"minecraft:undyed_shulker_box":205,"minecraft:end_bricks":206,"minecraft:frosted_ice":207,"minecraft:end_rod":208,"minecraft:end_gateway":209,"minecraft:allow":210,"minecraft:deny":211,"minecraft:border_block":212,"minecraft:magma":213,"minecraft:nether_wart_block":214,"minecraft:red_nether_brick":215,"minecraft:bone_block":216,"minecraft:structure_void":217,"minecraft:shulker_box":218,"minecraft:purple_glazed_terracotta":219,"minecraft:white_glazed_terracotta":220,"minecraft:orange_glazed_terracotta":221,"minecraft:magenta_glazed_terracotta":222,"minecraft:light_blue_glazed_terracotta":223,"minecraft:yellow_glazed_terracotta":224,"minecraft:lime_glazed_terracotta":225,"minecraft:pink_glazed_terracotta":226,"minecraft:gray_glazed_terracotta":227,"minecraft:silver_glazed_terracotta":228,"minecraft:cyan_glazed_terracotta":229,"minecraft:blue_glazed_terracotta":231,"minecraft:brown_glazed_terracotta":232,"minecraft:green_glazed_terracotta":233,"minecraft:red_glazed_terracotta":234,"minecraft:black_glazed_terracotta":235,"minecraft:concrete":236,"minecraft:concretePowder":237,"minecraft:chemistry_table":238,"minecraft:underwater_torch":239,"minecraft:chorus_plant":240,"minecraft:stained_glass":241,"minecraft:camera":242,"minecraft:podzol":243,"minecraft:beetroot":244,"minecraft:stonecutter":245,"minecraft:glowingobsidian":246,"minecraft:netherreactor":247,"minecraft:info_update":248,"minecraft:info_update2":249,"minecraft:movingBlock":250,"minecraft:observer":251,"minecraft:structure_block":252,"minecraft:hard_glass":253,"minecraft:hard_stained_glass":254,"minecraft:reserved6":255,"minecraft:prismarine_stairs":257,"minecraft:dark_prismarine_stairs":258,"minecraft:prismarine_bricks_stairs":259,"minecraft:stripped_spruce_log":260,"minecraft:stripped_birch_log":261,"minecraft:stripped_jungle_log":262,"minecraft:stripped_acacia_log":263,"minecraft:stripped_dark_oak_log":264,"minecraft:stripped_oak_log":265,"minecraft:blue_ice":266,"minecraft:element_1":267,"minecraft:element_2":268,"minecraft:element_3":269,"minecraft:element_4":270,"minecraft:element_5":271,"minecraft:element_6":272,"minecraft:element_7":273,"minecraft:element_8":274,"minecraft:element_9":275,"minecraft:element_10":276,"minecraft:element_11":277,"minecraft:element_12":278,"minecraft:element_13":279,"minecraft:element_14":280,"minecraft:element_15":281,"minecraft:element_16":282,"minecraft:element_17":283,"minecraft:element_18":284,"minecraft:element_19":285,"minecraft:element_20":286,"minecraft:element_21":287,"minecraft:element_22":288,"minecraft:element_23":289,"minecraft:element_24":290,"minecraft:element_25":291,"minecraft:element_26":292,"minecraft:element_27":293,"minecraft:element_28":294,"minecraft:element_29":295,"minecraft:element_30":296,"minecraft:element_31":297,"minecraft:element_32":298,"minecraft:element_33":299,"minecraft:element_34":300,"minecraft:element_35":301,"minecraft:element_36":302,"minecraft:element_37":303,"minecraft:element_38":304,"minecraft:element_39":305,"minecraft:element_40":306,"minecraft:element_41":307,"minecraft:element_42":308,"minecraft:element_43":309,"minecraft:element_44":310,"minecraft:element_45":311,"minecraft:element_46":312,"minecraft:element_47":313,"minecraft:element_48":314,"minecraft:element_49":315,"minecraft:element_50":316,"minecraft:element_51":317,"minecraft:element_52":318,"minecraft:element_53":319,"minecraft:element_54":320,"minecraft:element_55":321,"minecraft:element_56":322,"minecraft:element_57":323,"minecraft:element_58":324,"minecraft:element_59":325,"minecraft:element_60":326,"minecraft:element_61":327,"minecraft:element_62":328,"minecraft:element_63":329,"minecraft:element_64":330,"minecraft:element_65":331,"minecraft:element_66":332,"minecraft:element_67":333,"minecraft:element_68":334,"minecraft:element_69":335,"minecraft:element_70":336,"minecraft:element_71":337,"minecraft:element_72":338,"minecraft:element_73":339,"minecraft:element_74":340,"minecraft:element_75":341,"minecraft:element_76":342,"minecraft:element_77":343,"minecraft:element_78":344,"minecraft:element_79":345,"minecraft:element_80":346,"minecraft:element_81":347,"minecraft:element_82":348,"minecraft:element_83":349,"minecraft:element_84":350,"minecraft:element_85":351,"minecraft:element_86":352,"minecraft:element_87":353,"minecraft:element_88":354,"minecraft:element_89":355,"minecraft:element_90":356,"minecraft:element_91":357,"minecraft:element_92":358,"minecraft:element_93":359,"minecraft:element_94":360,"minecraft:element_95":361,"minecraft:element_96":362,"minecraft:element_97":363,"minecraft:element_98":364,"minecraft:element_99":365,"minecraft:element_100":366,"minecraft:element_101":367,"minecraft:element_102":368,"minecraft:element_103":369,"minecraft:element_104":370,"minecraft:element_105":371,"minecraft:element_106":372,"minecraft:element_107":373,"minecraft:element_108":374,"minecraft:element_109":375,"minecraft:element_110":376,"minecraft:element_111":377,"minecraft:element_112":378,"minecraft:element_113":379,"minecraft:element_114":380,"minecraft:element_115":381,"minecraft:element_116":382,"minecraft:element_117":383,"minecraft:element_118":384,"minecraft:seagrass":385,"minecraft:coral":386,"minecraft:coral_block":387,"minecraft:coral_fan":388,"minecraft:coral_fan_dead":389,"minecraft:coral_fan_hang":390,"minecraft:coral_fan_hang2":391,"minecraft:coral_fan_hang3":392,"minecraft:kelp":393,"minecraft:dried_kelp_block":394,"minecraft:acacia_button":395,"minecraft:birch_button":396,"minecraft:dark_oak_button":397,"minecraft:jungle_button":398,"minecraft:spruce_button":399,"minecraft:acacia_trapdoor":400,"minecraft:birch_trapdoor":401,"minecraft:dark_oak_trapdoor":402,"minecraft:jungle_trapdoor":403,"minecraft:spruce_trapdoor":404,"minecraft:acacia_pressure_plate":405,"minecraft:birch_pressure_plate":406,"minecraft:dark_oak_pressure_plate":407,"minecraft:jungle_pressure_plate":408,"minecraft:spruce_pressure_plate":409,"minecraft:carved_pumpkin":410,"minecraft:sea_pickle":411,"minecraft:conduit":412,"minecraft:turtle_egg":414,"minecraft:bubble_column":415,"minecraft:barrier":416,"minecraft:stone_slab3":417,"minecraft:bamboo":418,"minecraft:bamboo_sapling":419,"minecraft:scaffolding":420,"minecraft:stone_slab4":421,"minecraft:double_stone_slab3":422,"minecraft:double_stone_slab4":423,"minecraft:granite_stairs":424,"minecraft:diorite_stairs":425,"minecraft:andesite_stairs":426,"minecraft:polished_granite_stairs":427,"minecraft:polished_diorite_stairs":428,"minecraft:polished_andesite_stairs":429,"minecraft:mossy_stone_brick_stairs":430,"minecraft:smooth_red_sandstone_stairs":431,"minecraft:smooth_sandstone_stairs":432,"minecraft:end_brick_stairs":433,"minecraft:mossy_cobblestone_stairs":434,"minecraft:normal_stone_stairs":435,"minecraft:spruce_standing_sign":436,"minecraft:spruce_wall_sign":437,"minecraft:smooth_stone":438,"minecraft:red_nether_brick_stairs":439,"minecraft:smooth_quartz_stairs":440,"minecraft:birch_standing_sign":441,"minecraft:birch_wall_sign":442,"minecraft:jungle_standing_sign":443,"minecraft:jungle_wall_sign":444,"minecraft:acacia_standing_sign":445,"minecraft:acacia_wall_sign":446,"minecraft:darkoak_standing_sign":447,"minecraft:darkoak_wall_sign":448,"minecraft:lectern":449,"minecraft:grindstone":450,"minecraft:blast_furnace":451,"minecraft:stonecutter_block":452,"minecraft:smoker":453,"minecraft:lit_smoker":454,"minecraft:cartography_table":455,"minecraft:fletching_table":456,"minecraft:smithing_table":457,"minecraft:barrel":458,"minecraft:loom":459,"minecraft:bell":461,"minecraft:sweet_berry_bush":462,"minecraft:lantern":463,"minecraft:campfire":464,"minecraft:lava_cauldron":465,"minecraft:jigsaw":466,"minecraft:wood":467,"minecraft:composter":468,"minecraft:lit_blast_furnace":469,"minecraft:light_block":470,"minecraft:wither_rose":471,"minecraft:stickyPistonArmCollision":472,"minecraft:bee_nest":473,"minecraft:beehive":474,"minecraft:honey_block":475,"minecraft:honeycomb_block":476,"minecraft:lodestone":477,"minecraft:crimson_roots":478,"minecraft:warped_roots":479,"minecraft:crimson_stem":480,"minecraft:warped_stem":481,"minecraft:warped_wart_block":482,"minecraft:crimson_fungus":483,"minecraft:warped_fungus":484,"minecraft:shroomlight":485,"minecraft:weeping_vines":486,"minecraft:crimson_nylium":487,"minecraft:warped_nylium":488,"minecraft:basalt":489,"minecraft:polished_basalt":490,"minecraft:soul_soil":491,"minecraft:soul_fire":492,"minecraft:nether_sprouts":493,"minecraft:target":494,"minecraft:stripped_crimson_stem":495,"minecraft:stripped_warped_stem":496,"minecraft:crimson_planks":497,"minecraft:warped_planks":498,"minecraft:crimson_door":499,"minecraft:warped_door":500,"minecraft:crimson_trapdoor":501,"minecraft:warped_trapdoor":502,"minecraft:crimson_standing_sign":505,"minecraft:warped_standing_sign":506,"minecraft:crimson_wall_sign":507,"minecraft:warped_wall_sign":508,"minecraft:crimson_stairs":509,"minecraft:warped_stairs":510,"minecraft:crimson_fence":511,"minecraft:warped_fence":512,"minecraft:crimson_fence_gate":513,"minecraft:warped_fence_gate":514,"minecraft:crimson_button":515,"minecraft:warped_button":516,"minecraft:crimson_pressure_plate":517,"minecraft:warped_pressure_plate":518,"minecraft:crimson_slab":519,"minecraft:warped_slab":520,"minecraft:crimson_double_slab":521,"minecraft:warped_double_slab":522,"minecraft:soul_torch":523,"minecraft:soul_lantern":524,"minecraft:netherite_block":525,"minecraft:ancient_debris":526,"minecraft:respawn_anchor":527,"minecraft:blackstone":528,"minecraft:polished_blackstone_bricks":529,"minecraft:polished_blackstone_brick_stairs":530,"minecraft:blackstone_stairs":531,"minecraft:blackstone_wall":532,"minecraft:polished_blackstone_brick_wall":533,"minecraft:chiseled_polished_blackstone":534,"minecraft:cracked_polished_blackstone_bricks":535,"minecraft:gilded_blackstone":536,"minecraft:blackstone_slab":537,"minecraft:blackstone_double_slab":538,"minecraft:polished_blackstone_brick_slab":539,"minecraft:polished_blackstone_brick_double_slab":540,"minecraft:chain":541,"minecraft:twisting_vines":542,"minecraft:nether_gold_ore":543,"minecraft:crying_obsidian":544,"minecraft:soul_campfire":545,"minecraft:polished_blackstone":546,"minecraft:polished_blackstone_stairs":547,"minecraft:polished_blackstone_slab":548,"minecraft:polished_blackstone_double_slab":549,"minecraft:polished_blackstone_pressure_plate":550,"minecraft:polished_blackstone_button":551,"minecraft:polished_blackstone_wall":552,"minecraft:warped_hyphae":553,"minecraft:crimson_hyphae":554,"minecraft:stripped_crimson_hyphae":555,"minecraft:stripped_warped_hyphae":556,"minecraft:chiseled_nether_bricks":557,"minecraft:cracked_nether_bricks":558,"minecraft:quartz_bricks":559} -------------------------------------------------------------------------------- /resources/vanilla/canonical_block_states_1_16_220.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/canonical_block_states_1_16_220.nbt -------------------------------------------------------------------------------- /resources/vanilla/canonical_block_states_1_17_0.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/canonical_block_states_1_17_0.nbt -------------------------------------------------------------------------------- /resources/vanilla/canonical_block_states_1_17_10.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/canonical_block_states_1_17_10.nbt -------------------------------------------------------------------------------- /resources/vanilla/canonical_block_states_1_17_30.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/canonical_block_states_1_17_30.nbt -------------------------------------------------------------------------------- /resources/vanilla/canonical_block_states_1_17_40.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/canonical_block_states_1_17_40.nbt -------------------------------------------------------------------------------- /resources/vanilla/r12_to_current_block_map_1_16_220.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/r12_to_current_block_map_1_16_220.bin -------------------------------------------------------------------------------- /resources/vanilla/r12_to_current_block_map_1_17_10.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/r12_to_current_block_map_1_17_10.bin -------------------------------------------------------------------------------- /resources/vanilla/r12_to_current_block_map_1_17_30.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Laith98Dev/MultiVersion/b161a7b7f443656eefe312dce34cfbf52334698a/resources/vanilla/r12_to_current_block_map_1_17_30.bin -------------------------------------------------------------------------------- /resources/vanilla/required_item_list_1_16_220.json: -------------------------------------------------------------------------------- 1 | {"minecraft:acacia_boat":{"runtime_id":377,"component_based":false},"minecraft:acacia_button":{"runtime_id":-140,"component_based":false},"minecraft:acacia_door":{"runtime_id":546,"component_based":false},"minecraft:acacia_fence_gate":{"runtime_id":187,"component_based":false},"minecraft:acacia_pressure_plate":{"runtime_id":-150,"component_based":false},"minecraft:acacia_sign":{"runtime_id":569,"component_based":false},"minecraft:acacia_stairs":{"runtime_id":163,"component_based":false},"minecraft:acacia_standing_sign":{"runtime_id":-190,"component_based":false},"minecraft:acacia_trapdoor":{"runtime_id":-145,"component_based":false},"minecraft:acacia_wall_sign":{"runtime_id":-191,"component_based":false},"minecraft:activator_rail":{"runtime_id":126,"component_based":false},"minecraft:agent_spawn_egg":{"runtime_id":485,"component_based":false},"minecraft:air":{"runtime_id":-158,"component_based":false},"minecraft:allow":{"runtime_id":210,"component_based":false},"minecraft:ancient_debris":{"runtime_id":-271,"component_based":false},"minecraft:andesite_stairs":{"runtime_id":-171,"component_based":false},"minecraft:anvil":{"runtime_id":145,"component_based":false},"minecraft:apple":{"runtime_id":257,"component_based":false},"minecraft:armor_stand":{"runtime_id":542,"component_based":false},"minecraft:arrow":{"runtime_id":301,"component_based":false},"minecraft:baked_potato":{"runtime_id":281,"component_based":false},"minecraft:balloon":{"runtime_id":587,"component_based":false},"minecraft:bamboo":{"runtime_id":-163,"component_based":false},"minecraft:bamboo_sapling":{"runtime_id":-164,"component_based":false},"minecraft:banner":{"runtime_id":557,"component_based":false},"minecraft:banner_pattern":{"runtime_id":613,"component_based":false},"minecraft:barrel":{"runtime_id":-203,"component_based":false},"minecraft:barrier":{"runtime_id":-161,"component_based":false},"minecraft:basalt":{"runtime_id":-234,"component_based":false},"minecraft:bat_spawn_egg":{"runtime_id":451,"component_based":false},"minecraft:beacon":{"runtime_id":138,"component_based":false},"minecraft:bed":{"runtime_id":416,"component_based":false},"minecraft:bedrock":{"runtime_id":7,"component_based":false},"minecraft:bee_nest":{"runtime_id":-218,"component_based":false},"minecraft:bee_spawn_egg":{"runtime_id":492,"component_based":false},"minecraft:beef":{"runtime_id":273,"component_based":false},"minecraft:beehive":{"runtime_id":-219,"component_based":false},"minecraft:beetroot":{"runtime_id":285,"component_based":false},"minecraft:beetroot_seeds":{"runtime_id":295,"component_based":false},"minecraft:beetroot_soup":{"runtime_id":286,"component_based":false},"minecraft:bell":{"runtime_id":-206,"component_based":false},"minecraft:birch_boat":{"runtime_id":374,"component_based":false},"minecraft:birch_button":{"runtime_id":-141,"component_based":false},"minecraft:birch_door":{"runtime_id":544,"component_based":false},"minecraft:birch_fence_gate":{"runtime_id":184,"component_based":false},"minecraft:birch_pressure_plate":{"runtime_id":-151,"component_based":false},"minecraft:birch_sign":{"runtime_id":567,"component_based":false},"minecraft:birch_stairs":{"runtime_id":135,"component_based":false},"minecraft:birch_standing_sign":{"runtime_id":-186,"component_based":false},"minecraft:birch_trapdoor":{"runtime_id":-146,"component_based":false},"minecraft:birch_wall_sign":{"runtime_id":-187,"component_based":false},"minecraft:black_dye":{"runtime_id":393,"component_based":false},"minecraft:black_glazed_terracotta":{"runtime_id":235,"component_based":false},"minecraft:blackstone":{"runtime_id":-273,"component_based":false},"minecraft:blackstone_double_slab":{"runtime_id":-283,"component_based":false},"minecraft:blackstone_slab":{"runtime_id":-282,"component_based":false},"minecraft:blackstone_stairs":{"runtime_id":-276,"component_based":false},"minecraft:blackstone_wall":{"runtime_id":-277,"component_based":false},"minecraft:blast_furnace":{"runtime_id":-196,"component_based":false},"minecraft:blaze_powder":{"runtime_id":427,"component_based":false},"minecraft:blaze_rod":{"runtime_id":421,"component_based":false},"minecraft:blaze_spawn_egg":{"runtime_id":454,"component_based":false},"minecraft:bleach":{"runtime_id":585,"component_based":false},"minecraft:blue_dye":{"runtime_id":397,"component_based":false},"minecraft:blue_glazed_terracotta":{"runtime_id":231,"component_based":false},"minecraft:blue_ice":{"runtime_id":-11,"component_based":false},"minecraft:boat":{"runtime_id":611,"component_based":false},"minecraft:bone":{"runtime_id":413,"component_based":false},"minecraft:bone_block":{"runtime_id":216,"component_based":false},"minecraft:bone_meal":{"runtime_id":409,"component_based":false},"minecraft:book":{"runtime_id":385,"component_based":false},"minecraft:bookshelf":{"runtime_id":47,"component_based":false},"minecraft:border_block":{"runtime_id":212,"component_based":false},"minecraft:bordure_indented_banner_pattern":{"runtime_id":576,"component_based":false},"minecraft:bow":{"runtime_id":300,"component_based":false},"minecraft:bowl":{"runtime_id":321,"component_based":false},"minecraft:bread":{"runtime_id":261,"component_based":false},"minecraft:brewing_stand":{"runtime_id":429,"component_based":false},"minecraft:brewingstandblock":{"runtime_id":117,"component_based":false},"minecraft:brick":{"runtime_id":381,"component_based":false},"minecraft:brick_block":{"runtime_id":45,"component_based":false},"minecraft:brick_stairs":{"runtime_id":108,"component_based":false},"minecraft:brown_dye":{"runtime_id":396,"component_based":false},"minecraft:brown_glazed_terracotta":{"runtime_id":232,"component_based":false},"minecraft:brown_mushroom":{"runtime_id":39,"component_based":false},"minecraft:brown_mushroom_block":{"runtime_id":99,"component_based":false},"minecraft:bubble_column":{"runtime_id":-160,"component_based":false},"minecraft:bucket":{"runtime_id":360,"component_based":false},"minecraft:cactus":{"runtime_id":81,"component_based":false},"minecraft:cake":{"runtime_id":415,"component_based":false},"minecraft:camera":{"runtime_id":582,"component_based":false},"minecraft:campfire":{"runtime_id":578,"component_based":false},"minecraft:carpet":{"runtime_id":171,"component_based":false},"minecraft:carrot":{"runtime_id":279,"component_based":false},"minecraft:carrot_on_a_stick":{"runtime_id":507,"component_based":false},"minecraft:carrots":{"runtime_id":141,"component_based":false},"minecraft:cartography_table":{"runtime_id":-200,"component_based":false},"minecraft:carved_pumpkin":{"runtime_id":-155,"component_based":false},"minecraft:cat_spawn_egg":{"runtime_id":486,"component_based":false},"minecraft:cauldron":{"runtime_id":430,"component_based":false},"minecraft:cave_spider_spawn_egg":{"runtime_id":455,"component_based":false},"minecraft:chain":{"runtime_id":607,"component_based":false},"minecraft:chain_command_block":{"runtime_id":189,"component_based":false},"minecraft:chainmail_boots":{"runtime_id":342,"component_based":false},"minecraft:chainmail_chestplate":{"runtime_id":340,"component_based":false},"minecraft:chainmail_helmet":{"runtime_id":339,"component_based":false},"minecraft:chainmail_leggings":{"runtime_id":341,"component_based":false},"minecraft:charcoal":{"runtime_id":303,"component_based":false},"minecraft:chemical_heat":{"runtime_id":192,"component_based":false},"minecraft:chemistry_table":{"runtime_id":238,"component_based":false},"minecraft:chest":{"runtime_id":54,"component_based":false},"minecraft:chest_minecart":{"runtime_id":387,"component_based":false},"minecraft:chicken":{"runtime_id":275,"component_based":false},"minecraft:chicken_spawn_egg":{"runtime_id":433,"component_based":false},"minecraft:chiseled_nether_bricks":{"runtime_id":-302,"component_based":false},"minecraft:chiseled_polished_blackstone":{"runtime_id":-279,"component_based":false},"minecraft:chorus_flower":{"runtime_id":200,"component_based":false},"minecraft:chorus_fruit":{"runtime_id":548,"component_based":false},"minecraft:chorus_plant":{"runtime_id":240,"component_based":false},"minecraft:clay":{"runtime_id":82,"component_based":false},"minecraft:clay_ball":{"runtime_id":382,"component_based":false},"minecraft:clock":{"runtime_id":391,"component_based":false},"minecraft:coal":{"runtime_id":302,"component_based":false},"minecraft:coal_block":{"runtime_id":173,"component_based":false},"minecraft:coal_ore":{"runtime_id":16,"component_based":false},"minecraft:cobblestone":{"runtime_id":4,"component_based":false},"minecraft:cobblestone_wall":{"runtime_id":139,"component_based":false},"minecraft:cocoa":{"runtime_id":127,"component_based":false},"minecraft:cocoa_beans":{"runtime_id":410,"component_based":false},"minecraft:cod":{"runtime_id":264,"component_based":false},"minecraft:cod_bucket":{"runtime_id":364,"component_based":false},"minecraft:cod_spawn_egg":{"runtime_id":478,"component_based":false},"minecraft:colored_torch_bp":{"runtime_id":204,"component_based":false},"minecraft:colored_torch_rg":{"runtime_id":202,"component_based":false},"minecraft:command_block":{"runtime_id":137,"component_based":false},"minecraft:command_block_minecart":{"runtime_id":553,"component_based":false},"minecraft:comparator":{"runtime_id":512,"component_based":false},"minecraft:compass":{"runtime_id":389,"component_based":false},"minecraft:composter":{"runtime_id":-213,"component_based":false},"minecraft:compound":{"runtime_id":583,"component_based":false},"minecraft:concrete":{"runtime_id":236,"component_based":false},"minecraft:concrete_powder":{"runtime_id":237,"component_based":false},"minecraft:conduit":{"runtime_id":-157,"component_based":false},"minecraft:cooked_beef":{"runtime_id":274,"component_based":false},"minecraft:cooked_chicken":{"runtime_id":276,"component_based":false},"minecraft:cooked_cod":{"runtime_id":268,"component_based":false},"minecraft:cooked_mutton":{"runtime_id":541,"component_based":false},"minecraft:cooked_porkchop":{"runtime_id":263,"component_based":false},"minecraft:cooked_rabbit":{"runtime_id":289,"component_based":false},"minecraft:cooked_salmon":{"runtime_id":269,"component_based":false},"minecraft:cookie":{"runtime_id":271,"component_based":false},"minecraft:coral":{"runtime_id":-131,"component_based":false},"minecraft:coral_block":{"runtime_id":-132,"component_based":false},"minecraft:coral_fan":{"runtime_id":-133,"component_based":false},"minecraft:coral_fan_dead":{"runtime_id":-134,"component_based":false},"minecraft:coral_fan_hang":{"runtime_id":-135,"component_based":false},"minecraft:coral_fan_hang2":{"runtime_id":-136,"component_based":false},"minecraft:coral_fan_hang3":{"runtime_id":-137,"component_based":false},"minecraft:cow_spawn_egg":{"runtime_id":434,"component_based":false},"minecraft:cracked_nether_bricks":{"runtime_id":-303,"component_based":false},"minecraft:cracked_polished_blackstone_bricks":{"runtime_id":-280,"component_based":false},"minecraft:crafting_table":{"runtime_id":58,"component_based":false},"minecraft:creeper_banner_pattern":{"runtime_id":572,"component_based":false},"minecraft:creeper_spawn_egg":{"runtime_id":439,"component_based":false},"minecraft:crimson_button":{"runtime_id":-260,"component_based":false},"minecraft:crimson_door":{"runtime_id":604,"component_based":false},"minecraft:crimson_double_slab":{"runtime_id":-266,"component_based":false},"minecraft:crimson_fence":{"runtime_id":-256,"component_based":false},"minecraft:crimson_fence_gate":{"runtime_id":-258,"component_based":false},"minecraft:crimson_fungus":{"runtime_id":-228,"component_based":false},"minecraft:crimson_hyphae":{"runtime_id":-299,"component_based":false},"minecraft:crimson_nylium":{"runtime_id":-232,"component_based":false},"minecraft:crimson_planks":{"runtime_id":-242,"component_based":false},"minecraft:crimson_pressure_plate":{"runtime_id":-262,"component_based":false},"minecraft:crimson_roots":{"runtime_id":-223,"component_based":false},"minecraft:crimson_sign":{"runtime_id":602,"component_based":false},"minecraft:crimson_slab":{"runtime_id":-264,"component_based":false},"minecraft:crimson_stairs":{"runtime_id":-254,"component_based":false},"minecraft:crimson_standing_sign":{"runtime_id":-250,"component_based":false},"minecraft:crimson_stem":{"runtime_id":-225,"component_based":false},"minecraft:crimson_trapdoor":{"runtime_id":-246,"component_based":false},"minecraft:crimson_wall_sign":{"runtime_id":-252,"component_based":false},"minecraft:crossbow":{"runtime_id":565,"component_based":false},"minecraft:crying_obsidian":{"runtime_id":-289,"component_based":false},"minecraft:cyan_dye":{"runtime_id":399,"component_based":false},"minecraft:cyan_glazed_terracotta":{"runtime_id":229,"component_based":false},"minecraft:dark_oak_boat":{"runtime_id":378,"component_based":false},"minecraft:dark_oak_button":{"runtime_id":-142,"component_based":false},"minecraft:dark_oak_door":{"runtime_id":547,"component_based":false},"minecraft:dark_oak_fence_gate":{"runtime_id":186,"component_based":false},"minecraft:dark_oak_pressure_plate":{"runtime_id":-152,"component_based":false},"minecraft:dark_oak_sign":{"runtime_id":570,"component_based":false},"minecraft:dark_oak_stairs":{"runtime_id":164,"component_based":false},"minecraft:dark_oak_trapdoor":{"runtime_id":-147,"component_based":false},"minecraft:dark_prismarine_stairs":{"runtime_id":-3,"component_based":false},"minecraft:darkoak_standing_sign":{"runtime_id":-192,"component_based":false},"minecraft:darkoak_wall_sign":{"runtime_id":-193,"component_based":false},"minecraft:daylight_detector":{"runtime_id":151,"component_based":false},"minecraft:daylight_detector_inverted":{"runtime_id":178,"component_based":false},"minecraft:deadbush":{"runtime_id":32,"component_based":false},"minecraft:deny":{"runtime_id":211,"component_based":false},"minecraft:detector_rail":{"runtime_id":28,"component_based":false},"minecraft:diamond":{"runtime_id":304,"component_based":false},"minecraft:diamond_axe":{"runtime_id":319,"component_based":false},"minecraft:diamond_block":{"runtime_id":57,"component_based":false},"minecraft:diamond_boots":{"runtime_id":350,"component_based":false},"minecraft:diamond_chestplate":{"runtime_id":348,"component_based":false},"minecraft:diamond_helmet":{"runtime_id":347,"component_based":false},"minecraft:diamond_hoe":{"runtime_id":332,"component_based":false},"minecraft:diamond_horse_armor":{"runtime_id":523,"component_based":false},"minecraft:diamond_leggings":{"runtime_id":349,"component_based":false},"minecraft:diamond_ore":{"runtime_id":56,"component_based":false},"minecraft:diamond_pickaxe":{"runtime_id":318,"component_based":false},"minecraft:diamond_shovel":{"runtime_id":317,"component_based":false},"minecraft:diamond_sword":{"runtime_id":316,"component_based":false},"minecraft:diorite_stairs":{"runtime_id":-170,"component_based":false},"minecraft:dirt":{"runtime_id":3,"component_based":false},"minecraft:dispenser":{"runtime_id":23,"component_based":false},"minecraft:dolphin_spawn_egg":{"runtime_id":482,"component_based":false},"minecraft:donkey_spawn_egg":{"runtime_id":463,"component_based":false},"minecraft:double_plant":{"runtime_id":175,"component_based":false},"minecraft:double_stone_slab":{"runtime_id":44,"component_based":false},"minecraft:double_stone_slab2":{"runtime_id":182,"component_based":false},"minecraft:double_stone_slab3":{"runtime_id":-162,"component_based":false},"minecraft:double_stone_slab4":{"runtime_id":-166,"component_based":false},"minecraft:double_wooden_slab":{"runtime_id":157,"component_based":false},"minecraft:dragon_breath":{"runtime_id":550,"component_based":false},"minecraft:dragon_egg":{"runtime_id":122,"component_based":false},"minecraft:dried_kelp":{"runtime_id":270,"component_based":false},"minecraft:dried_kelp_block":{"runtime_id":-139,"component_based":false},"minecraft:dropper":{"runtime_id":125,"component_based":false},"minecraft:drowned_spawn_egg":{"runtime_id":481,"component_based":false},"minecraft:dye":{"runtime_id":612,"component_based":false},"minecraft:egg":{"runtime_id":388,"component_based":false},"minecraft:elder_guardian_spawn_egg":{"runtime_id":469,"component_based":false},"minecraft:element_0":{"runtime_id":36,"component_based":false},"minecraft:element_1":{"runtime_id":-12,"component_based":false},"minecraft:element_10":{"runtime_id":-21,"component_based":false},"minecraft:element_100":{"runtime_id":-111,"component_based":false},"minecraft:element_101":{"runtime_id":-112,"component_based":false},"minecraft:element_102":{"runtime_id":-113,"component_based":false},"minecraft:element_103":{"runtime_id":-114,"component_based":false},"minecraft:element_104":{"runtime_id":-115,"component_based":false},"minecraft:element_105":{"runtime_id":-116,"component_based":false},"minecraft:element_106":{"runtime_id":-117,"component_based":false},"minecraft:element_107":{"runtime_id":-118,"component_based":false},"minecraft:element_108":{"runtime_id":-119,"component_based":false},"minecraft:element_109":{"runtime_id":-120,"component_based":false},"minecraft:element_11":{"runtime_id":-22,"component_based":false},"minecraft:element_110":{"runtime_id":-121,"component_based":false},"minecraft:element_111":{"runtime_id":-122,"component_based":false},"minecraft:element_112":{"runtime_id":-123,"component_based":false},"minecraft:element_113":{"runtime_id":-124,"component_based":false},"minecraft:element_114":{"runtime_id":-125,"component_based":false},"minecraft:element_115":{"runtime_id":-126,"component_based":false},"minecraft:element_116":{"runtime_id":-127,"component_based":false},"minecraft:element_117":{"runtime_id":-128,"component_based":false},"minecraft:element_118":{"runtime_id":-129,"component_based":false},"minecraft:element_12":{"runtime_id":-23,"component_based":false},"minecraft:element_13":{"runtime_id":-24,"component_based":false},"minecraft:element_14":{"runtime_id":-25,"component_based":false},"minecraft:element_15":{"runtime_id":-26,"component_based":false},"minecraft:element_16":{"runtime_id":-27,"component_based":false},"minecraft:element_17":{"runtime_id":-28,"component_based":false},"minecraft:element_18":{"runtime_id":-29,"component_based":false},"minecraft:element_19":{"runtime_id":-30,"component_based":false},"minecraft:element_2":{"runtime_id":-13,"component_based":false},"minecraft:element_20":{"runtime_id":-31,"component_based":false},"minecraft:element_21":{"runtime_id":-32,"component_based":false},"minecraft:element_22":{"runtime_id":-33,"component_based":false},"minecraft:element_23":{"runtime_id":-34,"component_based":false},"minecraft:element_24":{"runtime_id":-35,"component_based":false},"minecraft:element_25":{"runtime_id":-36,"component_based":false},"minecraft:element_26":{"runtime_id":-37,"component_based":false},"minecraft:element_27":{"runtime_id":-38,"component_based":false},"minecraft:element_28":{"runtime_id":-39,"component_based":false},"minecraft:element_29":{"runtime_id":-40,"component_based":false},"minecraft:element_3":{"runtime_id":-14,"component_based":false},"minecraft:element_30":{"runtime_id":-41,"component_based":false},"minecraft:element_31":{"runtime_id":-42,"component_based":false},"minecraft:element_32":{"runtime_id":-43,"component_based":false},"minecraft:element_33":{"runtime_id":-44,"component_based":false},"minecraft:element_34":{"runtime_id":-45,"component_based":false},"minecraft:element_35":{"runtime_id":-46,"component_based":false},"minecraft:element_36":{"runtime_id":-47,"component_based":false},"minecraft:element_37":{"runtime_id":-48,"component_based":false},"minecraft:element_38":{"runtime_id":-49,"component_based":false},"minecraft:element_39":{"runtime_id":-50,"component_based":false},"minecraft:element_4":{"runtime_id":-15,"component_based":false},"minecraft:element_40":{"runtime_id":-51,"component_based":false},"minecraft:element_41":{"runtime_id":-52,"component_based":false},"minecraft:element_42":{"runtime_id":-53,"component_based":false},"minecraft:element_43":{"runtime_id":-54,"component_based":false},"minecraft:element_44":{"runtime_id":-55,"component_based":false},"minecraft:element_45":{"runtime_id":-56,"component_based":false},"minecraft:element_46":{"runtime_id":-57,"component_based":false},"minecraft:element_47":{"runtime_id":-58,"component_based":false},"minecraft:element_48":{"runtime_id":-59,"component_based":false},"minecraft:element_49":{"runtime_id":-60,"component_based":false},"minecraft:element_5":{"runtime_id":-16,"component_based":false},"minecraft:element_50":{"runtime_id":-61,"component_based":false},"minecraft:element_51":{"runtime_id":-62,"component_based":false},"minecraft:element_52":{"runtime_id":-63,"component_based":false},"minecraft:element_53":{"runtime_id":-64,"component_based":false},"minecraft:element_54":{"runtime_id":-65,"component_based":false},"minecraft:element_55":{"runtime_id":-66,"component_based":false},"minecraft:element_56":{"runtime_id":-67,"component_based":false},"minecraft:element_57":{"runtime_id":-68,"component_based":false},"minecraft:element_58":{"runtime_id":-69,"component_based":false},"minecraft:element_59":{"runtime_id":-70,"component_based":false},"minecraft:element_6":{"runtime_id":-17,"component_based":false},"minecraft:element_60":{"runtime_id":-71,"component_based":false},"minecraft:element_61":{"runtime_id":-72,"component_based":false},"minecraft:element_62":{"runtime_id":-73,"component_based":false},"minecraft:element_63":{"runtime_id":-74,"component_based":false},"minecraft:element_64":{"runtime_id":-75,"component_based":false},"minecraft:element_65":{"runtime_id":-76,"component_based":false},"minecraft:element_66":{"runtime_id":-77,"component_based":false},"minecraft:element_67":{"runtime_id":-78,"component_based":false},"minecraft:element_68":{"runtime_id":-79,"component_based":false},"minecraft:element_69":{"runtime_id":-80,"component_based":false},"minecraft:element_7":{"runtime_id":-18,"component_based":false},"minecraft:element_70":{"runtime_id":-81,"component_based":false},"minecraft:element_71":{"runtime_id":-82,"component_based":false},"minecraft:element_72":{"runtime_id":-83,"component_based":false},"minecraft:element_73":{"runtime_id":-84,"component_based":false},"minecraft:element_74":{"runtime_id":-85,"component_based":false},"minecraft:element_75":{"runtime_id":-86,"component_based":false},"minecraft:element_76":{"runtime_id":-87,"component_based":false},"minecraft:element_77":{"runtime_id":-88,"component_based":false},"minecraft:element_78":{"runtime_id":-89,"component_based":false},"minecraft:element_79":{"runtime_id":-90,"component_based":false},"minecraft:element_8":{"runtime_id":-19,"component_based":false},"minecraft:element_80":{"runtime_id":-91,"component_based":false},"minecraft:element_81":{"runtime_id":-92,"component_based":false},"minecraft:element_82":{"runtime_id":-93,"component_based":false},"minecraft:element_83":{"runtime_id":-94,"component_based":false},"minecraft:element_84":{"runtime_id":-95,"component_based":false},"minecraft:element_85":{"runtime_id":-96,"component_based":false},"minecraft:element_86":{"runtime_id":-97,"component_based":false},"minecraft:element_87":{"runtime_id":-98,"component_based":false},"minecraft:element_88":{"runtime_id":-99,"component_based":false},"minecraft:element_89":{"runtime_id":-100,"component_based":false},"minecraft:element_9":{"runtime_id":-20,"component_based":false},"minecraft:element_90":{"runtime_id":-101,"component_based":false},"minecraft:element_91":{"runtime_id":-102,"component_based":false},"minecraft:element_92":{"runtime_id":-103,"component_based":false},"minecraft:element_93":{"runtime_id":-104,"component_based":false},"minecraft:element_94":{"runtime_id":-105,"component_based":false},"minecraft:element_95":{"runtime_id":-106,"component_based":false},"minecraft:element_96":{"runtime_id":-107,"component_based":false},"minecraft:element_97":{"runtime_id":-108,"component_based":false},"minecraft:element_98":{"runtime_id":-109,"component_based":false},"minecraft:element_99":{"runtime_id":-110,"component_based":false},"minecraft:elytra":{"runtime_id":554,"component_based":false},"minecraft:emerald":{"runtime_id":502,"component_based":false},"minecraft:emerald_block":{"runtime_id":133,"component_based":false},"minecraft:emerald_ore":{"runtime_id":129,"component_based":false},"minecraft:empty_map":{"runtime_id":505,"component_based":false},"minecraft:enchanted_book":{"runtime_id":511,"component_based":false},"minecraft:enchanted_golden_apple":{"runtime_id":259,"component_based":false},"minecraft:enchanting_table":{"runtime_id":116,"component_based":false},"minecraft:end_brick_stairs":{"runtime_id":-178,"component_based":false},"minecraft:end_bricks":{"runtime_id":206,"component_based":false},"minecraft:end_crystal":{"runtime_id":615,"component_based":false},"minecraft:end_gateway":{"runtime_id":209,"component_based":false},"minecraft:end_portal":{"runtime_id":119,"component_based":false},"minecraft:end_portal_frame":{"runtime_id":120,"component_based":false},"minecraft:end_rod":{"runtime_id":208,"component_based":false},"minecraft:end_stone":{"runtime_id":121,"component_based":false},"minecraft:ender_chest":{"runtime_id":130,"component_based":false},"minecraft:ender_eye":{"runtime_id":431,"component_based":false},"minecraft:ender_pearl":{"runtime_id":420,"component_based":false},"minecraft:enderman_spawn_egg":{"runtime_id":440,"component_based":false},"minecraft:endermite_spawn_egg":{"runtime_id":458,"component_based":false},"minecraft:evoker_spawn_egg":{"runtime_id":473,"component_based":false},"minecraft:experience_bottle":{"runtime_id":498,"component_based":false},"minecraft:farmland":{"runtime_id":60,"component_based":false},"minecraft:feather":{"runtime_id":327,"component_based":false},"minecraft:fence":{"runtime_id":85,"component_based":false},"minecraft:fence_gate":{"runtime_id":107,"component_based":false},"minecraft:fermented_spider_eye":{"runtime_id":426,"component_based":false},"minecraft:field_masoned_banner_pattern":{"runtime_id":575,"component_based":false},"minecraft:filled_map":{"runtime_id":418,"component_based":false},"minecraft:fire":{"runtime_id":51,"component_based":false},"minecraft:fire_charge":{"runtime_id":499,"component_based":false},"minecraft:firework_rocket":{"runtime_id":509,"component_based":false},"minecraft:firework_star":{"runtime_id":510,"component_based":false},"minecraft:fishing_rod":{"runtime_id":390,"component_based":false},"minecraft:fletching_table":{"runtime_id":-201,"component_based":false},"minecraft:flint":{"runtime_id":356,"component_based":false},"minecraft:flint_and_steel":{"runtime_id":299,"component_based":false},"minecraft:flower_banner_pattern":{"runtime_id":571,"component_based":false},"minecraft:flower_pot":{"runtime_id":504,"component_based":false},"minecraft:flowing_lava":{"runtime_id":10,"component_based":false},"minecraft:flowing_water":{"runtime_id":8,"component_based":false},"minecraft:fox_spawn_egg":{"runtime_id":488,"component_based":false},"minecraft:frame":{"runtime_id":503,"component_based":false},"minecraft:frosted_ice":{"runtime_id":207,"component_based":false},"minecraft:furnace":{"runtime_id":61,"component_based":false},"minecraft:ghast_spawn_egg":{"runtime_id":452,"component_based":false},"minecraft:ghast_tear":{"runtime_id":422,"component_based":false},"minecraft:gilded_blackstone":{"runtime_id":-281,"component_based":false},"minecraft:glass":{"runtime_id":20,"component_based":false},"minecraft:glass_bottle":{"runtime_id":425,"component_based":false},"minecraft:glass_pane":{"runtime_id":102,"component_based":false},"minecraft:glistering_melon_slice":{"runtime_id":432,"component_based":false},"minecraft:glow_stick":{"runtime_id":166,"component_based":false},"minecraft:glowingobsidian":{"runtime_id":246,"component_based":false},"minecraft:glowstone":{"runtime_id":89,"component_based":false},"minecraft:glowstone_dust":{"runtime_id":392,"component_based":false},"minecraft:gold_block":{"runtime_id":41,"component_based":false},"minecraft:gold_ingot":{"runtime_id":306,"component_based":false},"minecraft:gold_nugget":{"runtime_id":423,"component_based":false},"minecraft:gold_ore":{"runtime_id":14,"component_based":false},"minecraft:golden_apple":{"runtime_id":258,"component_based":false},"minecraft:golden_axe":{"runtime_id":325,"component_based":false},"minecraft:golden_boots":{"runtime_id":354,"component_based":false},"minecraft:golden_carrot":{"runtime_id":283,"component_based":false},"minecraft:golden_chestplate":{"runtime_id":352,"component_based":false},"minecraft:golden_helmet":{"runtime_id":351,"component_based":false},"minecraft:golden_hoe":{"runtime_id":333,"component_based":false},"minecraft:golden_horse_armor":{"runtime_id":522,"component_based":false},"minecraft:golden_leggings":{"runtime_id":353,"component_based":false},"minecraft:golden_pickaxe":{"runtime_id":324,"component_based":false},"minecraft:golden_rail":{"runtime_id":27,"component_based":false},"minecraft:golden_shovel":{"runtime_id":323,"component_based":false},"minecraft:golden_sword":{"runtime_id":322,"component_based":false},"minecraft:granite_stairs":{"runtime_id":-169,"component_based":false},"minecraft:grass":{"runtime_id":2,"component_based":false},"minecraft:grass_path":{"runtime_id":198,"component_based":false},"minecraft:gravel":{"runtime_id":13,"component_based":false},"minecraft:gray_dye":{"runtime_id":401,"component_based":false},"minecraft:gray_glazed_terracotta":{"runtime_id":227,"component_based":false},"minecraft:green_dye":{"runtime_id":395,"component_based":false},"minecraft:green_glazed_terracotta":{"runtime_id":233,"component_based":false},"minecraft:grindstone":{"runtime_id":-195,"component_based":false},"minecraft:guardian_spawn_egg":{"runtime_id":459,"component_based":false},"minecraft:gunpowder":{"runtime_id":328,"component_based":false},"minecraft:hard_glass":{"runtime_id":253,"component_based":false},"minecraft:hard_glass_pane":{"runtime_id":190,"component_based":false},"minecraft:hard_stained_glass":{"runtime_id":254,"component_based":false},"minecraft:hard_stained_glass_pane":{"runtime_id":191,"component_based":false},"minecraft:hardened_clay":{"runtime_id":172,"component_based":false},"minecraft:hay_block":{"runtime_id":170,"component_based":false},"minecraft:heart_of_the_sea":{"runtime_id":561,"component_based":false},"minecraft:heavy_weighted_pressure_plate":{"runtime_id":148,"component_based":false},"minecraft:hoglin_spawn_egg":{"runtime_id":494,"component_based":false},"minecraft:honey_block":{"runtime_id":-220,"component_based":false},"minecraft:honey_bottle":{"runtime_id":581,"component_based":false},"minecraft:honeycomb":{"runtime_id":580,"component_based":false},"minecraft:honeycomb_block":{"runtime_id":-221,"component_based":false},"minecraft:hopper":{"runtime_id":517,"component_based":false},"minecraft:hopper_minecart":{"runtime_id":516,"component_based":false},"minecraft:horse_spawn_egg":{"runtime_id":456,"component_based":false},"minecraft:husk_spawn_egg":{"runtime_id":461,"component_based":false},"minecraft:ice":{"runtime_id":79,"component_based":false},"minecraft:ice_bomb":{"runtime_id":584,"component_based":false},"minecraft:info_update":{"runtime_id":248,"component_based":false},"minecraft:info_update2":{"runtime_id":249,"component_based":false},"minecraft:ink_sac":{"runtime_id":411,"component_based":false},"minecraft:invisiblebedrock":{"runtime_id":95,"component_based":false},"minecraft:iron_axe":{"runtime_id":298,"component_based":false},"minecraft:iron_bars":{"runtime_id":101,"component_based":false},"minecraft:iron_block":{"runtime_id":42,"component_based":false},"minecraft:iron_boots":{"runtime_id":346,"component_based":false},"minecraft:iron_chestplate":{"runtime_id":344,"component_based":false},"minecraft:iron_door":{"runtime_id":370,"component_based":false},"minecraft:iron_helmet":{"runtime_id":343,"component_based":false},"minecraft:iron_hoe":{"runtime_id":331,"component_based":false},"minecraft:iron_horse_armor":{"runtime_id":521,"component_based":false},"minecraft:iron_ingot":{"runtime_id":305,"component_based":false},"minecraft:iron_leggings":{"runtime_id":345,"component_based":false},"minecraft:iron_nugget":{"runtime_id":559,"component_based":false},"minecraft:iron_ore":{"runtime_id":15,"component_based":false},"minecraft:iron_pickaxe":{"runtime_id":297,"component_based":false},"minecraft:iron_shovel":{"runtime_id":296,"component_based":false},"minecraft:iron_sword":{"runtime_id":307,"component_based":false},"minecraft:iron_trapdoor":{"runtime_id":167,"component_based":false},"minecraft:item.acacia_door":{"runtime_id":196,"component_based":false},"minecraft:item.bed":{"runtime_id":26,"component_based":false},"minecraft:item.beetroot":{"runtime_id":244,"component_based":false},"minecraft:item.birch_door":{"runtime_id":194,"component_based":false},"minecraft:item.cake":{"runtime_id":92,"component_based":false},"minecraft:item.camera":{"runtime_id":242,"component_based":false},"minecraft:item.campfire":{"runtime_id":-209,"component_based":false},"minecraft:item.cauldron":{"runtime_id":118,"component_based":false},"minecraft:item.chain":{"runtime_id":-286,"component_based":false},"minecraft:item.crimson_door":{"runtime_id":-244,"component_based":false},"minecraft:item.dark_oak_door":{"runtime_id":197,"component_based":false},"minecraft:item.flower_pot":{"runtime_id":140,"component_based":false},"minecraft:item.frame":{"runtime_id":199,"component_based":false},"minecraft:item.hopper":{"runtime_id":154,"component_based":false},"minecraft:item.iron_door":{"runtime_id":71,"component_based":false},"minecraft:item.jungle_door":{"runtime_id":195,"component_based":false},"minecraft:item.kelp":{"runtime_id":-138,"component_based":false},"minecraft:item.nether_sprouts":{"runtime_id":-238,"component_based":false},"minecraft:item.nether_wart":{"runtime_id":115,"component_based":false},"minecraft:item.reeds":{"runtime_id":83,"component_based":false},"minecraft:item.skull":{"runtime_id":144,"component_based":false},"minecraft:item.soul_campfire":{"runtime_id":-290,"component_based":false},"minecraft:item.spruce_door":{"runtime_id":193,"component_based":false},"minecraft:item.warped_door":{"runtime_id":-245,"component_based":false},"minecraft:item.wheat":{"runtime_id":59,"component_based":false},"minecraft:item.wooden_door":{"runtime_id":64,"component_based":false},"minecraft:jigsaw":{"runtime_id":-211,"component_based":false},"minecraft:jukebox":{"runtime_id":84,"component_based":false},"minecraft:jungle_boat":{"runtime_id":375,"component_based":false},"minecraft:jungle_button":{"runtime_id":-143,"component_based":false},"minecraft:jungle_door":{"runtime_id":545,"component_based":false},"minecraft:jungle_fence_gate":{"runtime_id":185,"component_based":false},"minecraft:jungle_pressure_plate":{"runtime_id":-153,"component_based":false},"minecraft:jungle_sign":{"runtime_id":568,"component_based":false},"minecraft:jungle_stairs":{"runtime_id":136,"component_based":false},"minecraft:jungle_standing_sign":{"runtime_id":-188,"component_based":false},"minecraft:jungle_trapdoor":{"runtime_id":-148,"component_based":false},"minecraft:jungle_wall_sign":{"runtime_id":-189,"component_based":false},"minecraft:kelp":{"runtime_id":380,"component_based":false},"minecraft:ladder":{"runtime_id":65,"component_based":false},"minecraft:lantern":{"runtime_id":-208,"component_based":false},"minecraft:lapis_block":{"runtime_id":22,"component_based":false},"minecraft:lapis_lazuli":{"runtime_id":412,"component_based":false},"minecraft:lapis_ore":{"runtime_id":21,"component_based":false},"minecraft:lava":{"runtime_id":11,"component_based":false},"minecraft:lava_bucket":{"runtime_id":363,"component_based":false},"minecraft:lava_cauldron":{"runtime_id":-210,"component_based":false},"minecraft:lead":{"runtime_id":537,"component_based":false},"minecraft:leather":{"runtime_id":379,"component_based":false},"minecraft:leather_boots":{"runtime_id":338,"component_based":false},"minecraft:leather_chestplate":{"runtime_id":336,"component_based":false},"minecraft:leather_helmet":{"runtime_id":335,"component_based":false},"minecraft:leather_horse_armor":{"runtime_id":520,"component_based":false},"minecraft:leather_leggings":{"runtime_id":337,"component_based":false},"minecraft:leaves":{"runtime_id":18,"component_based":false},"minecraft:leaves2":{"runtime_id":161,"component_based":false},"minecraft:lectern":{"runtime_id":-194,"component_based":false},"minecraft:lever":{"runtime_id":69,"component_based":false},"minecraft:light_block":{"runtime_id":-215,"component_based":false},"minecraft:light_blue_dye":{"runtime_id":405,"component_based":false},"minecraft:light_blue_glazed_terracotta":{"runtime_id":223,"component_based":false},"minecraft:light_gray_dye":{"runtime_id":400,"component_based":false},"minecraft:light_weighted_pressure_plate":{"runtime_id":147,"component_based":false},"minecraft:lime_dye":{"runtime_id":403,"component_based":false},"minecraft:lime_glazed_terracotta":{"runtime_id":225,"component_based":false},"minecraft:lingering_potion":{"runtime_id":552,"component_based":false},"minecraft:lit_blast_furnace":{"runtime_id":-214,"component_based":false},"minecraft:lit_furnace":{"runtime_id":62,"component_based":false},"minecraft:lit_pumpkin":{"runtime_id":91,"component_based":false},"minecraft:lit_redstone_lamp":{"runtime_id":124,"component_based":false},"minecraft:lit_redstone_ore":{"runtime_id":74,"component_based":false},"minecraft:lit_smoker":{"runtime_id":-199,"component_based":false},"minecraft:llama_spawn_egg":{"runtime_id":471,"component_based":false},"minecraft:lodestone":{"runtime_id":-222,"component_based":false},"minecraft:lodestone_compass":{"runtime_id":590,"component_based":false},"minecraft:log":{"runtime_id":17,"component_based":false},"minecraft:log2":{"runtime_id":162,"component_based":false},"minecraft:loom":{"runtime_id":-204,"component_based":false},"minecraft:magenta_dye":{"runtime_id":406,"component_based":false},"minecraft:magenta_glazed_terracotta":{"runtime_id":222,"component_based":false},"minecraft:magma":{"runtime_id":213,"component_based":false},"minecraft:magma_cream":{"runtime_id":428,"component_based":false},"minecraft:magma_cube_spawn_egg":{"runtime_id":453,"component_based":false},"minecraft:medicine":{"runtime_id":588,"component_based":false},"minecraft:melon_block":{"runtime_id":103,"component_based":false},"minecraft:melon_seeds":{"runtime_id":293,"component_based":false},"minecraft:melon_slice":{"runtime_id":272,"component_based":false},"minecraft:melon_stem":{"runtime_id":105,"component_based":false},"minecraft:milk_bucket":{"runtime_id":361,"component_based":false},"minecraft:minecart":{"runtime_id":368,"component_based":false},"minecraft:mob_spawner":{"runtime_id":52,"component_based":false},"minecraft:mojang_banner_pattern":{"runtime_id":574,"component_based":false},"minecraft:monster_egg":{"runtime_id":97,"component_based":false},"minecraft:mooshroom_spawn_egg":{"runtime_id":438,"component_based":false},"minecraft:mossy_cobblestone":{"runtime_id":48,"component_based":false},"minecraft:mossy_cobblestone_stairs":{"runtime_id":-179,"component_based":false},"minecraft:mossy_stone_brick_stairs":{"runtime_id":-175,"component_based":false},"minecraft:movingblock":{"runtime_id":250,"component_based":false},"minecraft:mule_spawn_egg":{"runtime_id":464,"component_based":false},"minecraft:mushroom_stew":{"runtime_id":260,"component_based":false},"minecraft:music_disc_11":{"runtime_id":534,"component_based":false},"minecraft:music_disc_13":{"runtime_id":524,"component_based":false},"minecraft:music_disc_blocks":{"runtime_id":526,"component_based":false},"minecraft:music_disc_cat":{"runtime_id":525,"component_based":false},"minecraft:music_disc_chirp":{"runtime_id":527,"component_based":false},"minecraft:music_disc_far":{"runtime_id":528,"component_based":false},"minecraft:music_disc_mall":{"runtime_id":529,"component_based":false},"minecraft:music_disc_mellohi":{"runtime_id":530,"component_based":false},"minecraft:music_disc_pigstep":{"runtime_id":608,"component_based":false},"minecraft:music_disc_stal":{"runtime_id":531,"component_based":false},"minecraft:music_disc_strad":{"runtime_id":532,"component_based":false},"minecraft:music_disc_wait":{"runtime_id":535,"component_based":false},"minecraft:music_disc_ward":{"runtime_id":533,"component_based":false},"minecraft:mutton":{"runtime_id":540,"component_based":false},"minecraft:mycelium":{"runtime_id":110,"component_based":false},"minecraft:name_tag":{"runtime_id":538,"component_based":false},"minecraft:nautilus_shell":{"runtime_id":560,"component_based":false},"minecraft:nether_brick":{"runtime_id":112,"component_based":false},"minecraft:nether_brick_fence":{"runtime_id":113,"component_based":false},"minecraft:nether_brick_stairs":{"runtime_id":114,"component_based":false},"minecraft:nether_gold_ore":{"runtime_id":-288,"component_based":false},"minecraft:nether_sprouts":{"runtime_id":609,"component_based":false},"minecraft:nether_star":{"runtime_id":508,"component_based":false},"minecraft:nether_wart":{"runtime_id":294,"component_based":false},"minecraft:nether_wart_block":{"runtime_id":214,"component_based":false},"minecraft:netherbrick":{"runtime_id":513,"component_based":false},"minecraft:netherite_axe":{"runtime_id":595,"component_based":false},"minecraft:netherite_block":{"runtime_id":-270,"component_based":false},"minecraft:netherite_boots":{"runtime_id":600,"component_based":false},"minecraft:netherite_chestplate":{"runtime_id":598,"component_based":false},"minecraft:netherite_helmet":{"runtime_id":597,"component_based":false},"minecraft:netherite_hoe":{"runtime_id":596,"component_based":false},"minecraft:netherite_ingot":{"runtime_id":591,"component_based":false},"minecraft:netherite_leggings":{"runtime_id":599,"component_based":false},"minecraft:netherite_pickaxe":{"runtime_id":594,"component_based":false},"minecraft:netherite_scrap":{"runtime_id":601,"component_based":false},"minecraft:netherite_shovel":{"runtime_id":593,"component_based":false},"minecraft:netherite_sword":{"runtime_id":592,"component_based":false},"minecraft:netherrack":{"runtime_id":87,"component_based":false},"minecraft:netherreactor":{"runtime_id":247,"component_based":false},"minecraft:normal_stone_stairs":{"runtime_id":-180,"component_based":false},"minecraft:noteblock":{"runtime_id":25,"component_based":false},"minecraft:npc_spawn_egg":{"runtime_id":468,"component_based":false},"minecraft:oak_boat":{"runtime_id":373,"component_based":false},"minecraft:oak_sign":{"runtime_id":358,"component_based":false},"minecraft:oak_stairs":{"runtime_id":53,"component_based":false},"minecraft:observer":{"runtime_id":251,"component_based":false},"minecraft:obsidian":{"runtime_id":49,"component_based":false},"minecraft:ocelot_spawn_egg":{"runtime_id":449,"component_based":false},"minecraft:orange_dye":{"runtime_id":407,"component_based":false},"minecraft:orange_glazed_terracotta":{"runtime_id":221,"component_based":false},"minecraft:packed_ice":{"runtime_id":174,"component_based":false},"minecraft:painting":{"runtime_id":357,"component_based":false},"minecraft:panda_spawn_egg":{"runtime_id":487,"component_based":false},"minecraft:paper":{"runtime_id":384,"component_based":false},"minecraft:parrot_spawn_egg":{"runtime_id":476,"component_based":false},"minecraft:phantom_membrane":{"runtime_id":564,"component_based":false},"minecraft:phantom_spawn_egg":{"runtime_id":484,"component_based":false},"minecraft:pig_spawn_egg":{"runtime_id":435,"component_based":false},"minecraft:piglin_banner_pattern":{"runtime_id":577,"component_based":false},"minecraft:piglin_brute_spawn_egg":{"runtime_id":497,"component_based":false},"minecraft:piglin_spawn_egg":{"runtime_id":495,"component_based":false},"minecraft:pillager_spawn_egg":{"runtime_id":489,"component_based":false},"minecraft:pink_dye":{"runtime_id":402,"component_based":false},"minecraft:pink_glazed_terracotta":{"runtime_id":226,"component_based":false},"minecraft:piston":{"runtime_id":33,"component_based":false},"minecraft:pistonarmcollision":{"runtime_id":34,"component_based":false},"minecraft:planks":{"runtime_id":5,"component_based":false},"minecraft:podzol":{"runtime_id":243,"component_based":false},"minecraft:poisonous_potato":{"runtime_id":282,"component_based":false},"minecraft:polar_bear_spawn_egg":{"runtime_id":470,"component_based":false},"minecraft:polished_andesite_stairs":{"runtime_id":-174,"component_based":false},"minecraft:polished_basalt":{"runtime_id":-235,"component_based":false},"minecraft:polished_blackstone":{"runtime_id":-291,"component_based":false},"minecraft:polished_blackstone_brick_double_slab":{"runtime_id":-285,"component_based":false},"minecraft:polished_blackstone_brick_slab":{"runtime_id":-284,"component_based":false},"minecraft:polished_blackstone_brick_stairs":{"runtime_id":-275,"component_based":false},"minecraft:polished_blackstone_brick_wall":{"runtime_id":-278,"component_based":false},"minecraft:polished_blackstone_bricks":{"runtime_id":-274,"component_based":false},"minecraft:polished_blackstone_button":{"runtime_id":-296,"component_based":false},"minecraft:polished_blackstone_double_slab":{"runtime_id":-294,"component_based":false},"minecraft:polished_blackstone_pressure_plate":{"runtime_id":-295,"component_based":false},"minecraft:polished_blackstone_slab":{"runtime_id":-293,"component_based":false},"minecraft:polished_blackstone_stairs":{"runtime_id":-292,"component_based":false},"minecraft:polished_blackstone_wall":{"runtime_id":-297,"component_based":false},"minecraft:polished_diorite_stairs":{"runtime_id":-173,"component_based":false},"minecraft:polished_granite_stairs":{"runtime_id":-172,"component_based":false},"minecraft:popped_chorus_fruit":{"runtime_id":549,"component_based":false},"minecraft:porkchop":{"runtime_id":262,"component_based":false},"minecraft:portal":{"runtime_id":90,"component_based":false},"minecraft:potato":{"runtime_id":280,"component_based":false},"minecraft:potatoes":{"runtime_id":142,"component_based":false},"minecraft:potion":{"runtime_id":424,"component_based":false},"minecraft:powered_comparator":{"runtime_id":150,"component_based":false},"minecraft:powered_repeater":{"runtime_id":94,"component_based":false},"minecraft:prismarine":{"runtime_id":168,"component_based":false},"minecraft:prismarine_bricks_stairs":{"runtime_id":-4,"component_based":false},"minecraft:prismarine_crystals":{"runtime_id":539,"component_based":false},"minecraft:prismarine_shard":{"runtime_id":555,"component_based":false},"minecraft:prismarine_stairs":{"runtime_id":-2,"component_based":false},"minecraft:pufferfish":{"runtime_id":267,"component_based":false},"minecraft:pufferfish_bucket":{"runtime_id":367,"component_based":false},"minecraft:pufferfish_spawn_egg":{"runtime_id":479,"component_based":false},"minecraft:pumpkin":{"runtime_id":86,"component_based":false},"minecraft:pumpkin_pie":{"runtime_id":284,"component_based":false},"minecraft:pumpkin_seeds":{"runtime_id":292,"component_based":false},"minecraft:pumpkin_stem":{"runtime_id":104,"component_based":false},"minecraft:purple_dye":{"runtime_id":398,"component_based":false},"minecraft:purple_glazed_terracotta":{"runtime_id":219,"component_based":false},"minecraft:purpur_block":{"runtime_id":201,"component_based":false},"minecraft:purpur_stairs":{"runtime_id":203,"component_based":false},"minecraft:quartz":{"runtime_id":514,"component_based":false},"minecraft:quartz_block":{"runtime_id":155,"component_based":false},"minecraft:quartz_bricks":{"runtime_id":-304,"component_based":false},"minecraft:quartz_ore":{"runtime_id":153,"component_based":false},"minecraft:quartz_stairs":{"runtime_id":156,"component_based":false},"minecraft:rabbit":{"runtime_id":288,"component_based":false},"minecraft:rabbit_foot":{"runtime_id":518,"component_based":false},"minecraft:rabbit_hide":{"runtime_id":519,"component_based":false},"minecraft:rabbit_spawn_egg":{"runtime_id":457,"component_based":false},"minecraft:rabbit_stew":{"runtime_id":290,"component_based":false},"minecraft:rail":{"runtime_id":66,"component_based":false},"minecraft:rapid_fertilizer":{"runtime_id":586,"component_based":false},"minecraft:ravager_spawn_egg":{"runtime_id":491,"component_based":false},"minecraft:real_double_stone_slab":{"runtime_id":43,"component_based":false},"minecraft:real_double_stone_slab2":{"runtime_id":181,"component_based":false},"minecraft:real_double_stone_slab3":{"runtime_id":-167,"component_based":false},"minecraft:real_double_stone_slab4":{"runtime_id":-168,"component_based":false},"minecraft:red_dye":{"runtime_id":394,"component_based":false},"minecraft:red_flower":{"runtime_id":38,"component_based":false},"minecraft:red_glazed_terracotta":{"runtime_id":234,"component_based":false},"minecraft:red_mushroom":{"runtime_id":40,"component_based":false},"minecraft:red_mushroom_block":{"runtime_id":100,"component_based":false},"minecraft:red_nether_brick":{"runtime_id":215,"component_based":false},"minecraft:red_nether_brick_stairs":{"runtime_id":-184,"component_based":false},"minecraft:red_sandstone":{"runtime_id":179,"component_based":false},"minecraft:red_sandstone_stairs":{"runtime_id":180,"component_based":false},"minecraft:redstone":{"runtime_id":371,"component_based":false},"minecraft:redstone_block":{"runtime_id":152,"component_based":false},"minecraft:redstone_lamp":{"runtime_id":123,"component_based":false},"minecraft:redstone_ore":{"runtime_id":73,"component_based":false},"minecraft:redstone_torch":{"runtime_id":76,"component_based":false},"minecraft:redstone_wire":{"runtime_id":55,"component_based":false},"minecraft:repeater":{"runtime_id":417,"component_based":false},"minecraft:repeating_command_block":{"runtime_id":188,"component_based":false},"minecraft:reserved6":{"runtime_id":255,"component_based":false},"minecraft:respawn_anchor":{"runtime_id":-272,"component_based":false},"minecraft:rotten_flesh":{"runtime_id":277,"component_based":false},"minecraft:saddle":{"runtime_id":369,"component_based":false},"minecraft:salmon":{"runtime_id":265,"component_based":false},"minecraft:salmon_bucket":{"runtime_id":365,"component_based":false},"minecraft:salmon_spawn_egg":{"runtime_id":480,"component_based":false},"minecraft:sand":{"runtime_id":12,"component_based":false},"minecraft:sandstone":{"runtime_id":24,"component_based":false},"minecraft:sandstone_stairs":{"runtime_id":128,"component_based":false},"minecraft:sapling":{"runtime_id":6,"component_based":false},"minecraft:scaffolding":{"runtime_id":-165,"component_based":false},"minecraft:scute":{"runtime_id":562,"component_based":false},"minecraft:sea_pickle":{"runtime_id":-156,"component_based":false},"minecraft:seagrass":{"runtime_id":-130,"component_based":false},"minecraft:sealantern":{"runtime_id":169,"component_based":false},"minecraft:shears":{"runtime_id":419,"component_based":false},"minecraft:sheep_spawn_egg":{"runtime_id":436,"component_based":false},"minecraft:shield":{"runtime_id":355,"component_based":false},"minecraft:shroomlight":{"runtime_id":-230,"component_based":false},"minecraft:shulker_box":{"runtime_id":218,"component_based":false},"minecraft:shulker_shell":{"runtime_id":556,"component_based":false},"minecraft:shulker_spawn_egg":{"runtime_id":467,"component_based":false},"minecraft:silver_glazed_terracotta":{"runtime_id":228,"component_based":false},"minecraft:silverfish_spawn_egg":{"runtime_id":441,"component_based":false},"minecraft:skeleton_horse_spawn_egg":{"runtime_id":465,"component_based":false},"minecraft:skeleton_spawn_egg":{"runtime_id":442,"component_based":false},"minecraft:skull":{"runtime_id":506,"component_based":false},"minecraft:skull_banner_pattern":{"runtime_id":573,"component_based":false},"minecraft:slime":{"runtime_id":165,"component_based":false},"minecraft:slime_ball":{"runtime_id":386,"component_based":false},"minecraft:slime_spawn_egg":{"runtime_id":443,"component_based":false},"minecraft:smithing_table":{"runtime_id":-202,"component_based":false},"minecraft:smoker":{"runtime_id":-198,"component_based":false},"minecraft:smooth_quartz_stairs":{"runtime_id":-185,"component_based":false},"minecraft:smooth_red_sandstone_stairs":{"runtime_id":-176,"component_based":false},"minecraft:smooth_sandstone_stairs":{"runtime_id":-177,"component_based":false},"minecraft:smooth_stone":{"runtime_id":-183,"component_based":false},"minecraft:snow":{"runtime_id":80,"component_based":false},"minecraft:snow_layer":{"runtime_id":78,"component_based":false},"minecraft:snowball":{"runtime_id":372,"component_based":false},"minecraft:soul_campfire":{"runtime_id":610,"component_based":false},"minecraft:soul_fire":{"runtime_id":-237,"component_based":false},"minecraft:soul_lantern":{"runtime_id":-269,"component_based":false},"minecraft:soul_sand":{"runtime_id":88,"component_based":false},"minecraft:soul_soil":{"runtime_id":-236,"component_based":false},"minecraft:soul_torch":{"runtime_id":-268,"component_based":false},"minecraft:sparkler":{"runtime_id":589,"component_based":false},"minecraft:spawn_egg":{"runtime_id":614,"component_based":false},"minecraft:spider_eye":{"runtime_id":278,"component_based":false},"minecraft:spider_spawn_egg":{"runtime_id":444,"component_based":false},"minecraft:splash_potion":{"runtime_id":551,"component_based":false},"minecraft:sponge":{"runtime_id":19,"component_based":false},"minecraft:spruce_boat":{"runtime_id":376,"component_based":false},"minecraft:spruce_button":{"runtime_id":-144,"component_based":false},"minecraft:spruce_door":{"runtime_id":543,"component_based":false},"minecraft:spruce_fence_gate":{"runtime_id":183,"component_based":false},"minecraft:spruce_pressure_plate":{"runtime_id":-154,"component_based":false},"minecraft:spruce_sign":{"runtime_id":566,"component_based":false},"minecraft:spruce_stairs":{"runtime_id":134,"component_based":false},"minecraft:spruce_standing_sign":{"runtime_id":-181,"component_based":false},"minecraft:spruce_trapdoor":{"runtime_id":-149,"component_based":false},"minecraft:spruce_wall_sign":{"runtime_id":-182,"component_based":false},"minecraft:squid_spawn_egg":{"runtime_id":448,"component_based":false},"minecraft:stained_glass":{"runtime_id":241,"component_based":false},"minecraft:stained_glass_pane":{"runtime_id":160,"component_based":false},"minecraft:stained_hardened_clay":{"runtime_id":159,"component_based":false},"minecraft:standing_banner":{"runtime_id":176,"component_based":false},"minecraft:standing_sign":{"runtime_id":63,"component_based":false},"minecraft:stick":{"runtime_id":320,"component_based":false},"minecraft:sticky_piston":{"runtime_id":29,"component_based":false},"minecraft:stickypistonarmcollision":{"runtime_id":-217,"component_based":false},"minecraft:stone":{"runtime_id":1,"component_based":false},"minecraft:stone_axe":{"runtime_id":315,"component_based":false},"minecraft:stone_brick_stairs":{"runtime_id":109,"component_based":false},"minecraft:stone_button":{"runtime_id":77,"component_based":false},"minecraft:stone_hoe":{"runtime_id":330,"component_based":false},"minecraft:stone_pickaxe":{"runtime_id":314,"component_based":false},"minecraft:stone_pressure_plate":{"runtime_id":70,"component_based":false},"minecraft:stone_shovel":{"runtime_id":313,"component_based":false},"minecraft:stone_stairs":{"runtime_id":67,"component_based":false},"minecraft:stone_sword":{"runtime_id":312,"component_based":false},"minecraft:stonebrick":{"runtime_id":98,"component_based":false},"minecraft:stonecutter":{"runtime_id":245,"component_based":false},"minecraft:stonecutter_block":{"runtime_id":-197,"component_based":false},"minecraft:stray_spawn_egg":{"runtime_id":460,"component_based":false},"minecraft:strider_spawn_egg":{"runtime_id":493,"component_based":false},"minecraft:string":{"runtime_id":326,"component_based":false},"minecraft:stripped_acacia_log":{"runtime_id":-8,"component_based":false},"minecraft:stripped_birch_log":{"runtime_id":-6,"component_based":false},"minecraft:stripped_crimson_hyphae":{"runtime_id":-300,"component_based":false},"minecraft:stripped_crimson_stem":{"runtime_id":-240,"component_based":false},"minecraft:stripped_dark_oak_log":{"runtime_id":-9,"component_based":false},"minecraft:stripped_jungle_log":{"runtime_id":-7,"component_based":false},"minecraft:stripped_oak_log":{"runtime_id":-10,"component_based":false},"minecraft:stripped_spruce_log":{"runtime_id":-5,"component_based":false},"minecraft:stripped_warped_hyphae":{"runtime_id":-301,"component_based":false},"minecraft:stripped_warped_stem":{"runtime_id":-241,"component_based":false},"minecraft:structure_block":{"runtime_id":252,"component_based":false},"minecraft:structure_void":{"runtime_id":217,"component_based":false},"minecraft:sugar":{"runtime_id":414,"component_based":false},"minecraft:sugar_cane":{"runtime_id":383,"component_based":false},"minecraft:suspicious_stew":{"runtime_id":579,"component_based":false},"minecraft:sweet_berries":{"runtime_id":287,"component_based":false},"minecraft:sweet_berry_bush":{"runtime_id":-207,"component_based":false},"minecraft:tallgrass":{"runtime_id":31,"component_based":false},"minecraft:target":{"runtime_id":-239,"component_based":false},"minecraft:tnt":{"runtime_id":46,"component_based":false},"minecraft:tnt_minecart":{"runtime_id":515,"component_based":false},"minecraft:torch":{"runtime_id":50,"component_based":false},"minecraft:totem_of_undying":{"runtime_id":558,"component_based":false},"minecraft:trapdoor":{"runtime_id":96,"component_based":false},"minecraft:trapped_chest":{"runtime_id":146,"component_based":false},"minecraft:trident":{"runtime_id":536,"component_based":false},"minecraft:tripwire":{"runtime_id":132,"component_based":false},"minecraft:tripwire_hook":{"runtime_id":131,"component_based":false},"minecraft:tropical_fish":{"runtime_id":266,"component_based":false},"minecraft:tropical_fish_bucket":{"runtime_id":366,"component_based":false},"minecraft:tropical_fish_spawn_egg":{"runtime_id":477,"component_based":false},"minecraft:turtle_egg":{"runtime_id":-159,"component_based":false},"minecraft:turtle_helmet":{"runtime_id":563,"component_based":false},"minecraft:turtle_spawn_egg":{"runtime_id":483,"component_based":false},"minecraft:twisting_vines":{"runtime_id":-287,"component_based":false},"minecraft:underwater_torch":{"runtime_id":239,"component_based":false},"minecraft:undyed_shulker_box":{"runtime_id":205,"component_based":false},"minecraft:unknown":{"runtime_id":-305,"component_based":false},"minecraft:unlit_redstone_torch":{"runtime_id":75,"component_based":false},"minecraft:unpowered_comparator":{"runtime_id":149,"component_based":false},"minecraft:unpowered_repeater":{"runtime_id":93,"component_based":false},"minecraft:vex_spawn_egg":{"runtime_id":474,"component_based":false},"minecraft:villager_spawn_egg":{"runtime_id":447,"component_based":false},"minecraft:vindicator_spawn_egg":{"runtime_id":472,"component_based":false},"minecraft:vine":{"runtime_id":106,"component_based":false},"minecraft:wall_banner":{"runtime_id":177,"component_based":false},"minecraft:wall_sign":{"runtime_id":68,"component_based":false},"minecraft:wandering_trader_spawn_egg":{"runtime_id":490,"component_based":false},"minecraft:warped_button":{"runtime_id":-261,"component_based":false},"minecraft:warped_door":{"runtime_id":605,"component_based":false},"minecraft:warped_double_slab":{"runtime_id":-267,"component_based":false},"minecraft:warped_fence":{"runtime_id":-257,"component_based":false},"minecraft:warped_fence_gate":{"runtime_id":-259,"component_based":false},"minecraft:warped_fungus":{"runtime_id":-229,"component_based":false},"minecraft:warped_fungus_on_a_stick":{"runtime_id":606,"component_based":false},"minecraft:warped_hyphae":{"runtime_id":-298,"component_based":false},"minecraft:warped_nylium":{"runtime_id":-233,"component_based":false},"minecraft:warped_planks":{"runtime_id":-243,"component_based":false},"minecraft:warped_pressure_plate":{"runtime_id":-263,"component_based":false},"minecraft:warped_roots":{"runtime_id":-224,"component_based":false},"minecraft:warped_sign":{"runtime_id":603,"component_based":false},"minecraft:warped_slab":{"runtime_id":-265,"component_based":false},"minecraft:warped_stairs":{"runtime_id":-255,"component_based":false},"minecraft:warped_standing_sign":{"runtime_id":-251,"component_based":false},"minecraft:warped_stem":{"runtime_id":-226,"component_based":false},"minecraft:warped_trapdoor":{"runtime_id":-247,"component_based":false},"minecraft:warped_wall_sign":{"runtime_id":-253,"component_based":false},"minecraft:warped_wart_block":{"runtime_id":-227,"component_based":false},"minecraft:water":{"runtime_id":9,"component_based":false},"minecraft:water_bucket":{"runtime_id":362,"component_based":false},"minecraft:waterlily":{"runtime_id":111,"component_based":false},"minecraft:web":{"runtime_id":30,"component_based":false},"minecraft:weeping_vines":{"runtime_id":-231,"component_based":false},"minecraft:wheat":{"runtime_id":334,"component_based":false},"minecraft:wheat_seeds":{"runtime_id":291,"component_based":false},"minecraft:white_dye":{"runtime_id":408,"component_based":false},"minecraft:white_glazed_terracotta":{"runtime_id":220,"component_based":false},"minecraft:witch_spawn_egg":{"runtime_id":450,"component_based":false},"minecraft:wither_rose":{"runtime_id":-216,"component_based":false},"minecraft:wither_skeleton_spawn_egg":{"runtime_id":462,"component_based":false},"minecraft:wolf_spawn_egg":{"runtime_id":437,"component_based":false},"minecraft:wood":{"runtime_id":-212,"component_based":false},"minecraft:wooden_axe":{"runtime_id":311,"component_based":false},"minecraft:wooden_button":{"runtime_id":143,"component_based":false},"minecraft:wooden_door":{"runtime_id":359,"component_based":false},"minecraft:wooden_hoe":{"runtime_id":329,"component_based":false},"minecraft:wooden_pickaxe":{"runtime_id":310,"component_based":false},"minecraft:wooden_pressure_plate":{"runtime_id":72,"component_based":false},"minecraft:wooden_shovel":{"runtime_id":309,"component_based":false},"minecraft:wooden_slab":{"runtime_id":158,"component_based":false},"minecraft:wooden_sword":{"runtime_id":308,"component_based":false},"minecraft:wool":{"runtime_id":35,"component_based":false},"minecraft:writable_book":{"runtime_id":500,"component_based":false},"minecraft:written_book":{"runtime_id":501,"component_based":false},"minecraft:yellow_dye":{"runtime_id":404,"component_based":false},"minecraft:yellow_flower":{"runtime_id":37,"component_based":false},"minecraft:yellow_glazed_terracotta":{"runtime_id":224,"component_based":false},"minecraft:zoglin_spawn_egg":{"runtime_id":496,"component_based":false},"minecraft:zombie_horse_spawn_egg":{"runtime_id":466,"component_based":false},"minecraft:zombie_pigman_spawn_egg":{"runtime_id":446,"component_based":false},"minecraft:zombie_spawn_egg":{"runtime_id":445,"component_based":false},"minecraft:zombie_villager_spawn_egg":{"runtime_id":475,"component_based":false}} -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/Config.php: -------------------------------------------------------------------------------- 1 | getOrigin(); 50 | $packet = $event->getPacket(); 51 | if ($packet instanceof PacketViolationWarningPacket) { 52 | Loader::getInstance()->getLogger()->info("PacketViolationWarningPacket packet=" . PacketPool::getInstance()->getPacketById($packet->getPacketId())->getName() . ",message=" . $packet->getMessage() . ",type=" . $packet->getType() . ",severity=" . $packet->getSeverity()); 53 | } 54 | if ($packet instanceof LoginPacket) { 55 | if (!Loader::getInstance()->canJoin) { 56 | $origin->disconnect("Trying to join the server before CraftingManager registered", false); 57 | $event->cancel(); 58 | return; 59 | } 60 | if (!in_array($packet->protocol, ProtocolConstants::SUPPORTED_PROTOCOLS, true) || Loader::getInstance()->isProtocolDisabled($packet->protocol)) { 61 | $origin->sendDataPacket(PlayStatusPacket::create(PlayStatusPacket::LOGIN_FAILED_SERVER), true); 62 | $origin->disconnect(Server::getInstance()->getLanguage()->translateString("pocketmine.disconnect.incompatibleProtocol", [$packet->protocol]), false); 63 | $event->cancel(); 64 | return; 65 | } 66 | if ($packet->protocol === ProtocolInfo::CURRENT_PROTOCOL) { 67 | return; 68 | } 69 | 70 | $packet->protocol = ProtocolInfo::CURRENT_PROTOCOL; 71 | 72 | Utils::forceSetProps($origin, "this", new MultiVersionSessionAdapter(Server::getInstance(), new NetworkSessionManager(), PacketPool::getInstance(), new MultiVersionPacketSender(), $origin->getBroadcaster(), $origin->getCompressor(), $origin->getIp(), $origin->getPort(), $packet->protocol)); 73 | 74 | SessionManager::create($origin, $packet->protocol); 75 | 76 | Translator::fromClient($packet, $packet->protocol, $origin); 77 | } 78 | } 79 | 80 | /** 81 | * @param PlayerQuitEvent $event 82 | * @priority HIGHEST 83 | */ 84 | public function onPlayerQuit(PlayerQuitEvent $event) 85 | { 86 | SessionManager::remove($event->getPlayer()->getNetworkSession()); 87 | } 88 | 89 | /** 90 | * @param DataPacketSendEvent $event 91 | * @priority HIGHEST 92 | * @ignoreCancelled true 93 | */ 94 | public function onDataPacketSend(DataPacketSendEvent $event) 95 | { 96 | if ($this->cancel_send) { 97 | return; 98 | } 99 | 100 | $packets = $event->getPackets(); 101 | $players = $event->getTargets(); 102 | 103 | foreach ($packets as $packet) { 104 | foreach ($players as $session) { 105 | $protocol = SessionManager::getProtocol($session); 106 | $in = PacketSerializer::decoder($packet->getName(), 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())); 107 | if ($protocol === null) { 108 | return; 109 | } 110 | 111 | if ($packet instanceof ModalFormRequestPacket || $packet instanceof NetworkStackLatencyPacket) { 112 | return; // fix form and invmenu plugins not working 113 | } 114 | 115 | if ($packet instanceof CraftingDataPacket) { 116 | $this->cancel_send = true; 117 | $session->sendDataPacket(Loader::getInstance()->craftingManager->getCache(new CraftingManager(), $protocol)); 118 | $this->cancel_send = false; 119 | continue; 120 | } 121 | $packet->decode($in); 122 | $translated = Translator::fromServer($packet, $protocol, $session); 123 | if ($translated === null) { 124 | continue; 125 | } 126 | PacketPool::getInstance()->registerPacket($translated); 127 | 128 | $packet->decode($in); 129 | $translated = true; 130 | $newPacket = Translator::fromServer($packet, $protocol, $session, $translated); 131 | if(!$translated) { 132 | return; 133 | } 134 | if($newPacket === null) { 135 | $event->cancel(); 136 | return; 137 | } 138 | 139 | // $decompress = new DecompressTask($packet, function () use ($session, $packet) { 140 | // $session->sendDataPacket($packet); 141 | // }); 142 | // Server::getInstance()->getAsyncPool()->submitTask($decompress); 143 | $this->cancel_send = true; 144 | $compressor = MultiVersionZlibCompressor::new(); 145 | $context = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()); 146 | $compressor->compress(PacketBatch::fromPackets($context, $packet)->getBuffer()); 147 | $this->cancel_send = false; 148 | // $compress = new CompressTask($packet, function () use ($session, $packet) { 149 | // $this->cancel_send = true; 150 | // $session->sendDataPacket($packet); 151 | // $this->cancel_send = false; 152 | // }); 153 | // Server::getInstance()->getAsyncPool()->submitTask($compress); 154 | if($this->cancel_send === true){ 155 | $this->cancel_send = false; 156 | } 157 | } 158 | } 159 | $event->cancel(); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/Loader.php: -------------------------------------------------------------------------------- 1 | getResources() as $k => $v) { 39 | $this->saveResource($k, $k !== "config.yml"); 40 | } 41 | 42 | Config::init($this->getDataFolder() . "config.yml"); 43 | 44 | self::$resourcesPath = $this->getDataFolder(); 45 | MultiVersionRuntimeBlockMapping::init(); 46 | 47 | // wait until other plugin register custom craft 48 | $this->getScheduler()->scheduleDelayedTask(new ClosureTask(function() : void { 49 | $this->craftingManager = new MultiVersionCraftingManager(); 50 | $this->canJoin = true; 51 | }), 1); 52 | 53 | $this->getServer()->getCommandMap()->register("multiversion", new MultiVersionCommand("multiversion", $this)); 54 | $this->getServer()->getPluginManager()->registerEvents(new EventListener(), $this); 55 | 56 | // CheckUpdateTask::init($this->getDescription()->getVersion()); 57 | } 58 | 59 | public function isProtocolDisabled(int $protocol): bool{ 60 | $config = Config::$DISABLED_PROTOCOLS; 61 | return in_array($protocol, $config, true); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/MultiVersion.php: -------------------------------------------------------------------------------- 1 | getNetworkSession()) ?? ProtocolInfo::CURRENT_PROTOCOL; 15 | } 16 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/MultiVersionPacketSender.php: -------------------------------------------------------------------------------- 1 | setPermission("multiversion.command"); 22 | } 23 | 24 | public function execute(CommandSender $sender, string $commandLabel, array $args){ 25 | if(count($args) === 0) { 26 | return; 27 | } 28 | switch($args[0]) { 29 | case "player": 30 | if(count($args) !== 2) { 31 | $sender->sendMessage(self::PREFIX . "Usage: /multiversion player "); 32 | return; 33 | } 34 | $target = Server::getInstance()->getPlayerExact($args[1]); 35 | if(!$target instanceof Player) { 36 | $sender->sendMessage(self::PREFIX . "Player " . $args[1] . " is not found!"); 37 | return; 38 | } 39 | $protocol = MultiVersion::getProtocol($target); 40 | $ver = ProtocolConstants::MINECRAFT_VERSION[$protocol]; 41 | $sender->sendMessage(self::PREFIX . $target->getName() . " is using version " . $ver . " (Protocol: " . $protocol . " )"); 42 | return; 43 | case "all": 44 | foreach(Server::getInstance()->getOnlinePlayers() as $player) { 45 | $protocol = MultiVersion::getProtocol($player); 46 | $ver = ProtocolConstants::MINECRAFT_VERSION[$protocol]; 47 | $msg = $player->getName() . " [Protocol: " . $protocol . ", Version: " . $ver . "]"; 48 | $sender->sendMessage(self::PREFIX . $msg . "\n"); 49 | } 50 | return; 51 | default: 52 | $sender->sendMessage(self::PREFIX . " Usage: /multiversion "); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/compressor/MultiVersionZlibCompressor.php: -------------------------------------------------------------------------------- 1 | getMethod("make"); 13 | $method->setAccessible(true); 14 | return $method->invoke(self::getInstance(), ""); 15 | } 16 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/Chunk112.php: -------------------------------------------------------------------------------- 1 | getChunkX(); 19 | $z = $origin->getChunkZ(); 20 | $chunk = $level->getChunk($x, $z); 21 | if($chunk !== null){ 22 | $payload = self::networkSerialize($chunk); 23 | return LevelChunkPacket::create($x, $z, $origin->getSubChunkCount() - 4, false, $origin->getUsedBlobHashes(), $payload); 24 | } 25 | return null; 26 | } 27 | 28 | public static function networkSerialize(Chunk $chunk) { 29 | $result = ""; 30 | $subChunkCount = ChunkSerializer::getSubChunkCount($chunk) + ChunkSerializer::LOWER_PADDING_SIZE; 31 | for($y = 0; $y < $subChunkCount; ++$y){ 32 | // $result .= $chunk->getSubChunk($y)->networkSerialize(); 33 | } 34 | $result .= $chunk->getBiomeIdArray() . chr(0); //border block array count 35 | //Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client. 36 | 37 | foreach($chunk->getTiles() as $tile){ 38 | if($tile instanceof Spawnable){ 39 | $result .= $tile->getSerializedSpawnCompound(); 40 | } 41 | } 42 | 43 | return $result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/MultiVersionSessionAdapter.php: -------------------------------------------------------------------------------- 1 | protocol = $protocol; 34 | } 35 | 36 | public function handleDataPacket(Packet $packet, string $buffer): void 37 | { 38 | if(!($packet instanceof ServerboundPacket)){ 39 | throw new PacketHandlingException("Unexpected non-serverbound packet"); 40 | } 41 | 42 | $timings = Timings::getReceiveDataPacketTimings($packet); 43 | $timings->startTiming(); 44 | 45 | try{ 46 | $stream = PacketSerializer::decoder($buffer, 0, $this->getPacketSerializerContext()); 47 | try{ 48 | $packet->decode($stream); 49 | }catch(PacketDecodeException $e){ 50 | throw PacketHandlingException::wrap($e); 51 | } 52 | if(!$stream->feof()){ 53 | $remains = substr($stream->getBuffer(), $stream->getOffset()); 54 | $this->getLogger()->debug("Still " . strlen($remains) . " bytes unread in " . $packet->getName() . ": " . bin2hex($remains)); 55 | } 56 | 57 | $ev = new DataPacketReceiveEvent($this, $packet); 58 | $ev->call(); 59 | if(!$ev->isCancelled() && ($this->getHandler() === null || !$packet->handle($this->getHandler()))){ 60 | $this->getLogger()->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer())); 61 | } 62 | }finally{ 63 | $timings->stopTiming(); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/ProtocolConstants.php: -------------------------------------------------------------------------------- 1 | "1.16.220", 20 | self::BEDROCK_1_17_0 => "1.17.0", 21 | self::BEDROCK_1_17_10 => "1.17.10", 22 | self::BEDROCK_1_17_30 => "1.17.30", 23 | self::BEDROCK_1_17_40 => "1.17.40", 24 | self::BEDROCK_1_18_0 => "1.18.0", 25 | ProtocolInfo::CURRENT_PROTOCOL => ProtocolInfo::MINECRAFT_VERSION_NETWORK 26 | ]; 27 | 28 | public const SUPPORTED_PROTOCOLS = [ 29 | self::BEDROCK_1_16_220, 30 | self::BEDROCK_1_17_0, 31 | self::BEDROCK_1_17_10, 32 | self::BEDROCK_1_17_30, 33 | self::BEDROCK_1_17_40, 34 | self::BEDROCK_1_18_0, 35 | ProtocolInfo::CURRENT_PROTOCOL 36 | ]; 37 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/Serializer.php: -------------------------------------------------------------------------------- 1 | putString($skin->getSkinId()); 40 | $in->putString($skin->getPlayFabId()); 41 | $in->putString($skin->getResourcePatch()); 42 | self::putSkinImage($skin->getSkinImage(), $packet); 43 | $in->putLInt(count($skin->getAnimations())); 44 | foreach($skin->getAnimations() as $animation){ 45 | self::putSkinImage($animation->getImage(), $packet); 46 | $in->putLInt($animation->getType()); 47 | $in->putLFloat($animation->getFrames()); 48 | $in->putLInt($animation->getExpressionType()); 49 | } 50 | self::putSkinImage($skin->getCapeImage(), $packet); 51 | $in->putString($skin->getGeometryData()); 52 | if($protocol >= ProtocolConstants::BEDROCK_1_17_30){ 53 | $in->putString($skin->getGeometryDataEngineVersion()); 54 | } 55 | $in->putString($skin->getAnimationData()); 56 | if($protocol < ProtocolConstants::BEDROCK_1_17_30) { 57 | $in->putBool($skin->isPremium()); 58 | $in->putBool($skin->isPersona()); 59 | $in->putBool($skin->isPersonaCapeOnClassic()); 60 | } 61 | $in->putString($skin->getCapeId()); 62 | $in->putString($skin->getFullSkinId()); 63 | $in->putString($skin->getArmSize()); 64 | $in->putString($skin->getSkinColor()); 65 | $in->putLInt(count($skin->getPersonaPieces())); 66 | foreach($skin->getPersonaPieces() as $piece){ 67 | $in->putString($piece->getPieceId()); 68 | $in->putString($piece->getPieceType()); 69 | $in->putString($piece->getPackId()); 70 | $in->putBool($piece->isDefaultPiece()); 71 | $in->putString($piece->getProductId()); 72 | } 73 | $in->putLInt(count($skin->getPieceTintColors())); 74 | foreach($skin->getPieceTintColors() as $tint){ 75 | $in->putString($tint->getPieceType()); 76 | $in->putLInt(count($tint->getColors())); 77 | foreach($tint->getColors() as $color){ 78 | $in->putString($color); 79 | } 80 | } 81 | if($protocol >= ProtocolConstants::BEDROCK_1_17_30){ 82 | $in->putBool($skin->isPremium()); 83 | $in->putBool($skin->isPersona()); 84 | $in->putBool($skin->isPersonaCapeOnClassic()); 85 | $in->putBool($skin->isPrimaryUser()); 86 | } 87 | } 88 | 89 | public static function getSkin(DataPacket $packet, int $protocol) : SkinData{ 90 | $out = new BinaryStream(); 91 | $skinId = $out->getString(); 92 | $skinPlayFabId = $out->getString(); 93 | $skinResourcePatch = $out->getString(); 94 | $skinData = self::getSkinImage($out); 95 | $animationCount = $out->getLInt(); 96 | $animations = []; 97 | for($i = 0; $i < $animationCount; ++$i){ 98 | $skinImage = self::getSkinImage($out); 99 | $animationType = $out->getLInt(); 100 | $animationFrames = $out->getLFloat(); 101 | $expressionType = $out->getLInt(); 102 | $animations[] = new SkinAnimation($skinImage, $animationType, $animationFrames, $expressionType); 103 | } 104 | $capeData = self::getSkinImage($out); 105 | $geometryData = $out->getString(); 106 | if($protocol >= ProtocolConstants::BEDROCK_1_17_30){ 107 | $geometryDataVersion = $out->getString(); 108 | } 109 | $animationData = $out->getString(); 110 | if($protocol < ProtocolConstants::BEDROCK_1_17_30) { 111 | $premium = $out->getBool(); 112 | $persona = $out->getBool(); 113 | $capeOnClassic = $out->getBool(); 114 | } 115 | $capeId = $out->getString(); 116 | $fullSkinId = $out->getString(); 117 | $armSize = $out->getString(); 118 | $skinColor = $out->getString(); 119 | $personaPieceCount = $out->getLInt(); 120 | $personaPieces = []; 121 | for($i = 0; $i < $personaPieceCount; ++$i){ 122 | $pieceId = $out->getString(); 123 | $pieceType = $out->getString(); 124 | $packId = $out->getString(); 125 | $isDefaultPiece = $out->getBool(); 126 | $productId = $out->getString(); 127 | $personaPieces[] = new PersonaSkinPiece($pieceId, $pieceType, $packId, $isDefaultPiece, $productId); 128 | } 129 | $pieceTintColorCount = $out->getLInt(); 130 | $pieceTintColors = []; 131 | for($i = 0; $i < $pieceTintColorCount; ++$i){ 132 | $pieceType = $out->getString(); 133 | $colorCount = $out->getLInt(); 134 | $colors = []; 135 | for($j = 0; $j < $colorCount; ++$j){ 136 | $colors[] = $out->getString(); 137 | } 138 | $pieceTintColors[] = new PersonaPieceTintColor( 139 | $pieceType, 140 | $colors 141 | ); 142 | } 143 | if($protocol >= ProtocolConstants::BEDROCK_1_17_30){ 144 | $premium = $out->getBool(); 145 | $persona = $out->getBool(); 146 | $capeOnClassic = $out->getBool(); 147 | $isPrimaryUser = $out->getBool(); 148 | } 149 | 150 | return new SkinData($skinId, $skinPlayFabId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $geometryDataVersion ?? "1.17.30", $animationData, $capeId, $fullSkinId, $armSize, $skinColor, $personaPieces, $pieceTintColors, true, $premium ?? false, $persona ?? false, $capeOnClassic ?? false, $isPrimaryUser ?? true); 151 | } 152 | 153 | public static function putSkinImage(SkinImage $image, DataPacket $packet) : void{ 154 | $in = new BinaryStream(); 155 | $in->putLInt($image->getWidth()); 156 | $in->putLInt($image->getHeight()); 157 | $in->putString($image->getData()); 158 | } 159 | 160 | public static function getSkinImage(DataPacket $packet) : SkinImage{ 161 | $out = new BinaryStream(); 162 | $width = $out->getLInt(); 163 | $height = $out->getLInt(); 164 | $data = $out->getString(); 165 | try{ 166 | return new SkinImage($height, $width, $data); 167 | }catch(\InvalidArgumentException $e){ 168 | throw new PacketDecodeException($e->getMessage(), 0, $e); 169 | } 170 | } 171 | 172 | public static function putItemStack(PacketSerializer $packet, int $protocol, Item $item, callable $writeExtraCrapInTheMiddle) { 173 | if($item->getId() === 0){ 174 | $packet->putVarInt(0); 175 | return; 176 | } 177 | 178 | $coreData = $item->getMeta(); 179 | [$netId, $netData] = MultiVersionItemTranslator::getInstance()->toNetworkId($item->getId(), $coreData, $protocol); 180 | 181 | $packet->putVarInt($netId); 182 | $packet->putLShort($item->getCount()); 183 | $packet->putUnsignedVarInt($netData); 184 | 185 | $writeExtraCrapInTheMiddle($packet); 186 | 187 | $blockRuntimeId = 0; 188 | $isBlockItem = $item->getId() < 256; 189 | if($isBlockItem){ 190 | $block = $item->getBlock(); 191 | if($block->getId() !== BlockLegacyIds::AIR){ 192 | $blockRuntimeId = MultiVersionRuntimeBlockMapping::toStaticRuntimeId($block->getId(), $block->getMeta(), $protocol); 193 | } 194 | } 195 | $packet->putVarInt($blockRuntimeId); 196 | 197 | $nbt = null; 198 | if($item->hasNamedTag()){ 199 | $nbt = clone $item->getNamedTag(); 200 | } 201 | if($item instanceof Durable and $coreData > 0){ 202 | if($nbt !== null){ 203 | if(($existing = $nbt->getTag("Meta")) !== null){ 204 | $nbt->removeTag("Meta"); 205 | $nbt->setTag("___Meta_ProtocolCollisionResolution___", $existing); 206 | } 207 | }else{ 208 | $nbt = new CompoundTag(); 209 | } 210 | $nbt->setInt("Meta", $coreData); 211 | }elseif($isBlockItem && $coreData !== 0){ 212 | //TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the 213 | //client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata 214 | //client-side. Aside from being very annoying, this also breaks various server-side behaviours. 215 | if($nbt === null){ 216 | $nbt = new CompoundTag(); 217 | } 218 | $nbt->setInt("___Meta___", $coreData); 219 | } 220 | 221 | $context = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary($protocol)); 222 | $packet->putString( 223 | (static function() use ($protocol, $nbt, $netId, $context) : string{ 224 | $extraData = PacketSerializer::encoder($context); 225 | 226 | if($nbt !== null){ 227 | $extraData->putLShort(0xffff); 228 | $extraData->putByte(1); //TODO: NBT data version (?) 229 | $extraData->put((new LittleEndianNbtSerializer())->write(new TreeRoot($nbt))); 230 | }else{ 231 | $extraData->putLShort(0); 232 | } 233 | 234 | $extraData->putLInt(0); //CanPlaceOn entry count (TODO) 235 | $extraData->putLInt(0); //CanDestroy entry count (TODO) 236 | 237 | if($netId === MultiVersionGlobalItemTypeDictionary::getInstance()->getDictionary($protocol)->fromStringId("minecraft:shield", $protocol)){ 238 | $extraData->putLLong(0); //"blocking tick" (ffs mojang) 239 | } 240 | return $extraData->getBuffer(); 241 | })()); 242 | } 243 | 244 | public static function putItem(PacketSerializer $packet, int $protocol, Item $item, int $stackId) { 245 | self::putItemStack($packet, $protocol, $item, function(BinaryStream $out) use ($stackId){ 246 | $out->putBool($stackId !== 0); 247 | if($stackId !== 0) { 248 | $out->putVarInt($stackId); 249 | } 250 | }); 251 | } 252 | 253 | public static function putRecipeIngredient(PacketSerializer $packet, Item $item, int $protocol) { 254 | if($item->isNull()){ 255 | $packet->putVarInt(0); 256 | }else{ 257 | if($item->hasAnyDamageValue()){ 258 | [$netId, ] = MultiVersionItemTranslator::getInstance()->toNetworkId($item->getId(), 0, $protocol); 259 | $netData = 0x7fff; 260 | }else{ 261 | [$netId, $netData] = MultiVersionItemTranslator::getInstance()->toNetworkId($item->getId(), $item->getMeta(), $protocol); 262 | } 263 | $packet->putVarInt($netId); 264 | $packet->putVarInt($netData); 265 | $packet->putVarInt($item->getCount()); 266 | } 267 | } 268 | 269 | public static function putItemStackWithoutStackId(PacketSerializer $packet, Item $item, int $protocol) : void{ 270 | self::putItemStack($packet, $protocol, $item, function() : void{}); 271 | } 272 | 273 | public static function getItemStack(DataPacket $packet, \Closure $readExtraCrapInTheMiddle, int $protocol) : Item{ 274 | $out = new BinaryStream(); 275 | $netId = $out->getVarInt(); 276 | if($netId === 0){ 277 | return ItemFactory::getInstance()->get(0, 0, 0); 278 | } 279 | 280 | $cnt = $out->getLShort(); 281 | $netData = $out->getUnsignedVarInt(); 282 | 283 | $null = null; 284 | [$id, $meta] = MultiVersionItemTranslator::getInstance()->fromNetworkId($netId, $netData, $null, $protocol); 285 | 286 | $readExtraCrapInTheMiddle($packet); 287 | 288 | $out->getVarInt(); 289 | 290 | $extraData = PacketSerializer::decoder($out->getString(), 0, new PacketSerializerContext(MultiVersionGlobalItemTypeDictionary::getInstance()->getDictionary($protocol))); 291 | return (static function() use ($protocol, $extraData, $netId, $id, $meta, $cnt) : Item{ 292 | $nbtLen = $extraData->getLShort(); 293 | 294 | /** @var CompoundTag|null $nbt */ 295 | $nbt = null; 296 | if($nbtLen === 0xffff){ 297 | $nbtDataVersion = $extraData->getByte(); 298 | if($nbtDataVersion !== 1){ 299 | throw new \UnexpectedValueException("Unexpected NBT data version $nbtDataVersion"); 300 | } 301 | $offset = $extraData->getOffset(); 302 | $decodedNBT = (new LittleEndianNbtSerializer())->read($extraData->getBuffer(), $offset, 512); 303 | $nbt = $decodedNBT; 304 | }elseif($nbtLen !== 0){ 305 | throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen"); 306 | } 307 | 308 | //TODO 309 | for($i = 0, $canPlaceOn = $extraData->getLInt(); $i < $canPlaceOn; ++$i){ 310 | $extraData->get($extraData->getLShort()); 311 | } 312 | 313 | //TODO 314 | for($i = 0, $canDestroy = $extraData->getLInt(); $i < $canDestroy; ++$i){ 315 | $extraData->get($extraData->getLShort()); 316 | } 317 | 318 | if($netId === MultiVersionGlobalItemTypeDictionary::getInstance()->getDictionary($protocol)->fromStringId("minecraft:shield", $protocol)){ 319 | $extraData->getLLong(); //"blocking tick" (ffs mojang) 320 | } 321 | 322 | if(!$extraData->feof()){ 323 | throw new \UnexpectedValueException("Unexpected trailing extradata for network item $netId"); 324 | } 325 | 326 | if($nbt !== null){ 327 | if($nbt->getTag("Meta") !== null){ 328 | $meta = $nbt->getInt("Damage"); 329 | $nbt->removeTag("Damage"); 330 | if(($conflicted = $nbt->getTag("___Meta_ProtocolCollisionResolution___")) !== null){ 331 | $nbt->removeTag("___Meta_ProtocolCollisionResolution___"); 332 | $nbt->setTag("Meta", $conflicted); 333 | }elseif($nbt->count() === 0){ 334 | $nbt = null; 335 | } 336 | }elseif(($metaTag = $nbt->getTag("___Meta___")) instanceof IntTag){ 337 | //TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the 338 | //client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata 339 | //client-side. Aside from being very annoying, this also breaks various server-side behaviours. 340 | $meta = $metaTag->getValue(); 341 | $nbt->removeTag("___Meta___"); 342 | if($nbt->count() === 0){ 343 | $nbt = null; 344 | } 345 | } 346 | } 347 | return ItemFactory::getInstance()->get($id, $meta, $cnt, $nbt); 348 | })(); 349 | } 350 | 351 | public static function getItemStackWrapper(DataPacket $packet, int $protocol): ItemStackWrapper{ 352 | $stackId = 0; 353 | $stack = self::getItemStack($packet, function(PacketSerializer $in) use (&$stackId) : void{ 354 | $hasNetId = $in->getBool(); 355 | if($hasNetId){ 356 | $stackId = $in->readGenericTypeNetworkId(); 357 | } 358 | }, $protocol); 359 | return new ItemStackWrapper($stackId, new ItemStack($stack->getId(), $stack->getMeta(), $stack->getCount(), MultiVersionRuntimeBlockMapping::toStaticRuntimeId($stack->getId(), $stack->getMeta()), $stack->getNamedTag(), $stack->getCanPlaceOn(), $stack->getCanDestroy())); 360 | } 361 | 362 | public static function putEntityLink(EntityLink $link) { 363 | $out = new BinaryStream(); 364 | $out->putActorUniqueId($link->fromActorUniqueId); 365 | $out->putActorUniqueId($link->toActorUniqueId); 366 | $out->putByte($link->type); 367 | $out->putBool($link->immediate); 368 | $out->putBool($link->causedByRider); 369 | } 370 | 371 | public static function putGameRules(array $rules, int $protocol){ 372 | $out = new BinaryStream(); 373 | $out->putUnsignedVarInt(count($rules)); 374 | foreach($rules as $name => $rule){ 375 | $out->putString($name); 376 | if($protocol >= ProtocolConstants::BEDROCK_1_17_0){ 377 | $out->putBool($rule[2]); 378 | } 379 | $out->putUnsignedVarInt($rule[0]); 380 | switch($rule[0]){ 381 | case GameRuleType::BOOL: 382 | $out->putBool($rule[1]); 383 | break; 384 | case GameRuleType::INT: 385 | $out->putUnsignedVarInt($rule[1]); 386 | break; 387 | case GameRuleType::FLOAT: 388 | $out->putLFloat($rule[1]); 389 | break; 390 | } 391 | } 392 | } 393 | 394 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/Translator.php: -------------------------------------------------------------------------------- 1 | bEnforceMapType = false; //TODO: we don't really need this as an array, but right now we don't have enough models 87 | $mapper->bExceptionOnMissingData = true; 88 | $mapper->bExceptionOnUndefinedProperty = true; 89 | try{ 90 | $clientData = $mapper->map($clientDataClaims, new ClientData); 91 | }catch(\JsonMapper_Exception $e){ 92 | throw PacketHandlingException::wrap($e); 93 | } 94 | return $clientData; 95 | } 96 | 97 | public static function fromClient(DataPacket $packet, int $protocol, NetworkSession $session = null) : DataPacket{ 98 | $pid = $packet::NETWORK_ID; 99 | switch($pid) { 100 | case LoginPacket::NETWORK_ID: 101 | /** @var LoginPacket $packet */ 102 | //todo use JwtUtils instead 103 | $clientData = self::parseClientData($packet->clientDataJwt); 104 | if($protocol < ProtocolConstants::BEDROCK_1_17_30) { 105 | $clientData->SkinGeometryDataEngineVersion = ""; 106 | } 107 | return $packet; 108 | case PlayerSkinPacket::NETWORK_ID: 109 | /** @var PlayerSkinPacket $packet */ 110 | if($protocol < ProtocolConstants::BEDROCK_1_17_30) { 111 | self::decodeHeader($packet); 112 | PlayerSkinPacketTranslator::deserialize($packet, $protocol); 113 | } 114 | return $packet; 115 | case InventoryTransactionPacket::NETWORK_ID: 116 | /** @var InventoryTransactionPacket $packet */ 117 | self::decodeHeader($packet); 118 | InventoryTransactionPacketTranslator::deserialize($packet, $protocol); 119 | return $packet; 120 | case LevelSoundEventPacket::NETWORK_ID: 121 | /** @var LevelSoundEventPacket $packet */ 122 | $stream = PacketSerializer::decoder(file_get_contents(\pocketmine\BEDROCK_DATA_PATH . "level_sound_id_map.json"), 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())); 123 | $packet->decode($stream); 124 | switch($packet->sound) { 125 | case LevelSoundEvent::PLACE: 126 | case LevelSoundEvent::BREAK_BLOCK: 127 | $block = MultiVersionRuntimeBlockMapping::fromStaticRuntimeId($packet->extraData, $protocol); 128 | $packet->extraData = RuntimeBlockMapping::getInstance()->toRuntimeId(BlockFactory::getInstance()->get($block[0], $block[1])->getFullId()); 129 | return $packet; 130 | } 131 | return $packet; 132 | case NpcRequestPacket::NETWORK_ID: 133 | /** @var NpcRequestPacket $packet */ 134 | self::decodeHeader($packet); 135 | NpcRequestPacketTranslator::deserialize($packet, $protocol); 136 | return $packet; 137 | case MobEquipmentPacket::NETWORK_ID: 138 | /** @var MobEquipmentPacket $packet */ 139 | self::decodeHeader($packet); 140 | MobEquipmentPacketTranslator::deserialize($packet, $protocol); 141 | return $packet; 142 | case MobArmorEquipmentPacket::NETWORK_ID: 143 | /** @var MobArmorEquipmentPacket $packet */ 144 | self::decodeHeader($packet); 145 | MobArmorEquipmentPacketTranslator::deserialize($packet, $protocol); 146 | return $packet; 147 | } 148 | return $packet; 149 | } 150 | 151 | public static function fromServer(Packet $packet, int $protocol, NetworkSession $session = null, bool &$translated = true) : ?DataPacket { 152 | switch($packet->pid()) { 153 | case ResourcePackStackPacket::NETWORK_ID: 154 | /** @var ResourcePackStackPacket $packet */ 155 | $packet->baseGameVersion = "1.16.220"; 156 | return $packet; 157 | case UpdateBlockPacket::NETWORK_ID: 158 | /** @var UpdateBlockPacket $packet */ 159 | $block = RuntimeBlockMapping::getInstance()->fromNetworkId($packet->blockRuntimeId); 160 | $packet->blockRuntimeId = MultiVersionRuntimeBlockMapping::toStaticRuntimeId($block[0], $block[1], $protocol); 161 | return $packet; 162 | case LevelSoundEventPacket::NETWORK_ID: 163 | /** @var LevelSoundEventPacket $packet */ 164 | switch($packet->sound) { 165 | case LevelSoundEvent::PLACE: 166 | case LevelSoundEvent::BREAK_BLOCK: 167 | $block = RuntimeBlockMapping::getInstance()->fromNetworkId($packet->extraData); 168 | $packet->extraData = MultiVersionRuntimeBlockMapping::toStaticRuntimeId($block[0], $block[1], $protocol); 169 | return $packet; 170 | } 171 | return $packet; 172 | case AddActorPacket::NETWORK_ID: 173 | /** @var AddActorPacket $packet */ 174 | switch($packet->type) { 175 | case "minecraft:falling_block": 176 | if(isset($packet->metadata[EntityMetadataProperties::VARIANT])){ 177 | $block = RuntimeBlockMapping::getInstance()->fromNetworkId($packet->metadata[EntityMetadataProperties::VARIANT][1]); 178 | $packet->metadata[EntityMetadataProperties::VARIANT] = [EntityMetadataTypes::INT, MultiVersionRuntimeBlockMapping::toStaticRuntimeId($block[0], $block[1], $protocol)]; 179 | } 180 | return $packet; 181 | } 182 | return $packet; 183 | case LevelEventPacket::NETWORK_ID: 184 | /** @var LevelEventPacket $packet */ 185 | switch($packet->evid) { 186 | case LevelEvent::PARTICLE_DESTROY: 187 | $block = RuntimeBlockMapping::getInstance()->fromNetworkId($packet->data); 188 | $packet->data = MultiVersionRuntimeBlockMapping::toStaticRuntimeId($block[0], $block[1], $protocol); 189 | return $packet; 190 | case LevelEvent::PARTICLE_PUNCH_BLOCK: 191 | $position = $packet->position; 192 | $block = $session->getPlayer()->getWorld()->getBlock($position); 193 | if($block->getId() === 0) { 194 | return null; 195 | } 196 | $face = $packet->data & ~RuntimeBlockMapping::getInstance()->get($block->getId(), $block->getMeta())->getFullId(); 197 | $packet->data = MultiVersionRuntimeBlockMapping::toStaticRuntimeId($block->getId(), $block->getMeta(), $protocol) | $face; 198 | return $packet; 199 | } 200 | return $packet; 201 | case LevelChunkPacket::NETWORK_ID: 202 | /** @var LevelChunkPacket $packet */ 203 | if($protocol <= ProtocolConstants::BEDROCK_1_17_40) { 204 | if($session->getPlayer()->getWorld() !== null){ 205 | return Chunk112::serialize($session->getPlayer()->getWorld(), $packet); 206 | } 207 | return null; 208 | } 209 | return $packet; 210 | case AnimateEntityPacket::NETWORK_ID: 211 | /** @var AnimateEntityPacket $packet */ 212 | self::encodeHeader($packet); 213 | AnimateEntityPacketTranslator::serialize($packet, $protocol); 214 | return $packet; 215 | case CraftingDataPacket::NETWORK_ID: 216 | /** @var CraftingDataPacket $packet */ 217 | self::encodeHeader($packet); 218 | CraftingDataPacketTranslator::serialize($packet, $protocol); 219 | return $packet; 220 | case PlayerListPacket::NETWORK_ID: 221 | /** @var PlayerListPacket $packet */ 222 | self::encodeHeader($packet); 223 | PlayerListPacketTranslator::serialize($packet, $protocol); 224 | return $packet; 225 | case StartGamePacket::NETWORK_ID: 226 | /** @var StartGamePacket $packet */ 227 | $packet->itemTable = MultiVersionGlobalItemTypeDictionary::getInstance()->getDictionary($protocol)->getEntries($protocol); 228 | self::encodeHeader($packet); 229 | StartGamePacketTranslator::serialize($packet, $protocol); 230 | return $packet; 231 | case PlayerSkinPacket::NETWORK_ID: 232 | /** @var PlayerSkinPacket $packet */ 233 | self::encodeHeader($packet); 234 | PlayerSkinPacketTranslator::serialize($packet, $protocol); 235 | return $packet; 236 | case AddItemActorPacket::NETWORK_ID: 237 | /** @var AddItemActorPacket $packet */ 238 | self::encodeHeader($packet); 239 | AddItemActorPacketTranslator::serialize($packet, $protocol); 240 | return $packet; 241 | case InventoryContentPacket::NETWORK_ID: 242 | /** @var InventoryContentPacket $packet */ 243 | self::encodeHeader($packet); 244 | InventoryContentPacketTranslator::serialize($packet, $protocol); 245 | return $packet; 246 | case MobEquipmentPacket::NETWORK_ID: 247 | /** @var MobEquipmentPacket $packet */ 248 | self::encodeHeader($packet); 249 | MobEquipmentPacketTranslator::serialize($packet, $protocol); 250 | return $packet; 251 | case MobArmorEquipmentPacket::NETWORK_ID: 252 | /** @var MobArmorEquipmentPacket $packet */ 253 | self::encodeHeader($packet); 254 | MobArmorEquipmentPacketTranslator::serialize($packet, $protocol); 255 | return $packet; 256 | case AddPlayerPacket::NETWORK_ID: 257 | /** @var AddPlayerPacket $packet */ 258 | self::encodeHeader($packet); 259 | AddPlayerPacketTranslator::serialize($packet, $protocol); 260 | return $packet; 261 | case InventorySlotPacket::NETWORK_ID: 262 | /** @var InventorySlotPacket $packet */ 263 | self::encodeHeader($packet); 264 | InventorySlotPacketTranslator::serialize($packet, $protocol); 265 | return $packet; 266 | case InventoryTransactionPacket::NETWORK_ID: 267 | /** @var InventoryTransactionPacket $packet */ 268 | self::encodeHeader($packet); 269 | InventoryTransactionPacketTranslator::serialize($packet, $protocol); 270 | return $packet; 271 | case CreativeContentPacket::NETWORK_ID: 272 | /** @var CreativeContentPacket $packet */ 273 | self::encodeHeader($packet); 274 | CreativeContentPacketTranslator::serialize($packet, $protocol); 275 | return $packet; 276 | case AvailableCommandsPacket::NETWORK_ID: 277 | /** @var AvailableCommandsPacket $packet */ 278 | self::encodeHeader($packet); 279 | AvailableCommandsPacketTranslator::serialize($packet, $protocol); 280 | return $packet; 281 | case SetTitlePacket::NETWORK_ID: 282 | /** @var SetTitlePacket $packet */ 283 | self::encodeHeader($packet); 284 | SetTitlePacketTranslator::serialize($packet, $protocol); 285 | return $packet; 286 | case ResourcePacksInfoPacket::NETWORK_ID: 287 | /** @var ResourcePacksInfoPacket $packet */ 288 | self::encodeHeader($packet); 289 | ResourcePacksInfoPacketTranslator::serialize($packet, $protocol); 290 | return $packet; 291 | case GameRulesChangedPacket::NETWORK_ID: 292 | /** @var GameRulesChangedPacket $packet */ 293 | self::encodeHeader($packet); 294 | GameRulesChangedPacketTranslator::serialize($packet, $protocol); 295 | return $packet; 296 | } 297 | $translated = false; 298 | return $packet; 299 | } 300 | 301 | public static function encodeHeader(DataPacket $packet) { 302 | $in = new BinaryStream(); 303 | $in->rewind(); 304 | $in->putUnsignedVarInt( 305 | $packet::NETWORK_ID | 306 | ($packet->senderSubId << 10) | 307 | ($packet->recipientSubId << 12) 308 | ); 309 | } 310 | 311 | public static function decodeHeader(DataPacket $packet) { 312 | $out = new BinaryStream(); 313 | $packet->offset = 0; 314 | $header = $out->getUnsignedVarInt(); 315 | $pid = $header & $packet::PID_MASK; 316 | if($pid !== $packet::NETWORK_ID){ 317 | throw new \UnexpectedValueException("Expected " . $packet::NETWORK_ID . " for packet ID, got $pid"); 318 | } 319 | $packet->senderSubId = ($header >> 10) & 0x03; 320 | $packet->recipientSubId = ($header >> 12) & 0x03; 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/convert/MultiVersionCraftingManager.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | private $caches = []; 39 | 40 | const PROTOCOL = [ 41 | ProtocolConstants::BEDROCK_1_18_0, 42 | ProtocolConstants::BEDROCK_1_17_40, 43 | ProtocolConstants::BEDROCK_1_17_30, 44 | ProtocolConstants::BEDROCK_1_17_10, 45 | ProtocolConstants::BEDROCK_1_17_0, 46 | ProtocolConstants::BEDROCK_1_16_220 47 | ]; 48 | 49 | public function getCache(CraftingManager $manager, int $protocol) : CraftingDataPacket{ 50 | $id = spl_object_id($manager); 51 | if(!isset($this->caches[$protocol][$id])){ 52 | $manager->getDestructorCallbacks()->add(function() use ($id, $protocol) : void{ 53 | unset($this->caches[$protocol][$id]); 54 | }); 55 | $manager->getRecipeRegisteredCallbacks()->add(function() use ($id, $protocol) : void{ 56 | unset($this->caches[$protocol][$id]); 57 | }); 58 | $this->caches[$protocol][$id] = $this->buildCraftingDataCache($manager); 59 | } 60 | return $this->caches[$protocol][$id]; 61 | } 62 | 63 | /** 64 | * Rebuilds the cached CraftingDataPacket. 65 | */ 66 | private function buildCraftingDataCache(CraftingManager $manager) : CraftingDataPacket{ 67 | Timings::$craftingDataCacheRebuild->startTiming(); 68 | 69 | $counter = 0; 70 | $nullUUID = Uuid::fromString(Uuid::NIL); 71 | $converter = TypeConverter::getInstance(); 72 | $recipesWithTypeIds = []; 73 | foreach($manager->getShapelessRecipes() as $list){ 74 | foreach($list as $recipe){ 75 | $recipesWithTypeIds[] = new ProtocolShapelessRecipe( 76 | CraftingDataPacket::ENTRY_SHAPELESS, 77 | Binary::writeInt(++$counter), 78 | array_map(function(Item $item) use ($converter) : RecipeIngredient{ 79 | return $converter->coreItemStackToRecipeIngredient($item); 80 | }, $recipe->getIngredientList()), 81 | array_map(function(Item $item) use ($converter) : ItemStack{ 82 | return $converter->coreItemStackToNet($item); 83 | }, $recipe->getResults()), 84 | $nullUUID, 85 | CraftingRecipeBlockName::CRAFTING_TABLE, 86 | 50, 87 | $counter 88 | ); 89 | } 90 | } 91 | foreach($manager->getShapedRecipes() as $list){ 92 | foreach($list as $recipe){ 93 | $inputs = []; 94 | 95 | for($row = 0, $height = $recipe->getHeight(); $row < $height; ++$row){ 96 | for($column = 0, $width = $recipe->getWidth(); $column < $width; ++$column){ 97 | $inputs[$row][$column] = $converter->coreItemStackToRecipeIngredient($recipe->getIngredient($column, $row)); 98 | } 99 | } 100 | $recipesWithTypeIds[] = $r = new ProtocolShapedRecipe( 101 | CraftingDataPacket::ENTRY_SHAPED, 102 | Binary::writeInt(++$counter), 103 | $inputs, 104 | array_map(function(Item $item) use ($converter) : ItemStack{ 105 | return $converter->coreItemStackToNet($item); 106 | }, $recipe->getResults()), 107 | $nullUUID, 108 | CraftingRecipeBlockName::CRAFTING_TABLE, 109 | 50, 110 | $counter 111 | ); 112 | } 113 | } 114 | 115 | foreach(FurnaceType::getAll() as $furnaceType){ 116 | $typeTag = match($furnaceType->id()){ 117 | FurnaceType::FURNACE()->id() => FurnaceRecipeBlockName::FURNACE, 118 | FurnaceType::BLAST_FURNACE()->id() => FurnaceRecipeBlockName::BLAST_FURNACE, 119 | FurnaceType::SMOKER()->id() => FurnaceRecipeBlockName::SMOKER, 120 | default => throw new AssumptionFailedError("Unreachable"), 121 | }; 122 | foreach($manager->getFurnaceRecipeManager($furnaceType)->getAll() as $recipe){ 123 | $input = $converter->coreItemStackToNet($recipe->getInput()); 124 | $recipesWithTypeIds[] = new ProtocolFurnaceRecipe( 125 | CraftingDataPacket::ENTRY_FURNACE_DATA, 126 | $input->getId(), 127 | $input->getMeta(), 128 | $converter->coreItemStackToNet($recipe->getResult()), 129 | $typeTag 130 | ); 131 | } 132 | } 133 | 134 | $potionTypeRecipes = []; 135 | foreach($manager->getPotionTypeRecipes() as $recipes){ 136 | foreach($recipes as $recipe){ 137 | $input = $converter->coreItemStackToNet($recipe->getInput()); 138 | $ingredient = $converter->coreItemStackToNet($recipe->getIngredient()); 139 | $output = $converter->coreItemStackToNet($recipe->getOutput()); 140 | $potionTypeRecipes[] = new ProtocolPotionTypeRecipe( 141 | $input->getId(), 142 | $input->getMeta(), 143 | $ingredient->getId(), 144 | $ingredient->getMeta(), 145 | $output->getId(), 146 | $output->getMeta() 147 | ); 148 | } 149 | } 150 | 151 | $potionContainerChangeRecipes = []; 152 | $itemTranslator = MultiVersionItemTranslator::getInstance(); 153 | foreach (self::PROTOCOL as $protocol => $file){ 154 | if(Loader::getInstance()->isProtocolDisabled($protocol)) { 155 | continue; 156 | } 157 | foreach($manager->getPotionContainerChangeRecipes() as $recipes){ 158 | foreach($recipes as $recipe){ 159 | $input = $itemTranslator->toNetworkId($recipe->getInputItemId(), 0, $protocol); 160 | $ingredient = $itemTranslator->toNetworkId($recipe->getIngredient()->getId(), 0, $protocol); 161 | $output = $itemTranslator->toNetworkId($recipe->getOutputItemId(), 0, $protocol); 162 | $potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe( 163 | $input[0], 164 | $ingredient[0], 165 | $output[0] 166 | ); 167 | } 168 | } 169 | } 170 | 171 | Timings::$craftingDataCacheRebuild->stopTiming(); 172 | return CraftingDataPacket::create($recipesWithTypeIds, $potionTypeRecipes, $potionContainerChangeRecipes, [], true); 173 | } 174 | 175 | public function getCraftingDataPacketA(int $protocol): BatchPacket{ 176 | return $this->multiVersionCraftingDataCache[$protocol]; 177 | } 178 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/convert/MultiVersionGlobalItemTypeDictionary.php: -------------------------------------------------------------------------------- 1 | "_1_16_220", 26 | ProtocolConstants::BEDROCK_1_17_0 => "_1_17_0", 27 | ProtocolConstants::BEDROCK_1_17_10 => "_1_17_10", 28 | ProtocolConstants::BEDROCK_1_17_30 => "_1_17_30", 29 | ProtocolConstants::BEDROCK_1_17_40 => "_1_17_40", 30 | ProtocolConstants::BEDROCK_1_18_0 => "_1_18_0", 31 | ]; 32 | 33 | private static function make() : self{ 34 | $dictionary = []; 35 | $p = -1; 36 | foreach(self::PROTOCOL as $protocol => $file){ 37 | if(Loader::getInstance()->isProtocolDisabled($protocol)) { 38 | continue; 39 | } 40 | $data = Utils::assumeNotFalse(file_get_contents(Path::join(Loader::$resourcesPath, "vanilla/required_item_list$file.json")), "Missing required resource file"); 41 | $table = json_decode($data, true); 42 | if(!is_array($table)){ 43 | throw new AssumptionFailedError("Invalid item list format"); 44 | } 45 | 46 | $params = []; 47 | foreach($table as $name => $entry){ 48 | if(!is_array($entry) || !is_string($name) || !isset($entry["component_based"], $entry["runtime_id"]) || !is_bool($entry["component_based"]) || !is_int($entry["runtime_id"])){ 49 | throw new AssumptionFailedError("Invalid item list format"); 50 | } 51 | $params[] = new ItemTypeEntry($name, $entry["runtime_id"], $entry["component_based"]); 52 | } 53 | $dictionary[$protocol] = $params; 54 | $p = $protocol; 55 | } 56 | self::$dictionary[$p] = new MultiVersionItemTypeDictionary($dictionary, $p); 57 | return new self; 58 | } 59 | 60 | public function getDictionary(int $protocol = ProtocolInfo::CURRENT_PROTOCOL) : MultiVersionItemTypeDictionary{ return self::$dictionary[$protocol]; } 61 | 62 | /** 63 | * @return MultiVersionItemTypeDictionary[] 64 | */ 65 | public function getAllDictionaries(): MultiVersionItemTypeDictionary{ return self::$dictionary; } 66 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/convert/MultiVersionItemTranslator.php: -------------------------------------------------------------------------------- 1 | $simpleMappings */ 58 | $simpleMappings = []; 59 | foreach($json["simple"] as $oldId => $newId){ 60 | if(!is_string($oldId) || !is_string($newId)){ 61 | throw new AssumptionFailedError("Invalid item table format"); 62 | } 63 | if(!isset($legacyStringToIntMap[$oldId])){ 64 | //new item without a fixed legacy ID - we can't handle this right now 65 | continue; 66 | } 67 | $simpleMappings[$newId] = $legacyStringToIntMap[$oldId]; 68 | } 69 | foreach($legacyStringToIntMap as $stringId => $intId){ 70 | if(isset($simpleMappings[$stringId])){ 71 | throw new \UnexpectedValueException("Old ID $stringId collides with new ID"); 72 | } 73 | $simpleMappings[$stringId] = $intId; 74 | } 75 | 76 | /** @phpstan-var array $complexMappings */ 77 | $complexMappings = []; 78 | foreach($json["complex"] as $oldId => $map){ 79 | if(!is_string($oldId) || !is_array($map)){ 80 | throw new AssumptionFailedError("Invalid item table format"); 81 | } 82 | foreach($map as $meta => $newId){ 83 | if(!is_numeric($meta) || !is_string($newId)){ 84 | throw new AssumptionFailedError("Invalid item table format"); 85 | } 86 | $complexMappings[$newId] = [$legacyStringToIntMap[$oldId], (int) $meta]; 87 | } 88 | } 89 | 90 | $p = null; 91 | foreach (MultiVersionGlobalItemTypeDictionary::PROTOCOL as $protocol => $file){ 92 | $p = $protocol; 93 | } 94 | 95 | return new self(MultiVersionGlobalItemTypeDictionary::getInstance()->getDictionary($p), $simpleMappings, $complexMappings); 96 | } 97 | 98 | /** 99 | * @param MultiVersionItemTypeDictionary $dictionary 100 | * @param int[] $simpleMappings 101 | * @param int[][] $complexMappings 102 | * @phpstan-param array $simpleMappings 103 | * @phpstan-param array> $complexMappings 104 | */ 105 | public function __construct(MultiVersionItemTypeDictionary $dictionary, array $simpleMappings, array $complexMappings){ 106 | foreach($dictionary->getAllEntries() as $protocol => $entries){ 107 | if(Loader::getInstance()->isProtocolDisabled($protocol)) { 108 | continue; 109 | } 110 | foreach($entries as $entry){ 111 | $stringId = $entry->getStringId(); 112 | $netId = $entry->getNumericId(); 113 | if(isset($complexMappings[$stringId])){ 114 | [$id, $meta] = $complexMappings[$stringId]; 115 | $this->complexCoreToNetMapping[$protocol][$id][$meta] = $netId; 116 | $this->complexNetToCoreMapping[$protocol][$netId] = [$id, $meta]; 117 | }elseif(isset($simpleMappings[$stringId])){ 118 | $this->simpleCoreToNetMapping[$protocol][$simpleMappings[$stringId]] = $netId; 119 | $this->simpleNetToCoreMapping[$protocol][$netId] = $simpleMappings[$stringId]; 120 | }else{ 121 | //not all items have a legacy mapping - for now, we only support the ones that do 122 | continue; 123 | } 124 | } 125 | } 126 | } 127 | 128 | /** 129 | * @return int[] 130 | * @phpstan-return array{int, int} 131 | */ 132 | public function toNetworkId(int $internalId, int $internalMeta, int $protocol) : array{ 133 | if($internalMeta === -1){ 134 | $internalMeta = 0x7fff; 135 | } 136 | if(isset($this->complexCoreToNetMapping[$protocol][$internalId][$internalMeta])){ 137 | return [$this->complexCoreToNetMapping[$protocol][$internalId][$internalMeta], 0]; 138 | } 139 | if(array_key_exists($internalId, $this->simpleCoreToNetMapping[$protocol])){ 140 | return [$this->simpleCoreToNetMapping[$protocol][$internalId], $internalMeta]; 141 | } 142 | 143 | return ItemTranslator::getInstance()->toNetworkId($internalId, $internalMeta); // custom item check 144 | } 145 | 146 | /** 147 | * @return int[] 148 | * @phpstan-return array{int, int} 149 | */ 150 | public function fromNetworkId(int $networkId, int $networkMeta, ?bool &$isComplexMapping = null, int $protocol) : array{ 151 | if(isset($this->complexNetToCoreMapping[$protocol][$networkId])){ 152 | if($networkMeta !== 0){ 153 | throw new \UnexpectedValueException("Unexpected non-zero network meta on complex item mapping"); 154 | } 155 | $isComplexMapping = true; 156 | return $this->complexNetToCoreMapping[$protocol][$networkId]; 157 | } 158 | $isComplexMapping = false; 159 | if(isset($this->simpleNetToCoreMapping[$protocol][$networkId])){ 160 | return [$this->simpleNetToCoreMapping[$protocol][$networkId], $networkMeta]; 161 | } 162 | return ItemTranslator::getInstance()->fromNetworkId($networkId, $networkMeta, $isComplexMapping); // custom item check 163 | } 164 | 165 | /** 166 | * @return int[] 167 | * @phpstan-return array{int, int} 168 | */ 169 | public function fromNetworkIdWithWildcardHandling(int $networkId, int $networkMeta, int $protocol) : array{ 170 | $isComplexMapping = false; 171 | if($networkMeta !== 0x7fff){ 172 | $null = null; 173 | return $this->fromNetworkId($networkId, $networkMeta, $null, $protocol); 174 | } 175 | [$id, $meta] = $this->fromNetworkId($networkId, 0, $isComplexMapping, $protocol); 176 | return [$id, $isComplexMapping ? $meta : -1]; 177 | } 178 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/convert/MultiVersionItemTypeDictionary.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | private array $itemTypes; 17 | /** 18 | * @var string[][] 19 | * @phpstan-var array 20 | */ 21 | private array $intToStringIdMap = []; 22 | /** 23 | * @var int[][] 24 | * @phpstan-var array 25 | */ 26 | private array $stringToIntMap = []; 27 | 28 | /** 29 | * @param ItemTypeEntry[] $itemTypes 30 | */ 31 | public function __construct(array $itemTypes, int $protocol){ 32 | $this->itemTypes[$protocol] = $itemTypes; 33 | foreach($this->itemTypes[$protocol] as $type){ 34 | foreach ($type as $types){ 35 | $this->stringToIntMap[$protocol][$types->getStringId()] = $types->getNumericId(); 36 | $this->intToStringIdMap[$protocol][$types->getNumericId()] = $types->getStringId(); 37 | } 38 | } 39 | } 40 | 41 | /** 42 | * @return ItemTypeEntry[] 43 | * @phpstan-return list 44 | */ 45 | public function getEntries(int $protocol) : array{ 46 | return $this->itemTypes[$protocol]; 47 | } 48 | 49 | public function getAllEntries(): array{ 50 | return $this->itemTypes; 51 | } 52 | 53 | public function fromStringId(string $stringId, int $protocol) : int{ 54 | if(!array_key_exists($stringId, $this->stringToIntMap[$protocol])){ 55 | throw new \InvalidArgumentException("Unmapped string ID \"$stringId\""); 56 | } 57 | return $this->stringToIntMap[$protocol][$stringId]; 58 | } 59 | 60 | public function fromIntId(int $intId, int $protocol) : string{ 61 | if(!array_key_exists($intId, $this->intToStringIdMap[$protocol])){ 62 | throw new \InvalidArgumentException("Unmapped int ID $intId"); 63 | } 64 | return $this->intToStringIdMap[$protocol][$intId]; 65 | } 66 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/convert/MultiVersionLegacyBlockIdMap.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | private $legacyToString = []; 22 | /** 23 | * @var int[] 24 | * @phpstan-var array 25 | */ 26 | private $stringToLegacy = []; 27 | 28 | public function __construct(string $file){ 29 | $stringToLegacyId = json_decode(Utils::assumeNotFalse(file_get_contents($file), "Missing required resource file"), true); 30 | if(!is_array($stringToLegacyId)){ 31 | throw new AssumptionFailedError("Invalid format of ID map"); 32 | } 33 | foreach($stringToLegacyId as $stringId => $legacyId){ 34 | if(!is_string($stringId) || !is_int($legacyId)){ 35 | throw new AssumptionFailedError("ID map should have string keys and int values"); 36 | } 37 | $this->legacyToString[$legacyId] = $stringId; 38 | $this->stringToLegacy[$stringId] = $legacyId; 39 | } 40 | } 41 | 42 | public function legacyToString(int $legacy) : ?string{ 43 | return $this->legacyToString[$legacy] ?? null; 44 | } 45 | 46 | public function stringToLegacy(string $string) : ?int{ 47 | return $this->stringToLegacy[$string] ?? null; 48 | } 49 | 50 | /** 51 | * @return string[] 52 | * @phpstan-return array 53 | */ 54 | public function getLegacyToStringMap() : array{ 55 | return $this->legacyToString; 56 | } 57 | 58 | /** 59 | * @return int[] 60 | * @phpstan-return array 61 | */ 62 | public function getStringToLegacyMap() : array{ 63 | return $this->stringToLegacy; 64 | } 65 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/convert/MultiVersionRuntimeBlockMapping.php: -------------------------------------------------------------------------------- 1 | "_1_16_220", 32 | ProtocolConstants::BEDROCK_1_17_0 => "_1_17_0", 33 | ProtocolConstants::BEDROCK_1_17_10 => "_1_17_10", 34 | ProtocolConstants::BEDROCK_1_17_30 => "_1_17_30", 35 | ProtocolConstants::BEDROCK_1_17_40 => "_1_17_40" 36 | ]; 37 | 38 | private function __construct(){ 39 | //NOOP 40 | } 41 | 42 | public static function init() : void{ 43 | foreach(self::PROTOCOL as $protocol => $fileName){ 44 | if(Loader::getInstance()->isProtocolDisabled($protocol)) { 45 | continue; 46 | } 47 | $stream = PacketSerializer::decoder( 48 | Utils::assumeNotFalse(file_get_contents(Path::join(Loader::$resourcesPath, "vanilla/canonical_block_states".$fileName.".nbt")), "Missing required resource file"), 49 | 0, 50 | new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()) 51 | ); 52 | $list = []; 53 | while(!$stream->feof()){ 54 | $list[] = $stream->getNbtCompoundRoot(); 55 | } 56 | self::$bedrockKnownStates[$protocol] = $list; 57 | 58 | self::setupLegacyMappings($protocol); 59 | } 60 | } 61 | 62 | private static function setupLegacyMappings(int $protocol) : void{ 63 | $legacyIdMap = new MultiVersionLegacyBlockIdMap(Loader::$resourcesPath . "vanilla/block_id_map.json"); 64 | 65 | /** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */ 66 | $legacyStateMap = []; 67 | $suffix = match ($protocol) { 68 | ProtocolConstants::BEDROCK_1_17_0, ProtocolConstants::BEDROCK_1_17_10 => self::PROTOCOL[ProtocolConstants::BEDROCK_1_17_10], 69 | ProtocolConstants::BEDROCK_1_17_40, ProtocolConstants::BEDROCK_1_17_30 => self::PROTOCOL[ProtocolConstants::BEDROCK_1_17_30], 70 | default => self::PROTOCOL[$protocol], 71 | }; 72 | $path = Loader::$resourcesPath . "vanilla/r12_to_current_block_map".$suffix.".bin"; 73 | $legacyStateMapReader = PacketSerializer::decoder( 74 | Utils::assumeNotFalse(file_get_contents($path), "Missing required resource file"), 75 | 0, 76 | new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()) 77 | ); 78 | $nbtReader = new NetworkNbtSerializer(); 79 | while(!$legacyStateMapReader->feof()){ 80 | $id = $legacyStateMapReader->getString(); 81 | $meta = $legacyStateMapReader->getLShort(); 82 | 83 | $offset = $legacyStateMapReader->getOffset(); 84 | $state = $nbtReader->read($legacyStateMapReader->getBuffer(), $offset)->mustGetCompoundTag(); 85 | $legacyStateMapReader->setOffset($offset); 86 | $legacyStateMap[] = new R12ToCurrentBlockMapEntry($id, $meta, $state); 87 | } 88 | 89 | /** 90 | * @var int[][] $idToStatesMap string id -> int[] list of candidate state indices 91 | */ 92 | $idToStatesMap = []; 93 | foreach(self::$bedrockKnownStates[$protocol] as $k => $state){ 94 | $idToStatesMap[$state->getString("name")][] = $k; 95 | } 96 | foreach($legacyStateMap as $pair){ 97 | $id = $legacyIdMap->stringToLegacy($pair->getId()); 98 | if($id === null){ 99 | throw new \RuntimeException("No legacy ID matches " . $pair->getId()); 100 | } 101 | $data = $pair->getMeta(); 102 | if($data > 15){ 103 | //we can't handle metadata with more than 4 bits 104 | continue; 105 | } 106 | $mappedState = $pair->getBlockState(); 107 | $mappedName = $mappedState->getString("name"); 108 | if(!isset($idToStatesMap[$mappedName])){ 109 | throw new \RuntimeException("Mapped new state does not appear in network table"); 110 | } 111 | foreach($idToStatesMap[$mappedName] as $k){ 112 | $networkState = self::$bedrockKnownStates[$protocol][$k]; 113 | if($mappedState->equals($networkState)){ 114 | self::registerMapping($k, $id, $data, $protocol); 115 | continue 2; 116 | } 117 | } 118 | throw new \RuntimeException("Mapped new state does not appear in network table"); 119 | } 120 | } 121 | 122 | private static function lazyInit() : void{ 123 | if(self::$bedrockKnownStates === null){ 124 | self::init(); 125 | } 126 | } 127 | 128 | public static function toStaticRuntimeId(int $id, int $meta = 0, int $protocol = ProtocolInfo::CURRENT_PROTOCOL) : int{ 129 | if($protocol === ProtocolConstants::BEDROCK_1_18_0) { 130 | $protocol = ProtocolConstants::BEDROCK_1_17_40; 131 | } 132 | self::lazyInit(); 133 | /* 134 | * try id+meta first 135 | * if not found, try id+0 (strip meta) 136 | * if still not found, return update! block 137 | */ 138 | return self::$legacyToRuntimeMap[$protocol][($id << 4) | $meta] ?? self::$legacyToRuntimeMap[$protocol][$id << 4] ?? self::$legacyToRuntimeMap[$protocol][BlockLegacyIds::INFO_UPDATE << 4]; 139 | } 140 | 141 | /** 142 | * @return int[] [id, meta] 143 | */ 144 | public static function fromStaticRuntimeId(int $runtimeId, int $protocol) : array{ 145 | if($protocol === ProtocolConstants::BEDROCK_1_18_0) { 146 | $protocol = ProtocolConstants::BEDROCK_1_17_40; 147 | } 148 | self::lazyInit(); 149 | $v = self::$runtimeToLegacyMap[$protocol][$runtimeId] ?? null; 150 | if($v === null) { 151 | return [0, 0]; 152 | } 153 | return [$v >> 4, $v & 0xf]; 154 | } 155 | 156 | private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta, $protocol) : void{ 157 | self::$legacyToRuntimeMap[$protocol][($legacyId << 4) | $legacyMeta] = $staticRuntimeId; 158 | self::$runtimeToLegacyMap[$protocol][$staticRuntimeId] = ($legacyId << 4) | $legacyMeta; 159 | } 160 | 161 | /** 162 | * @return CompoundTag[] 163 | */ 164 | public static function getBedrockKnownStates() : array{ 165 | self::lazyInit(); 166 | return self::$bedrockKnownStates; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/AddItemActorPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putEntityUniqueId($packet->entityUniqueId ?? $packet->entityRuntimeId); 14 | $packet->putEntityRuntimeId($packet->entityRuntimeId); 15 | Serializer::putItem($packet, $protocol, $packet->item->getItemStack(), $packet->item->getStackId()); 16 | $packet->putVector3($packet->position); 17 | $packet->putVector3Nullable($packet->motion); 18 | $packet->putEntityMetadata($packet->metadata); 19 | ($packet->buffer .= ($packet->isFromFishing ? "\x01" : "\x00")); 20 | } 21 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/AddPlayerPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putUUID($packet->uuid); 15 | $packet->putString($packet->username); 16 | $packet->putEntityUniqueId($packet->entityUniqueId ?? $packet->entityRuntimeId); 17 | $packet->putEntityRuntimeId($packet->entityRuntimeId); 18 | $packet->putString($packet->platformChatId); 19 | $packet->putVector3($packet->position); 20 | $packet->putVector3Nullable($packet->motion); 21 | ($packet->buffer .= (\pack("g", $packet->pitch))); 22 | ($packet->buffer .= (\pack("g", $packet->yaw))); 23 | ($packet->buffer .= (\pack("g", $packet->headYaw ?? $packet->yaw))); 24 | Serializer::putItem($packet, $protocol, $packet->item->getItemStack(), $packet->item->getStackId()); 25 | $packet->putEntityMetadata($packet->metadata); 26 | 27 | $packet->putUnsignedVarInt($packet->uvarint1); 28 | $packet->putUnsignedVarInt($packet->uvarint2); 29 | $packet->putUnsignedVarInt($packet->uvarint3); 30 | $packet->putUnsignedVarInt($packet->uvarint4); 31 | $packet->putUnsignedVarInt($packet->uvarint5); 32 | 33 | ($packet->buffer .= (\pack("VV", $packet->long1 & 0xFFFFFFFF, $packet->long1 >> 32))); 34 | 35 | $packet->putUnsignedVarInt(count($packet->links)); 36 | foreach($packet->links as $link){ 37 | Serializer::putEntityLink($packet, $link); 38 | } 39 | 40 | $packet->putString($packet->deviceId); 41 | ($packet->buffer .= (\pack("V", $packet->buildPlatform))); 42 | } 43 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/AnimateEntityPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putString($packet->getAnimation()); 14 | $packet->putString($packet->getNextState()); 15 | $packet->putString($packet->getStopExpression()); 16 | if($protocol >= ProtocolConstants::BEDROCK_1_17_30){ 17 | $packet->putLInt($packet->getStopExpressionVersion()); 18 | } 19 | $packet->putString($packet->getController()); 20 | $packet->putLFloat($packet->getBlendOutTime()); 21 | $packet->putUnsignedVarInt(count($packet->getActorRuntimeIds())); 22 | foreach($packet->getActorRuntimeIds() as $id){ 23 | $packet->putEntityRuntimeId($id); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/AvailableCommandsPacketTranslator.php: -------------------------------------------------------------------------------- 1 | enumName])){ 28 | $enums[$enumIndexes[$enum->enumName] = count($enumIndexes)] = $enum; 29 | } 30 | foreach($enum->enumValues as $str){ 31 | $enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes); 32 | } 33 | }; 34 | foreach($packet->hardcodedEnums as $enum){ 35 | $addEnumFn($enum); 36 | } 37 | foreach($packet->commandData as $commandData){ 38 | if($commandData->aliases !== null){ 39 | $addEnumFn($commandData->aliases); 40 | } 41 | /** @var CommandParameter[] $overload */ 42 | foreach($commandData->overloads as $overload){ 43 | /** @var CommandParameter $parameter */ 44 | foreach($overload as $parameter){ 45 | if($parameter->enum !== null){ 46 | $addEnumFn($parameter->enum); 47 | } 48 | 49 | if($parameter->postfix !== null){ 50 | $postfixIndexes[$parameter->postfix] = $postfixIndexes[$parameter->postfix] ?? count($postfixIndexes); 51 | } 52 | } 53 | } 54 | } 55 | 56 | $packet->putUnsignedVarInt(count($enumValueIndexes)); 57 | foreach($enumValueIndexes as $enumValue => $index){ 58 | $packet->putString((string) $enumValue); //stupid PHP key casting D: 59 | } 60 | 61 | $packet->putUnsignedVarInt(count($postfixIndexes)); 62 | foreach($postfixIndexes as $postfix => $index){ 63 | $packet->putString((string) $postfix); //stupid PHP key casting D: 64 | } 65 | 66 | $packet->putUnsignedVarInt(count($enums)); 67 | foreach($enums as $enum){ 68 | Utils::forceCallMethod($packet, "putEnum", $enum, $enumValueIndexes); 69 | } 70 | 71 | $packet->putUnsignedVarInt(count($packet->commandData)); 72 | foreach($packet->commandData as $data){ 73 | self::putCommandData($packet, $data, $enumIndexes, $postfixIndexes, $protocol); 74 | } 75 | 76 | $packet->putUnsignedVarInt(count($packet->softEnums)); 77 | foreach($packet->softEnums as $enum){ 78 | Utils::forceCallMethod($packet, "putSoftEnum", $enum); 79 | } 80 | 81 | $packet->putUnsignedVarInt(count($packet->enumConstraints)); 82 | foreach($packet->enumConstraints as $constraint){ 83 | Utils::forceCallMethod($packet, "putEnumConstraint", $constraint, $enumIndexes, $enumValueIndexes); 84 | } 85 | } 86 | 87 | private static function putCommandData(AvailableCommandsPacket $packet, CommandData $data, array $enumIndexes, array $postfixIndexes, int $protocol){ 88 | $packet->putString($data->commandName); 89 | $packet->putString($data->commandDescription); 90 | if($protocol >= ProtocolConstants::BEDROCK_1_17_10){ 91 | $packet->putLShort($data->flags); 92 | } else { 93 | $packet->putByte($data->flags); 94 | } 95 | $packet->putByte($data->permission); 96 | 97 | if($data->aliases !== null){ 98 | $packet->putLInt($enumIndexes[$data->aliases->enumName] ?? -1); 99 | }else{ 100 | $packet->putLInt(-1); 101 | } 102 | 103 | $packet->putUnsignedVarInt(count($data->overloads)); 104 | foreach($data->overloads as $overload){ 105 | /** @var CommandParameter[] $overload */ 106 | $packet->putUnsignedVarInt(count($overload)); 107 | foreach($overload as $parameter){ 108 | $packet->putString($parameter->paramName); 109 | 110 | if($parameter->enum !== null){ 111 | $type = $packet::ARG_FLAG_ENUM | $packet::ARG_FLAG_VALID | ($enumIndexes[$parameter->enum->enumName] ?? -1); 112 | }elseif($parameter->postfix !== null){ 113 | $key = $postfixIndexes[$parameter->postfix] ?? -1; 114 | if($key === -1){ 115 | throw new \InvalidStateException("Postfix '$parameter->postfix' not in postfixes array"); 116 | } 117 | $type = $packet::ARG_FLAG_POSTFIX | $key; 118 | }else{ 119 | $type = $parameter->paramType; 120 | } 121 | 122 | $packet->putLInt($type); 123 | $packet->putBool($parameter->isOptional); 124 | $packet->putByte($parameter->flags); 125 | } 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/CraftingDataPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putString((\pack("N", $pos))); //some kind of recipe ID, doesn't matter what it is as long as it's unique 35 | $stream->putUnsignedVarInt($recipe->getIngredientCount()); 36 | foreach($recipe->getIngredientList() as $item){ 37 | Serializer::putRecipeIngredient($stream, $item, $protocol); 38 | } 39 | 40 | $results = $recipe->getResults(); 41 | $stream->putUnsignedVarInt(count($results)); 42 | foreach($results as $item){ 43 | Serializer::putItemStackWithoutStackId($stream, $item, $protocol); 44 | } 45 | 46 | $stream->put(str_repeat("\x00", 16)); //Null UUID 47 | $stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks) 48 | $stream->putVarInt(50); //TODO: priority 49 | $stream->writeGenericTypeNetworkId($pos); //TODO: ANOTHER recipe ID, only used on the network 50 | 51 | return CraftingDataPacket::ENTRY_SHAPELESS; 52 | } 53 | 54 | private static function writeShapedRecipe(ShapedRecipe $recipe, NetworkBinaryStream $stream, int $pos, int $protocol) : int{ 55 | $stream->putString((\pack("N", $pos))); //some kind of recipe ID, doesn't matter what it is as long as it's unique 56 | $stream->putVarInt($recipe->getWidth()); 57 | $stream->putVarInt($recipe->getHeight()); 58 | 59 | for($z = 0; $z < $recipe->getHeight(); ++$z){ 60 | for($x = 0; $x < $recipe->getWidth(); ++$x){ 61 | Serializer::putRecipeIngredient($stream, $recipe->getIngredient($x, $z), $protocol); 62 | } 63 | } 64 | 65 | $results = $recipe->getResults(); 66 | $stream->putUnsignedVarInt(count($results)); 67 | foreach($results as $item){ 68 | Serializer::putItemStackWithoutStackId($stream, $item, $protocol); 69 | } 70 | 71 | $stream->put(str_repeat("\x00", 16)); //Null UUID 72 | $stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks) 73 | $stream->putVarInt(50); //TODO: priority 74 | $stream->writeGenericTypeNetworkId($pos); //TODO: ANOTHER recipe ID, only used on the network 75 | 76 | return CraftingDataPacket::ENTRY_SHAPED; 77 | } 78 | 79 | private static function writeFurnaceRecipe(FurnaceRecipe $recipe, NetworkBinaryStream $stream, int $protocol) : int{ 80 | $input = $recipe->getInput(); 81 | if($input->hasAnyDamageValue()){ 82 | [$netId, ] = MultiVersionItemTranslator::getInstance()->toNetworkId($input->getId(), 0, $protocol); 83 | $netData = 0x7fff; 84 | }else{ 85 | [$netId, $netData] = MultiVersionItemTranslator::getInstance()->toNetworkId($input->getId(), $input->getDamage(), $protocol); 86 | } 87 | $stream->putVarInt($netId); 88 | $stream->putVarInt($netData); 89 | Serializer::putItemStackWithoutStackId($stream, $recipe->getResult(), $protocol); 90 | $stream->putString("furnace"); //TODO: blocktype (no prefix) (this might require internal API breaks) 91 | return CraftingDataPacket::ENTRY_FURNACE_DATA; 92 | } 93 | 94 | public static function serialize(CraftingDataPacket $packet, int $protocol) { 95 | $packet->putUnsignedVarInt(count($packet->entries)); 96 | 97 | $writer = new NetworkBinaryStream(); 98 | $counter = 0; 99 | foreach($packet->entries as $d){ 100 | $entryType = self::writeEntry($d, $writer, ++$counter, $protocol); 101 | if($entryType >= 0){ 102 | $packet->putVarInt($entryType); 103 | ($packet->buffer .= $writer->getBuffer()); 104 | }else{ 105 | $packet->putVarInt(-1); 106 | } 107 | 108 | $writer->reset(); 109 | } 110 | $packet->putUnsignedVarInt(count($packet->potionTypeRecipes)); 111 | foreach($packet->potionTypeRecipes as $recipe){ 112 | $packet->putVarInt($recipe->getInputItemId()); 113 | $packet->putVarInt($recipe->getInputItemMeta()); 114 | $packet->putVarInt($recipe->getIngredientItemId()); 115 | $packet->putVarInt($recipe->getIngredientItemMeta()); 116 | $packet->putVarInt($recipe->getOutputItemId()); 117 | $packet->putVarInt($recipe->getOutputItemMeta()); 118 | } 119 | $packet->putUnsignedVarInt(count($packet->potionContainerRecipes)); 120 | foreach($packet->potionContainerRecipes as $recipe){ 121 | $packet->putVarInt($recipe->getInputItemId()); 122 | $packet->putVarInt($recipe->getIngredientItemId()); 123 | $packet->putVarInt($recipe->getOutputItemId()); 124 | } 125 | if($protocol >= ProtocolConstants::BEDROCK_1_17_30){ 126 | $packet->putUnsignedVarInt(count($packet->materialReducerRecipes)); 127 | foreach($packet->materialReducerRecipes as $recipe){ 128 | $packet->putVarInt(($recipe->getInputItemId() << 16) | $recipe->getInputItemMeta()); 129 | $packet->putUnsignedVarInt(count($recipe->getOutputs())); 130 | foreach($recipe->getOutputs() as $output){ 131 | $packet->putVarInt($output->getItemId()); 132 | $packet->putVarInt($output->getCount()); 133 | } 134 | } 135 | } 136 | ($packet->buffer .= ($packet->cleanRecipes ? "\x01" : "\x00")); 137 | } 138 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/CreativeContentPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putUnsignedVarInt(count($packet->getEntries())); 15 | foreach($packet->getEntries() as $entry){ 16 | $packet->writeGenericTypeNetworkId($entry->getEntryId()); 17 | Serializer::putItemStackWithoutStackId($packet, $entry->getItem(), $protocol); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/GameRulesChangedPacketTranslator.php: -------------------------------------------------------------------------------- 1 | gameRules, $protocol); 14 | } 15 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/InventoryContentPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putUnsignedVarInt($packet->windowId); 15 | $packet->putUnsignedVarInt(count($packet->items)); 16 | foreach($packet->items as $item){ 17 | Serializer::putItem($packet, $protocol, $item->getItemStack(), $item->getStackId()); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/InventorySlotPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putUnsignedVarInt($packet->windowId); 14 | $packet->putUnsignedVarInt($packet->inventorySlot); 15 | Serializer::putItem($packet, $protocol, $packet->item->getItemStack(), $packet->item->getStackId()); 16 | } 17 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/InventoryTransactionPacketTranslator.php: -------------------------------------------------------------------------------- 1 | writeGenericTypeNetworkId($packet->requestId); 28 | if($packet->requestId !== 0){ 29 | $packet->putUnsignedVarInt(count($packet->requestChangedSlots)); 30 | foreach($packet->requestChangedSlots as $changedSlots){ 31 | $changedSlots->write($packet); 32 | } 33 | } 34 | 35 | $trData = $packet->trData; 36 | $packet->putUnsignedVarInt($trData->getTypeId()); 37 | 38 | /** @var NetworkInventoryAction[] $actions */ 39 | $actions = Utils::forceGetProps($trData, "actions"); 40 | $packet->putUnsignedVarInt(count($actions)); 41 | foreach($actions as $action) { 42 | $packet->putUnsignedVarInt($action->sourceType); 43 | 44 | switch($action->sourceType){ 45 | case $action::SOURCE_TODO: 46 | case $action::SOURCE_CONTAINER: 47 | $packet->putVarInt($action->windowId); 48 | break; 49 | case $action::SOURCE_WORLD: 50 | $packet->putUnsignedVarInt($action->sourceFlags); 51 | break; 52 | case $action::SOURCE_CREATIVE: 53 | break; 54 | default: 55 | throw new \InvalidArgumentException("Unknown inventory action source type $action->sourceType"); 56 | } 57 | 58 | $packet->putUnsignedVarInt($action->inventorySlot); 59 | Serializer::putItem($packet, $protocol, $action->oldItem->getItemStack(), $action->oldItem->getStackId()); 60 | Serializer::putItem($packet, $protocol, $action->newItem->getItemStack(), $action->newItem->getStackId()); 61 | } 62 | if($trData instanceof ReleaseItemTransactionData) { 63 | $packet->putUnsignedVarInt($trData->getActionType()); 64 | $packet->putVarInt($trData->getHotbarSlot()); 65 | /** @var ItemStackWrapper $itemInHand */ 66 | $itemInHand = $trData->getItemInHand(); 67 | Serializer::putItem($packet, $protocol, $itemInHand->getItemStack(), $itemInHand->getStackId()); 68 | $packet->putVector3($trData->getHeadPos()); 69 | } elseif ($trData instanceof UseItemOnEntityTransactionData) { 70 | $packet->putEntityRuntimeId($trData->getEntityRuntimeId()); 71 | $packet->putUnsignedVarInt($trData->getActionType()); 72 | $packet->putVarInt($trData->getHotbarSlot()); 73 | $itemInHand = $trData->getItemInHand(); 74 | Serializer::putItem($packet, $protocol, $itemInHand->getItemStack(), $itemInHand->getStackId()); 75 | $packet->putVector3($trData->getPlayerPos()); 76 | $packet->putVector3($trData->getClickPos()); 77 | } elseif ($trData instanceof UseItemTransactionData) { 78 | $packet->putUnsignedVarInt($trData->getActionType()); 79 | $packet->putBlockPosition($trData->getBlockPos()->x, $trData->getBlockPos()->y, $trData->getBlockPos()->z); 80 | $packet->putVarInt($trData->getFace()); 81 | $packet->putVarInt($trData->getHotbarSlot()); 82 | $itemInHand = $trData->getItemInHand(); 83 | Serializer::putItem($packet, $protocol, $itemInHand->getItemStack(), $itemInHand->getStackId()); 84 | $packet->putVector3($trData->getPlayerPos()); 85 | $packet->putVector3($trData->getClickPos()); 86 | $block = RuntimeBlockMapping::fromStaticRuntimeId($trData->getBlockRuntimeId()); 87 | $packet->putUnsignedVarInt(MultiVersionRuntimeBlockMapping::toStaticRuntimeId($block[0], $block[1], $protocol)); 88 | } else { 89 | Utils::forceCallMethod($trData, "encodeData", $packet); 90 | } 91 | } 92 | 93 | public static function deserialize(InventoryTransactionPacket $packet, int $protocol) { 94 | $packet->requestId = $packet->readGenericTypeNetworkId(); 95 | $packet->requestChangedSlots = []; 96 | if($packet->requestId !== 0){ 97 | for($i = 0, $len = $packet->getUnsignedVarInt(); $i < $len; ++$i){ 98 | $packet->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($packet); 99 | } 100 | } 101 | 102 | $transactionType = $packet->getUnsignedVarInt(); 103 | 104 | switch($transactionType){ 105 | case $packet::TYPE_NORMAL: 106 | $packet->trData = new NormalTransactionData(); 107 | break; 108 | case $packet::TYPE_MISMATCH: 109 | $packet->trData = new MismatchTransactionData(); 110 | break; 111 | case $packet::TYPE_USE_ITEM: 112 | $packet->trData = new UseItemTransactionData(); 113 | break; 114 | case $packet::TYPE_USE_ITEM_ON_ENTITY: 115 | $packet->trData = new UseItemOnEntityTransactionData(); 116 | break; 117 | case $packet::TYPE_RELEASE_ITEM: 118 | $packet->trData = new ReleaseItemTransactionData(); 119 | break; 120 | default: 121 | throw new PacketDecodeException("Unknown transaction type $transactionType"); 122 | } 123 | 124 | $trData = $packet->trData; 125 | $actionCount = $packet->getUnsignedVarInt(); 126 | $actions = []; 127 | for($i = 0; $i < $actionCount; ++$i){ 128 | $action = new NetworkInventoryAction(); 129 | $action->sourceType = $packet->getUnsignedVarInt(); 130 | 131 | switch($action->sourceType){ 132 | case $action::SOURCE_TODO: 133 | case $action::SOURCE_CONTAINER: 134 | $action->windowId = $packet->getVarInt(); 135 | break; 136 | case $action::SOURCE_WORLD: 137 | $action->sourceFlags = $packet->getUnsignedVarInt(); 138 | break; 139 | case $action::SOURCE_CREATIVE: 140 | break; 141 | default: 142 | throw new \UnexpectedValueException("Unknown inventory action source type $action->sourceType"); 143 | } 144 | 145 | $action->inventorySlot = $packet->getUnsignedVarInt(); 146 | $action->oldItem = Serializer::getItemStackWrapper($packet, $protocol); 147 | $action->newItem = Serializer::getItemStackWrapper($packet, $protocol); 148 | $actions[] = $action; 149 | } 150 | Utils::forceSetProps($trData, "actions", $actions); 151 | 152 | if($trData instanceof ReleaseItemTransactionData) { 153 | Utils::forceSetProps($trData, "actionType", $packet->getUnsignedVarInt()); 154 | Utils::forceSetProps($trData, "hotbarSlot", $packet->getVarInt()); 155 | Utils::forceSetProps($trData, "itemInHand", Serializer::getItemStackWrapper($packet, $protocol)); 156 | Utils::forceSetProps($trData, "headPos", $packet->getVector3()); 157 | } elseif ($trData instanceof UseItemOnEntityTransactionData) { 158 | Utils::forceSetProps($trData, "entityRuntimeId", $packet->getEntityRuntimeId()); 159 | Utils::forceSetProps($trData, "actionType", $packet->getUnsignedVarInt()); 160 | Utils::forceSetProps($trData, "hotbarSlot", $packet->getVarInt()); 161 | Utils::forceSetProps($trData, "itemInHand", Serializer::getItemStackWrapper($packet, $protocol)); 162 | Utils::forceSetProps($trData, "playerPos", $packet->getVector3()); 163 | Utils::forceSetProps($trData, "clickPos", $packet->getVector3()); 164 | } elseif ($trData instanceof UseItemTransactionData) { 165 | Utils::forceSetProps($trData, "actionType", $packet->getUnsignedVarInt()); 166 | $x = $y = $z = 0; 167 | $packet->getBlockPosition($x, $y, $z); 168 | Utils::forceSetProps($trData, "blockPos", new Vector3($x, $y, $z)); 169 | Utils::forceSetProps($trData, "face", $packet->getVarInt()); 170 | Utils::forceSetProps($trData, "hotbarSlot", $packet->getVarInt()); 171 | Utils::forceSetProps($trData, "itemInHand", Serializer::getItemStackWrapper($packet, $protocol)); 172 | Utils::forceSetProps($trData, "playerPos", $packet->getVector3()); 173 | Utils::forceSetProps($trData, "clickPos", $packet->getVector3()); 174 | $block = MultiVersionRuntimeBlockMapping::fromStaticRuntimeId($packet->getUnsignedVarInt(), $protocol); 175 | Utils::forceSetProps($trData, "blockRuntimeId", RuntimeBlockMapping::toStaticRuntimeId($block[0], $block[1])); 176 | } else { 177 | Utils::forceCallMethod($trData, "decodeData", $packet); 178 | } 179 | } 180 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/MobArmorEquipmentPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putEntityRuntimeId($packet->entityRuntimeId); 15 | Serializer::putItem($packet, $protocol, $packet->head->getItemStack(), $packet->head->getStackId()); 16 | Serializer::putItem($packet, $protocol, $packet->chest->getItemStack(), $packet->chest->getStackId()); 17 | Serializer::putItem($packet, $protocol, $packet->legs->getItemStack(), $packet->legs->getStackId()); 18 | Serializer::putItem($packet, $protocol, $packet->feet->getItemStack(), $packet->feet->getStackId()); 19 | } 20 | 21 | public static function deserialize(MobArmorEquipmentPacket $packet, int $protocol) { 22 | $packet->entityRuntimeId = $packet->getEntityRuntimeId(); 23 | $packet->head = Serializer::getItemStackWrapper($packet, $protocol); 24 | $packet->chest = Serializer::getItemStackWrapper($packet, $protocol); 25 | $packet->legs = Serializer::getItemStackWrapper($packet, $protocol); 26 | $packet->feet = Serializer::getItemStackWrapper($packet, $protocol); 27 | } 28 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/MobEquipmentPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putEntityRuntimeId($packet->entityRuntimeId); 14 | Serializer::putItem($packet, $protocol, $packet->item->getItemStack(), $packet->item->getStackId()); 15 | ($packet->buffer .= \chr($packet->inventorySlot)); 16 | ($packet->buffer .= \chr($packet->hotbarSlot)); 17 | ($packet->buffer .= \chr($packet->windowId)); 18 | } 19 | 20 | public static function deserialize(MobEquipmentPacket $packet, int $protocol) { 21 | $packet->entityRuntimeId = $packet->getEntityRuntimeId(); 22 | $packet->item = Serializer::getItemStackWrapper($packet, $protocol); 23 | $packet->inventorySlot = (\ord($packet->get(1))); 24 | $packet->hotbarSlot = (\ord($packet->get(1))); 25 | $packet->windowId = (\ord($packet->get(1))); 26 | } 27 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/NpcRequestPacketTranslator.php: -------------------------------------------------------------------------------- 1 | entityRuntimeId = $packet->getEntityRuntimeId(); 14 | $packet->requestType = $packet->getByte(); 15 | $packet->commandString = $packet->getString(); 16 | $packet->actionType = $packet->getByte(); 17 | if($protocol >= ProtocolConstants::BEDROCK_1_17_10){ 18 | $packet->sceneName = $packet->getString(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/PlayerListPacketTranslator.php: -------------------------------------------------------------------------------- 1 | buffer .= \chr($packet->type)); 15 | $packet->putUnsignedVarInt(count($packet->entries)); 16 | foreach($packet->entries as $entry){ 17 | if($packet->type === $packet::TYPE_ADD){ 18 | $packet->putUUID($entry->uuid); 19 | $packet->putEntityUniqueId($entry->entityUniqueId); 20 | $packet->putString($entry->username); 21 | $packet->putString($entry->xboxUserId); 22 | $packet->putString($entry->platformChatId); 23 | ($packet->buffer .= (\pack("V", $entry->buildPlatform))); 24 | Serializer::putSkin($entry->skinData, $packet, $protocol); 25 | ($packet->buffer .= ($entry->isTeacher ? "\x01" : "\x00")); 26 | ($packet->buffer .= ($entry->isHost ? "\x01" : "\x00")); 27 | }else{ 28 | $packet->putUUID($entry->uuid); 29 | } 30 | } 31 | if($packet->type === $packet::TYPE_ADD){ 32 | foreach($packet->entries as $entry){ 33 | ($packet->buffer .= ($entry->skinData->isVerified() ? "\x01" : "\x00")); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/PlayerSkinPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putUUID($packet->uuid); 14 | Serializer::putSkin($packet->skin, $packet, $protocol); 15 | $packet->putString($packet->newSkinName); 16 | $packet->putString($packet->oldSkinName); 17 | ($packet->buffer .= ($packet->skin->isVerified() ? "\x01" : "\x00")); 18 | } 19 | 20 | public static function deserialize(PlayerSkinPacket $packet, int $protocol) { 21 | $packet->uuid = $packet->getUUID(); 22 | $packet->skin = Serializer::getSkin($packet, $protocol); 23 | $packet->newSkinName = $packet->getString(); 24 | $packet->oldSkinName = $packet->getString(); 25 | $packet->skin->setVerified((($packet->get(1) !== "\x00"))); 26 | } 27 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/ResourcePacksInfoPacketTranslator.php: -------------------------------------------------------------------------------- 1 | putBool($packet->mustAccept); 14 | $packet->putBool($packet->hasScripts); 15 | if($protocol >= ProtocolConstants::BEDROCK_1_17_10){ 16 | $packet->putBool($packet->forceServerPacks); 17 | } 18 | $packet->putLShort(count($packet->behaviorPackEntries)); 19 | foreach($packet->behaviorPackEntries as $entry){ 20 | $packet->putString($entry->getPackId()); 21 | $packet->putString($entry->getPackVersion()); 22 | $packet->putLLong($entry->getPackSize()); 23 | $packet->putString(""); //TODO: encryption key 24 | $packet->putString(""); //TODO: subpack name 25 | $packet->putString(""); //TODO: content identity 26 | $packet->putBool(false); //TODO: has scripts (?) 27 | } 28 | $packet->putLShort(count($packet->resourcePackEntries)); 29 | foreach($packet->resourcePackEntries as $entry){ 30 | $packet->putString($entry->getPackId()); 31 | $packet->putString($entry->getPackVersion()); 32 | $packet->putLLong($entry->getPackSize()); 33 | $packet->putString(""); //TODO: encryption key 34 | $packet->putString(""); //TODO: subpack name 35 | $packet->putString(""); //TODO: content identity 36 | $packet->putBool(false); //TODO: seems useless for resource packs 37 | $packet->putBool(false); //TODO: supports RTX 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/SetTitlePacketTranslator.php: -------------------------------------------------------------------------------- 1 | putVarInt($packet->type); 14 | $packet->putString($packet->text); 15 | $packet->putVarInt($packet->fadeInTime); 16 | $packet->putVarInt($packet->stayTime); 17 | $packet->putVarInt($packet->fadeOutTime); 18 | if($protocol >= ProtocolConstants::BEDROCK_1_17_10){ 19 | $packet->putString($packet->xuid); 20 | $packet->putString($packet->platformOnlineId); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/network/translator/StartGamePacketTranslator.php: -------------------------------------------------------------------------------- 1 | putEntityUniqueId($packet->entityUniqueId); 17 | $packet->putEntityRuntimeId($packet->entityRuntimeId); 18 | $packet->putVarInt($packet->playerGamemode); 19 | 20 | $packet->putVector3($packet->playerPosition); 21 | 22 | ($packet->buffer .= (\pack("g", $packet->pitch))); 23 | ($packet->buffer .= (\pack("g", $packet->yaw))); 24 | 25 | //Level settings 26 | $packet->putVarInt($packet->seed); 27 | $packet->spawnSettings->write($packet); 28 | $packet->putVarInt($packet->generator); 29 | $packet->putVarInt($packet->worldGamemode); 30 | $packet->putVarInt($packet->difficulty); 31 | $packet->putBlockPosition($packet->spawnX, $packet->spawnY, $packet->spawnZ); 32 | ($packet->buffer .= ($packet->hasAchievementsDisabled ? "\x01" : "\x00")); 33 | $packet->putVarInt($packet->time); 34 | $packet->putVarInt($packet->eduEditionOffer); 35 | ($packet->buffer .= ($packet->hasEduFeaturesEnabled ? "\x01" : "\x00")); 36 | $packet->putString($packet->eduProductUUID); 37 | ($packet->buffer .= (\pack("g", $packet->rainLevel))); 38 | ($packet->buffer .= (\pack("g", $packet->lightningLevel))); 39 | ($packet->buffer .= ($packet->hasConfirmedPlatformLockedContent ? "\x01" : "\x00")); 40 | ($packet->buffer .= ($packet->isMultiplayerGame ? "\x01" : "\x00")); 41 | ($packet->buffer .= ($packet->hasLANBroadcast ? "\x01" : "\x00")); 42 | $packet->putVarInt($packet->xboxLiveBroadcastMode); 43 | $packet->putVarInt($packet->platformBroadcastMode); 44 | ($packet->buffer .= ($packet->commandsEnabled ? "\x01" : "\x00")); 45 | ($packet->buffer .= ($packet->isTexturePacksRequired ? "\x01" : "\x00")); 46 | Serializer::putGameRules($packet, $packet->gameRules, $protocol); 47 | $packet->experiments->write($packet); 48 | ($packet->buffer .= ($packet->hasBonusChestEnabled ? "\x01" : "\x00")); 49 | ($packet->buffer .= ($packet->hasStartWithMapEnabled ? "\x01" : "\x00")); 50 | $packet->putVarInt($packet->defaultPlayerPermission); 51 | ($packet->buffer .= (\pack("V", $packet->serverChunkTickRadius))); 52 | ($packet->buffer .= ($packet->hasLockedBehaviorPack ? "\x01" : "\x00")); 53 | ($packet->buffer .= ($packet->hasLockedResourcePack ? "\x01" : "\x00")); 54 | ($packet->buffer .= ($packet->isFromLockedWorldTemplate ? "\x01" : "\x00")); 55 | ($packet->buffer .= ($packet->useMsaGamertagsOnly ? "\x01" : "\x00")); 56 | ($packet->buffer .= ($packet->isFromWorldTemplate ? "\x01" : "\x00")); 57 | ($packet->buffer .= ($packet->isWorldTemplateOptionLocked ? "\x01" : "\x00")); 58 | ($packet->buffer .= ($packet->onlySpawnV1Villagers ? "\x01" : "\x00")); 59 | $packet->putString(ProtocolConstants::MINECRAFT_VERSION[$protocol] ?? "*"); 60 | ($packet->buffer .= (\pack("V", $packet->limitedWorldWidth))); 61 | ($packet->buffer .= (\pack("V", $packet->limitedWorldLength))); 62 | ($packet->buffer .= ($packet->isNewNether ? "\x01" : "\x00")); 63 | if($protocol >= ProtocolConstants::BEDROCK_1_17_30){ 64 | $packet->putString(""); //Education URI resource -> buttonName 65 | $packet->putString(""); //Education URI resource -> link URI 66 | } 67 | ($packet->buffer .= ($packet->experimentalGameplayOverride !== null ? "\x01" : "\x00")); 68 | if($packet->experimentalGameplayOverride !== null){ 69 | ($packet->buffer .= ($packet->experimentalGameplayOverride ? "\x01" : "\x00")); 70 | } 71 | 72 | $packet->putString($packet->levelId); 73 | $packet->putString($packet->worldName); 74 | $packet->putString($packet->premiumWorldTemplateId); 75 | ($packet->buffer .= ($packet->isTrial ? "\x01" : "\x00")); 76 | $packet->playerMovementSettings->write($packet); 77 | ($packet->buffer .= (\pack("VV", $packet->currentTick & 0xFFFFFFFF, $packet->currentTick >> 32))); 78 | 79 | $packet->putVarInt($packet->enchantmentSeed); 80 | 81 | $packet->putUnsignedVarInt(count($packet->blockPalette)); 82 | $nbtWriter = new NetworkLittleEndianNBTStream(); 83 | foreach($packet->blockPalette as $entry){ 84 | $packet->putString($entry->getName()); 85 | ($packet->buffer .= $nbtWriter->write($entry->getStates())); 86 | } 87 | $packet->putUnsignedVarInt(count($packet->itemTable)); 88 | foreach($packet->itemTable as $entry){ 89 | $packet->putString($entry->getStringId()); 90 | ($packet->buffer .= (\pack("v", $entry->getNumericId()))); 91 | ($packet->buffer .= ($entry->isComponentBased() ? "\x01" : "\x00")); 92 | } 93 | 94 | $packet->putString($packet->multiplayerCorrelationId); 95 | ($packet->buffer .= ($packet->enableNewInventorySystem ? "\x01" : "\x00")); 96 | if($protocol >= ProtocolConstants::BEDROCK_1_17_0){ 97 | $packet->putString($packet->serverSoftwareVersion); 98 | } 99 | if($protocol >= ProtocolConstants::BEDROCK_1_18_0){ 100 | $packet->putLLong(0); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/session/Session.php: -------------------------------------------------------------------------------- 1 | session = $session; 19 | $this->protocol = $protocol; 20 | } 21 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/session/SessionManager.php: -------------------------------------------------------------------------------- 1 | getDisplayName()] ?? null; 16 | } 17 | 18 | public static function remove(NetworkSession $session) { 19 | unset(self::$sessions[$session->getDisplayName()]); 20 | } 21 | 22 | public static function create(NetworkSession $session, int $protocol) { 23 | self::$sessions[$session->getDisplayName()] = new Session($session, $protocol); 24 | } 25 | 26 | public static function getProtocol(NetworkSession $session): ?int{ 27 | if(($session = self::get($session)) !== null) { 28 | return $session->protocol; 29 | } 30 | return null; 31 | } 32 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/task/CheckUpdateTask.php: -------------------------------------------------------------------------------- 1 | getAsyncPool()->submitTask(new self($pluginVersion)); 19 | } 20 | 21 | const PLUGIN_NAME = "MultiVersion"; 22 | 23 | const API_URL = "https://poggit.pmmp.io/releases.min.json?name=" . self::PLUGIN_NAME; 24 | 25 | /** @var string */ 26 | private $currentVersion; 27 | 28 | public function __construct(string $currentVersion){ 29 | $this->currentVersion = $currentVersion; 30 | } 31 | 32 | public function onRun() : void{ 33 | try{ 34 | $response = json_decode(Internet::getURL(self::API_URL), true); 35 | $ver = $this->currentVersion; 36 | $api = null; 37 | $downloadUrl = null; 38 | $date = null; 39 | foreach($response as $plugins) { 40 | if(version_compare($ver, $plugins["version"], ">=")){ 41 | continue; 42 | } 43 | $ver = $plugins["version"]; 44 | $api = $plugins["api"][0]["from"] . " - " . $plugins["api"][0]["to"]; 45 | $downloadUrl = $plugins["artifact_url"] . "/" . self::PLUGIN_NAME . ".phar"; 46 | $date = $plugins["last_state_change_date"]; 47 | } 48 | if($ver === $this->currentVersion) { 49 | $this->setResult(null); 50 | } else{ 51 | $this->setResult([$ver, $api, $downloadUrl, $date]); 52 | } 53 | } catch(\Throwable $exception) { 54 | $this->setResult(null); 55 | } 56 | } 57 | 58 | public function onCompletion() : void{ 59 | $res = $this->getResult(); 60 | if($res === null) { 61 | return; 62 | } 63 | [$ver, $api, $url, $date] = $res; 64 | $date = date("d F y H:i", $date) . " UTC"; 65 | $messages = [ 66 | "=========== Update Available ===========", 67 | "Version: " . $ver, 68 | "Time: " . $date, 69 | "API: " . $api, 70 | "Download URL: " . $url, 71 | "========================================" 72 | ]; 73 | foreach($messages as $m) { 74 | Loader::getInstance()->getLogger()->notice(TextFormat::GOLD . $m); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/task/CompressTask.php: -------------------------------------------------------------------------------- 1 | rewind(); 29 | $promise = new CompressBatchPromise(); 30 | $this->storeLocal(self::TLS_KEY_PROMISE, $promise); 31 | $this->storeLocal(self::TLS_KEY_ERROR_HOOK, $callback); 32 | $this->payload = $promise->getResult(); 33 | $this->level = 7; 34 | } 35 | 36 | public function onRun(): void{ 37 | try{ 38 | $this->setResult(zlib_encode($this->payload, ZLIB_ENCODING_RAW, $this->level)); 39 | } catch(\Exception $e) { 40 | $this->fail = true; 41 | } 42 | } 43 | 44 | public function onCompletion() : void{ 45 | if($this->fail) { 46 | Loader::getInstance()->getLogger()->error("Failed to compress batch packet"); 47 | return; 48 | } 49 | /** @var CompressBatchPromise $promise */ 50 | [$packet, $callback] = $this->fetchLocal(self::TLS_KEY_PROMISE); 51 | $promise->resolve($this->getResult()); 52 | $callback($packet); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/task/DecompressTask.php: -------------------------------------------------------------------------------- 1 | setOffset(0); 28 | $packet->getByte(); 29 | $this->buffer = $packet->getRemaining(); 30 | $this->storeLocal(self::TLS_KEY_PROMISE, $packet); 31 | $this->storeLocal(self::TLS_KEY_ERROR_HOOK, $callback); 32 | } 33 | 34 | public function onRun(): void{ 35 | try{ 36 | $this->setResult(zlib_decode($this->buffer, 1024 * 1024 * 2)); 37 | } catch(\Exception $e) { 38 | $this->fail = true; 39 | } 40 | } 41 | 42 | public function onCompletion(): void{ 43 | if($this->fail) { 44 | Loader::getInstance()->getLogger()->error("Failed to decompress batch packet"); 45 | return; 46 | } 47 | /** @var CompressBatchPromise $promise */ 48 | [$packet, $callback] = $this->fetchLocal(self::TLS_KEY_PROMISE); 49 | $promise->resolve($this->getResult()); 50 | $packet->offset = 0; 51 | $packet->payload = $this->getResult(); 52 | $callback($packet); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/AkmalFairuz/MultiVersion/utils/Utils.php: -------------------------------------------------------------------------------- 1 | getProperty($propName); 15 | $prop->setAccessible(true); 16 | return $prop->getValue($object); 17 | } catch(ReflectionException $e) { 18 | return null; 19 | } 20 | } 21 | 22 | public static function forceSetProps($object, string $propName, $value) { 23 | try{ 24 | $reflection = new \ReflectionClass($object); 25 | $prop = $reflection->getProperty($propName); 26 | $prop->setAccessible(true); 27 | $prop->setValue($object, $value); 28 | } catch(ReflectionException $e) { 29 | } 30 | } 31 | 32 | public static function forceCallMethod($object, string $methodName, ...$args) { 33 | try{ 34 | $reflection = new \ReflectionClass($object); 35 | $method = $reflection->getMethod($methodName); 36 | $method->setAccessible(true); 37 | ($method->getClosure($object))(...$args); 38 | } catch(ReflectionException $e) { 39 | } 40 | } 41 | } --------------------------------------------------------------------------------