diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index a9828efbe..554d0e5c5 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -18,4 +18,4 @@ jobs: - name: Checkout Actions Repository uses: actions/checkout@v4 - name: Spell Check Repo - uses: crate-ci/typos@v1.29.7 \ No newline at end of file + uses: crate-ci/typos@v1.29.9 \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 1aa60adf6..b27a9ebb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ [workspace.package] version = "0.1.0" -edition = "2021" +edition = "2024" [profile.dev] @@ -51,7 +51,7 @@ rayon = "1.10" parking_lot = { version = "0.12", features = ["send_guard"] } crossbeam = "0.8" -uuid = { version = "1.13", features = ["serde", "v3", "v4"] } +uuid = { version = "1.15", features = ["serde", "v3", "v4"] } derive_more = { version = "2.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/README.md b/README.md index 8e2ec1fb1..a410b9908 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ and customizable experience. It prioritizes performance and player enjoyment whi > [!IMPORTANT] > Pumpkin is currently under heavy development. -## Features (WIP) +## Features - [x] Configuration (toml) - [x] Server Status/Ping @@ -41,20 +41,23 @@ and customizable experience. It prioritizes performance and player enjoyment whi - World - [x] World Joining - [x] Player Tab-list + - [x] Scoreboard - [x] World Loading + - [x] World Time + - [x] World Borders + - [x] World Saving (W.I.P) - [x] Lighting - [x] Entity Spawning - - [x] Item drops + - [x] Item drops (W.I.P) - [x] Bossbar + - [x] TNT - [x] Chunk Loading (Vanilla, Linear) - [x] Chunk Generation - [x] Chunk Saving (Vanilla, Linear) - - [x] World Time - - [x] Scoreboard - - [x] World Borders - - [x] World Saving - [ ] Redstone - [ ] Liquid Physics + - [ ] Biomes + - [ ] Vegetation - Player - [x] Skins - [x] Client brand @@ -65,15 +68,22 @@ and customizable experience. It prioritizes performance and player enjoyment whi - [x] Combat - [x] Experience - [x] Hunger + - [ ] Off Hand + - [ ] Advancements + - [ ] Eating - Entities - - [x] Non-Living (Minecart, Eggs...) + - [x] Non-Living (Minecart, Eggs...) (W.I.P) + - [x] Entity Effects - [x] Players - - [x] Mobs - - [x] Animals - - [x] Entity AI + - [x] Mobs (W.I.P) + - [x] Animals (W.I.P) + - [x] Entity AI (W.I.P) + - [ ] Entity Saving - [ ] Boss + - [ ] Villagers + - [ ] Mobs Inventory - Server - - [x] Plugins + - [x] Plugins (W.I.P) - [x] Query - [x] RCON - [x] Inventories diff --git a/assets/blocks.json b/assets/blocks.json index 4952136f1..b87c387f1 100644 --- a/assets/blocks.json +++ b/assets/blocks.json @@ -4182,6 +4182,7 @@ "name": "air", "translation_key": "block.minecraft.air", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "properties": [], "default_state_id": 0, @@ -4204,6 +4205,7 @@ "name": "stone", "translation_key": "block.minecraft.stone", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1, "loot_table": { "type": "minecraft:block", @@ -4276,6 +4278,7 @@ "name": "granite", "translation_key": "block.minecraft.granite", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 2, "loot_table": { "type": "minecraft:block", @@ -4322,6 +4325,7 @@ "name": "polished_granite", "translation_key": "block.minecraft.polished_granite", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 3, "loot_table": { "type": "minecraft:block", @@ -4368,6 +4372,7 @@ "name": "diorite", "translation_key": "block.minecraft.diorite", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 4, "loot_table": { "type": "minecraft:block", @@ -4414,6 +4419,7 @@ "name": "polished_diorite", "translation_key": "block.minecraft.polished_diorite", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 5, "loot_table": { "type": "minecraft:block", @@ -4460,6 +4466,7 @@ "name": "andesite", "translation_key": "block.minecraft.andesite", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 6, "loot_table": { "type": "minecraft:block", @@ -4506,6 +4513,7 @@ "name": "polished_andesite", "translation_key": "block.minecraft.polished_andesite", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 7, "loot_table": { "type": "minecraft:block", @@ -4552,6 +4560,7 @@ "name": "grass_block", "translation_key": "block.minecraft.grass_block", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 27, "loot_table": { "type": "minecraft:block", @@ -4646,6 +4655,7 @@ "name": "dirt", "translation_key": "block.minecraft.dirt", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 28, "loot_table": { "type": "minecraft:block", @@ -4692,6 +4702,7 @@ "name": "coarse_dirt", "translation_key": "block.minecraft.coarse_dirt", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 29, "loot_table": { "type": "minecraft:block", @@ -4738,6 +4749,7 @@ "name": "podzol", "translation_key": "block.minecraft.podzol", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 30, "loot_table": { "type": "minecraft:block", @@ -4832,6 +4844,7 @@ "name": "cobblestone", "translation_key": "block.minecraft.cobblestone", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 35, "loot_table": { "type": "minecraft:block", @@ -4878,6 +4891,7 @@ "name": "oak_planks", "translation_key": "block.minecraft.oak_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 36, "loot_table": { "type": "minecraft:block", @@ -4924,6 +4938,7 @@ "name": "spruce_planks", "translation_key": "block.minecraft.spruce_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 37, "loot_table": { "type": "minecraft:block", @@ -4970,6 +4985,7 @@ "name": "birch_planks", "translation_key": "block.minecraft.birch_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 38, "loot_table": { "type": "minecraft:block", @@ -5016,6 +5032,7 @@ "name": "jungle_planks", "translation_key": "block.minecraft.jungle_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 39, "loot_table": { "type": "minecraft:block", @@ -5062,6 +5079,7 @@ "name": "acacia_planks", "translation_key": "block.minecraft.acacia_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 40, "loot_table": { "type": "minecraft:block", @@ -5108,6 +5126,7 @@ "name": "cherry_planks", "translation_key": "block.minecraft.cherry_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 41, "loot_table": { "type": "minecraft:block", @@ -5154,6 +5173,7 @@ "name": "dark_oak_planks", "translation_key": "block.minecraft.dark_oak_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 42, "loot_table": { "type": "minecraft:block", @@ -5200,6 +5220,7 @@ "name": "pale_oak_wood", "translation_key": "block.minecraft.pale_oak_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 177, "loot_table": { "type": "minecraft:block", @@ -5283,6 +5304,7 @@ "name": "pale_oak_planks", "translation_key": "block.minecraft.pale_oak_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 43, "loot_table": { "type": "minecraft:block", @@ -5329,6 +5351,7 @@ "name": "mangrove_planks", "translation_key": "block.minecraft.mangrove_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 44, "loot_table": { "type": "minecraft:block", @@ -5375,6 +5398,7 @@ "name": "bamboo_planks", "translation_key": "block.minecraft.bamboo_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 45, "loot_table": { "type": "minecraft:block", @@ -5421,6 +5445,7 @@ "name": "bamboo_mosaic", "translation_key": "block.minecraft.bamboo_mosaic", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 48, "loot_table": { "type": "minecraft:block", @@ -5467,6 +5492,7 @@ "name": "oak_sapling", "translation_key": "block.minecraft.oak_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 49, "loot_table": { "type": "minecraft:block", @@ -5529,6 +5555,7 @@ "name": "spruce_sapling", "translation_key": "block.minecraft.spruce_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 50, "loot_table": { "type": "minecraft:block", @@ -5591,6 +5618,7 @@ "name": "birch_sapling", "translation_key": "block.minecraft.birch_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 51, "loot_table": { "type": "minecraft:block", @@ -5653,6 +5681,7 @@ "name": "jungle_sapling", "translation_key": "block.minecraft.jungle_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 52, "loot_table": { "type": "minecraft:block", @@ -5715,6 +5744,7 @@ "name": "acacia_sapling", "translation_key": "block.minecraft.acacia_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 53, "loot_table": { "type": "minecraft:block", @@ -5777,6 +5807,7 @@ "name": "cherry_sapling", "translation_key": "block.minecraft.cherry_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 54, "loot_table": { "type": "minecraft:block", @@ -5839,6 +5870,7 @@ "name": "dark_oak_sapling", "translation_key": "block.minecraft.dark_oak_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 55, "loot_table": { "type": "minecraft:block", @@ -5901,6 +5933,7 @@ "name": "pale_oak_sapling", "translation_key": "block.minecraft.pale_oak_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 56, "loot_table": { "type": "minecraft:block", @@ -5963,6 +5996,7 @@ "name": "mangrove_propagule", "translation_key": "block.minecraft.mangrove_propagule", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 57, "loot_table": { "type": "minecraft:block", @@ -6476,6 +6510,7 @@ "name": "bedrock", "translation_key": "block.minecraft.bedrock", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 58, "properties": [], "default_state_id": 85, @@ -6501,6 +6536,7 @@ "name": "water", "translation_key": "block.minecraft.water", "hardness": 100.0, + "blast_resistance": 100.0, "item_id": 0, "properties": [ { @@ -6710,6 +6746,7 @@ "name": "lava", "translation_key": "block.minecraft.lava", "hardness": 100.0, + "blast_resistance": 100.0, "item_id": 0, "properties": [ { @@ -6919,6 +6956,7 @@ "name": "sand", "translation_key": "block.minecraft.sand", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 59, "loot_table": { "type": "minecraft:block", @@ -6965,6 +7003,7 @@ "name": "suspicious_sand", "translation_key": "block.minecraft.suspicious_sand", "hardness": 0.25, + "blast_resistance": 0.25, "item_id": 60, "loot_table": { "type": "minecraft:block", @@ -7050,6 +7089,7 @@ "name": "red_sand", "translation_key": "block.minecraft.red_sand", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 62, "loot_table": { "type": "minecraft:block", @@ -7096,6 +7136,7 @@ "name": "gravel", "translation_key": "block.minecraft.gravel", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 63, "loot_table": { "type": "minecraft:block", @@ -7189,6 +7230,7 @@ "name": "suspicious_gravel", "translation_key": "block.minecraft.suspicious_gravel", "hardness": 0.25, + "blast_resistance": 0.25, "item_id": 61, "loot_table": { "type": "minecraft:block", @@ -7274,6 +7316,7 @@ "name": "gold_ore", "translation_key": "block.minecraft.gold_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 70, "experience": { "experience": 0, @@ -7355,6 +7398,7 @@ "name": "deepslate_gold_ore", "translation_key": "block.minecraft.deepslate_gold_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 71, "experience": { "experience": 0, @@ -7436,6 +7480,7 @@ "name": "iron_ore", "translation_key": "block.minecraft.iron_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 66, "experience": { "experience": 0, @@ -7517,6 +7562,7 @@ "name": "deepslate_iron_ore", "translation_key": "block.minecraft.deepslate_iron_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 67, "experience": { "experience": 0, @@ -7598,6 +7644,7 @@ "name": "coal_ore", "translation_key": "block.minecraft.coal_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 64, "experience": { "experience": { @@ -7683,6 +7730,7 @@ "name": "deepslate_coal_ore", "translation_key": "block.minecraft.deepslate_coal_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 65, "experience": { "experience": { @@ -7768,6 +7816,7 @@ "name": "nether_gold_ore", "translation_key": "block.minecraft.nether_gold_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 80, "experience": { "experience": { @@ -7862,6 +7911,7 @@ "name": "oak_log", "translation_key": "block.minecraft.oak_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 134, "loot_table": { "type": "minecraft:block", @@ -7945,6 +7995,7 @@ "name": "spruce_log", "translation_key": "block.minecraft.spruce_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 135, "loot_table": { "type": "minecraft:block", @@ -8028,6 +8079,7 @@ "name": "birch_log", "translation_key": "block.minecraft.birch_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 136, "loot_table": { "type": "minecraft:block", @@ -8111,6 +8163,7 @@ "name": "jungle_log", "translation_key": "block.minecraft.jungle_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 137, "loot_table": { "type": "minecraft:block", @@ -8194,6 +8247,7 @@ "name": "acacia_log", "translation_key": "block.minecraft.acacia_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 138, "loot_table": { "type": "minecraft:block", @@ -8277,6 +8331,7 @@ "name": "cherry_log", "translation_key": "block.minecraft.cherry_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 139, "loot_table": { "type": "minecraft:block", @@ -8360,6 +8415,7 @@ "name": "dark_oak_log", "translation_key": "block.minecraft.dark_oak_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 141, "loot_table": { "type": "minecraft:block", @@ -8443,6 +8499,7 @@ "name": "pale_oak_log", "translation_key": "block.minecraft.pale_oak_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 140, "loot_table": { "type": "minecraft:block", @@ -8526,6 +8583,7 @@ "name": "mangrove_log", "translation_key": "block.minecraft.mangrove_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 142, "loot_table": { "type": "minecraft:block", @@ -8609,6 +8667,7 @@ "name": "mangrove_roots", "translation_key": "block.minecraft.mangrove_roots", "hardness": 0.7, + "blast_resistance": 0.7, "item_id": 143, "loot_table": { "type": "minecraft:block", @@ -8675,6 +8734,7 @@ "name": "muddy_mangrove_roots", "translation_key": "block.minecraft.muddy_mangrove_roots", "hardness": 0.7, + "blast_resistance": 0.7, "item_id": 144, "loot_table": { "type": "minecraft:block", @@ -8758,6 +8818,7 @@ "name": "bamboo_block", "translation_key": "block.minecraft.bamboo_block", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 147, "loot_table": { "type": "minecraft:block", @@ -8841,6 +8902,7 @@ "name": "stripped_spruce_log", "translation_key": "block.minecraft.stripped_spruce_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 149, "loot_table": { "type": "minecraft:block", @@ -8924,6 +8986,7 @@ "name": "stripped_birch_log", "translation_key": "block.minecraft.stripped_birch_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 150, "loot_table": { "type": "minecraft:block", @@ -9007,6 +9070,7 @@ "name": "stripped_jungle_log", "translation_key": "block.minecraft.stripped_jungle_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 151, "loot_table": { "type": "minecraft:block", @@ -9090,6 +9154,7 @@ "name": "stripped_acacia_log", "translation_key": "block.minecraft.stripped_acacia_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 152, "loot_table": { "type": "minecraft:block", @@ -9173,6 +9238,7 @@ "name": "stripped_cherry_log", "translation_key": "block.minecraft.stripped_cherry_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 153, "loot_table": { "type": "minecraft:block", @@ -9256,6 +9322,7 @@ "name": "stripped_dark_oak_log", "translation_key": "block.minecraft.stripped_dark_oak_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 154, "loot_table": { "type": "minecraft:block", @@ -9339,6 +9406,7 @@ "name": "stripped_pale_oak_log", "translation_key": "block.minecraft.stripped_pale_oak_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 155, "loot_table": { "type": "minecraft:block", @@ -9422,6 +9490,7 @@ "name": "stripped_oak_log", "translation_key": "block.minecraft.stripped_oak_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 148, "loot_table": { "type": "minecraft:block", @@ -9505,6 +9574,7 @@ "name": "stripped_mangrove_log", "translation_key": "block.minecraft.stripped_mangrove_log", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 156, "loot_table": { "type": "minecraft:block", @@ -9588,6 +9658,7 @@ "name": "stripped_bamboo_block", "translation_key": "block.minecraft.stripped_bamboo_block", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 170, "loot_table": { "type": "minecraft:block", @@ -9671,6 +9742,7 @@ "name": "oak_wood", "translation_key": "block.minecraft.oak_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 171, "loot_table": { "type": "minecraft:block", @@ -9754,6 +9826,7 @@ "name": "spruce_wood", "translation_key": "block.minecraft.spruce_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 172, "loot_table": { "type": "minecraft:block", @@ -9837,6 +9910,7 @@ "name": "birch_wood", "translation_key": "block.minecraft.birch_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 173, "loot_table": { "type": "minecraft:block", @@ -9920,6 +9994,7 @@ "name": "jungle_wood", "translation_key": "block.minecraft.jungle_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 174, "loot_table": { "type": "minecraft:block", @@ -10003,6 +10078,7 @@ "name": "acacia_wood", "translation_key": "block.minecraft.acacia_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 175, "loot_table": { "type": "minecraft:block", @@ -10086,6 +10162,7 @@ "name": "cherry_wood", "translation_key": "block.minecraft.cherry_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 176, "loot_table": { "type": "minecraft:block", @@ -10169,6 +10246,7 @@ "name": "dark_oak_wood", "translation_key": "block.minecraft.dark_oak_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 178, "loot_table": { "type": "minecraft:block", @@ -10252,6 +10330,7 @@ "name": "mangrove_wood", "translation_key": "block.minecraft.mangrove_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 179, "loot_table": { "type": "minecraft:block", @@ -10335,6 +10414,7 @@ "name": "stripped_oak_wood", "translation_key": "block.minecraft.stripped_oak_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 159, "loot_table": { "type": "minecraft:block", @@ -10418,6 +10498,7 @@ "name": "stripped_spruce_wood", "translation_key": "block.minecraft.stripped_spruce_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 160, "loot_table": { "type": "minecraft:block", @@ -10501,6 +10582,7 @@ "name": "stripped_birch_wood", "translation_key": "block.minecraft.stripped_birch_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 161, "loot_table": { "type": "minecraft:block", @@ -10584,6 +10666,7 @@ "name": "stripped_jungle_wood", "translation_key": "block.minecraft.stripped_jungle_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 162, "loot_table": { "type": "minecraft:block", @@ -10667,6 +10750,7 @@ "name": "stripped_acacia_wood", "translation_key": "block.minecraft.stripped_acacia_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 163, "loot_table": { "type": "minecraft:block", @@ -10750,6 +10834,7 @@ "name": "stripped_cherry_wood", "translation_key": "block.minecraft.stripped_cherry_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 164, "loot_table": { "type": "minecraft:block", @@ -10833,6 +10918,7 @@ "name": "stripped_dark_oak_wood", "translation_key": "block.minecraft.stripped_dark_oak_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 165, "loot_table": { "type": "minecraft:block", @@ -10916,6 +11002,7 @@ "name": "stripped_pale_oak_wood", "translation_key": "block.minecraft.stripped_pale_oak_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 166, "loot_table": { "type": "minecraft:block", @@ -10999,6 +11086,7 @@ "name": "stripped_mangrove_wood", "translation_key": "block.minecraft.stripped_mangrove_wood", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 167, "loot_table": { "type": "minecraft:block", @@ -11082,6 +11170,7 @@ "name": "oak_leaves", "translation_key": "block.minecraft.oak_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 182, "loot_table": { "type": "minecraft:block", @@ -11677,6 +11766,7 @@ "name": "spruce_leaves", "translation_key": "block.minecraft.spruce_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 183, "loot_table": { "type": "minecraft:block", @@ -12215,6 +12305,7 @@ "name": "birch_leaves", "translation_key": "block.minecraft.birch_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 184, "loot_table": { "type": "minecraft:block", @@ -12753,6 +12844,7 @@ "name": "jungle_leaves", "translation_key": "block.minecraft.jungle_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 185, "loot_table": { "type": "minecraft:block", @@ -13292,6 +13384,7 @@ "name": "acacia_leaves", "translation_key": "block.minecraft.acacia_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 186, "loot_table": { "type": "minecraft:block", @@ -13830,6 +13923,7 @@ "name": "cherry_leaves", "translation_key": "block.minecraft.cherry_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 187, "loot_table": { "type": "minecraft:block", @@ -14368,6 +14462,7 @@ "name": "dark_oak_leaves", "translation_key": "block.minecraft.dark_oak_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 188, "loot_table": { "type": "minecraft:block", @@ -14963,6 +15058,7 @@ "name": "pale_oak_leaves", "translation_key": "block.minecraft.pale_oak_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 189, "loot_table": { "type": "minecraft:block", @@ -15501,6 +15597,7 @@ "name": "mangrove_leaves", "translation_key": "block.minecraft.mangrove_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 190, "loot_table": { "type": "minecraft:block", @@ -15983,6 +16080,7 @@ "name": "azalea_leaves", "translation_key": "block.minecraft.azalea_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 191, "loot_table": { "type": "minecraft:block", @@ -16521,6 +16619,7 @@ "name": "flowering_azalea_leaves", "translation_key": "block.minecraft.flowering_azalea_leaves", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 192, "loot_table": { "type": "minecraft:block", @@ -17059,6 +17158,7 @@ "name": "sponge", "translation_key": "block.minecraft.sponge", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 193, "loot_table": { "type": "minecraft:block", @@ -17105,6 +17205,7 @@ "name": "wet_sponge", "translation_key": "block.minecraft.wet_sponge", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 194, "loot_table": { "type": "minecraft:block", @@ -17151,6 +17252,7 @@ "name": "glass", "translation_key": "block.minecraft.glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 195, "loot_table": { "type": "minecraft:block", @@ -17208,6 +17310,7 @@ "name": "lapis_ore", "translation_key": "block.minecraft.lapis_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 76, "experience": { "experience": { @@ -17302,6 +17405,7 @@ "name": "deepslate_lapis_ore", "translation_key": "block.minecraft.deepslate_lapis_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 77, "experience": { "experience": { @@ -17396,6 +17500,7 @@ "name": "lapis_block", "translation_key": "block.minecraft.lapis_block", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 197, "loot_table": { "type": "minecraft:block", @@ -17442,6 +17547,7 @@ "name": "dispenser", "translation_key": "block.minecraft.dispenser", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 691, "loot_table": { "type": "minecraft:block", @@ -17682,6 +17788,7 @@ "name": "sandstone", "translation_key": "block.minecraft.sandstone", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 198, "loot_table": { "type": "minecraft:block", @@ -17728,6 +17835,7 @@ "name": "chiseled_sandstone", "translation_key": "block.minecraft.chiseled_sandstone", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 199, "loot_table": { "type": "minecraft:block", @@ -17774,6 +17882,7 @@ "name": "cut_sandstone", "translation_key": "block.minecraft.cut_sandstone", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 200, "loot_table": { "type": "minecraft:block", @@ -17820,6 +17929,7 @@ "name": "note_block", "translation_key": "block.minecraft.note_block", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 704, "loot_table": { "type": "minecraft:block", @@ -34018,6 +34128,7 @@ "name": "white_bed", "translation_key": "block.minecraft.white_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1013, "loot_table": { "type": "minecraft:block", @@ -34359,6 +34470,7 @@ "name": "orange_bed", "translation_key": "block.minecraft.orange_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1014, "loot_table": { "type": "minecraft:block", @@ -34700,6 +34812,7 @@ "name": "magenta_bed", "translation_key": "block.minecraft.magenta_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1015, "loot_table": { "type": "minecraft:block", @@ -35041,6 +35154,7 @@ "name": "light_blue_bed", "translation_key": "block.minecraft.light_blue_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1016, "loot_table": { "type": "minecraft:block", @@ -35382,6 +35496,7 @@ "name": "yellow_bed", "translation_key": "block.minecraft.yellow_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1017, "loot_table": { "type": "minecraft:block", @@ -35723,6 +35838,7 @@ "name": "lime_bed", "translation_key": "block.minecraft.lime_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1018, "loot_table": { "type": "minecraft:block", @@ -36064,6 +36180,7 @@ "name": "pink_bed", "translation_key": "block.minecraft.pink_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1019, "loot_table": { "type": "minecraft:block", @@ -36405,6 +36522,7 @@ "name": "gray_bed", "translation_key": "block.minecraft.gray_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1020, "loot_table": { "type": "minecraft:block", @@ -36746,6 +36864,7 @@ "name": "light_gray_bed", "translation_key": "block.minecraft.light_gray_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1021, "loot_table": { "type": "minecraft:block", @@ -37087,6 +37206,7 @@ "name": "cyan_bed", "translation_key": "block.minecraft.cyan_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1022, "loot_table": { "type": "minecraft:block", @@ -37428,6 +37548,7 @@ "name": "purple_bed", "translation_key": "block.minecraft.purple_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1023, "loot_table": { "type": "minecraft:block", @@ -37769,6 +37890,7 @@ "name": "blue_bed", "translation_key": "block.minecraft.blue_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1024, "loot_table": { "type": "minecraft:block", @@ -38110,6 +38232,7 @@ "name": "brown_bed", "translation_key": "block.minecraft.brown_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1025, "loot_table": { "type": "minecraft:block", @@ -38451,6 +38574,7 @@ "name": "green_bed", "translation_key": "block.minecraft.green_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1026, "loot_table": { "type": "minecraft:block", @@ -38792,6 +38916,7 @@ "name": "red_bed", "translation_key": "block.minecraft.red_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1027, "loot_table": { "type": "minecraft:block", @@ -39133,6 +39258,7 @@ "name": "black_bed", "translation_key": "block.minecraft.black_bed", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 1028, "loot_table": { "type": "minecraft:block", @@ -39474,6 +39600,7 @@ "name": "powered_rail", "translation_key": "block.minecraft.powered_rail", "hardness": 0.7, + "blast_resistance": 0.7, "item_id": 789, "loot_table": { "type": "minecraft:block", @@ -39796,6 +39923,7 @@ "name": "detector_rail", "translation_key": "block.minecraft.detector_rail", "hardness": 0.7, + "blast_resistance": 0.7, "item_id": 790, "loot_table": { "type": "minecraft:block", @@ -40118,6 +40246,7 @@ "name": "sticky_piston", "translation_key": "block.minecraft.sticky_piston", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 686, "loot_table": { "type": "minecraft:block", @@ -40337,6 +40466,7 @@ "name": "cobweb", "translation_key": "block.minecraft.cobweb", "hardness": 4.0, + "blast_resistance": 4.0, "item_id": 201, "loot_table": { "type": "minecraft:block", @@ -40417,6 +40547,7 @@ "name": "short_grass", "translation_key": "block.minecraft.short_grass", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 202, "loot_table": { "type": "minecraft:block", @@ -40491,6 +40622,7 @@ "name": "fern", "translation_key": "block.minecraft.fern", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 203, "loot_table": { "type": "minecraft:block", @@ -40565,6 +40697,7 @@ "name": "dead_bush", "translation_key": "block.minecraft.dead_bush", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 206, "loot_table": { "type": "minecraft:block", @@ -40634,6 +40767,7 @@ "name": "seagrass", "translation_key": "block.minecraft.seagrass", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 207, "loot_table": { "type": "minecraft:block", @@ -40680,6 +40814,7 @@ "name": "tall_seagrass", "translation_key": "block.minecraft.tall_seagrass", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -40752,6 +40887,7 @@ "name": "piston", "translation_key": "block.minecraft.piston", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 685, "loot_table": { "type": "minecraft:block", @@ -40971,6 +41107,7 @@ "name": "piston_head", "translation_key": "block.minecraft.piston_head", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 0, "properties": [ { @@ -41380,6 +41517,7 @@ "name": "white_wool", "translation_key": "block.minecraft.white_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 209, "loot_table": { "type": "minecraft:block", @@ -41426,6 +41564,7 @@ "name": "orange_wool", "translation_key": "block.minecraft.orange_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 210, "loot_table": { "type": "minecraft:block", @@ -41472,6 +41611,7 @@ "name": "magenta_wool", "translation_key": "block.minecraft.magenta_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 211, "loot_table": { "type": "minecraft:block", @@ -41518,6 +41658,7 @@ "name": "light_blue_wool", "translation_key": "block.minecraft.light_blue_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 212, "loot_table": { "type": "minecraft:block", @@ -41564,6 +41705,7 @@ "name": "yellow_wool", "translation_key": "block.minecraft.yellow_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 213, "loot_table": { "type": "minecraft:block", @@ -41610,6 +41752,7 @@ "name": "lime_wool", "translation_key": "block.minecraft.lime_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 214, "loot_table": { "type": "minecraft:block", @@ -41656,6 +41799,7 @@ "name": "pink_wool", "translation_key": "block.minecraft.pink_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 215, "loot_table": { "type": "minecraft:block", @@ -41702,6 +41846,7 @@ "name": "gray_wool", "translation_key": "block.minecraft.gray_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 216, "loot_table": { "type": "minecraft:block", @@ -41748,6 +41893,7 @@ "name": "light_gray_wool", "translation_key": "block.minecraft.light_gray_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 217, "loot_table": { "type": "minecraft:block", @@ -41794,6 +41940,7 @@ "name": "cyan_wool", "translation_key": "block.minecraft.cyan_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 218, "loot_table": { "type": "minecraft:block", @@ -41840,6 +41987,7 @@ "name": "purple_wool", "translation_key": "block.minecraft.purple_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 219, "loot_table": { "type": "minecraft:block", @@ -41886,6 +42034,7 @@ "name": "blue_wool", "translation_key": "block.minecraft.blue_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 220, "loot_table": { "type": "minecraft:block", @@ -41932,6 +42081,7 @@ "name": "brown_wool", "translation_key": "block.minecraft.brown_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 221, "loot_table": { "type": "minecraft:block", @@ -41978,6 +42128,7 @@ "name": "green_wool", "translation_key": "block.minecraft.green_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 222, "loot_table": { "type": "minecraft:block", @@ -42024,6 +42175,7 @@ "name": "red_wool", "translation_key": "block.minecraft.red_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 223, "loot_table": { "type": "minecraft:block", @@ -42070,6 +42222,7 @@ "name": "black_wool", "translation_key": "block.minecraft.black_wool", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 224, "loot_table": { "type": "minecraft:block", @@ -42116,6 +42269,7 @@ "name": "moving_piston", "translation_key": "block.minecraft.moving_piston", "hardness": -1.0, + "blast_resistance": 0.0, "item_id": 0, "properties": [ { @@ -42290,6 +42444,7 @@ "name": "dandelion", "translation_key": "block.minecraft.dandelion", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 225, "loot_table": { "type": "minecraft:block", @@ -42333,6 +42488,7 @@ "name": "torchflower", "translation_key": "block.minecraft.torchflower", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 240, "loot_table": { "type": "minecraft:block", @@ -42376,6 +42532,7 @@ "name": "poppy", "translation_key": "block.minecraft.poppy", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 228, "loot_table": { "type": "minecraft:block", @@ -42419,6 +42576,7 @@ "name": "blue_orchid", "translation_key": "block.minecraft.blue_orchid", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 229, "loot_table": { "type": "minecraft:block", @@ -42462,6 +42620,7 @@ "name": "allium", "translation_key": "block.minecraft.allium", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 230, "loot_table": { "type": "minecraft:block", @@ -42505,6 +42664,7 @@ "name": "azure_bluet", "translation_key": "block.minecraft.azure_bluet", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 231, "loot_table": { "type": "minecraft:block", @@ -42548,6 +42708,7 @@ "name": "red_tulip", "translation_key": "block.minecraft.red_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 232, "loot_table": { "type": "minecraft:block", @@ -42591,6 +42752,7 @@ "name": "orange_tulip", "translation_key": "block.minecraft.orange_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 233, "loot_table": { "type": "minecraft:block", @@ -42634,6 +42796,7 @@ "name": "white_tulip", "translation_key": "block.minecraft.white_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 234, "loot_table": { "type": "minecraft:block", @@ -42677,6 +42840,7 @@ "name": "pink_tulip", "translation_key": "block.minecraft.pink_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 235, "loot_table": { "type": "minecraft:block", @@ -42720,6 +42884,7 @@ "name": "oxeye_daisy", "translation_key": "block.minecraft.oxeye_daisy", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 236, "loot_table": { "type": "minecraft:block", @@ -42763,6 +42928,7 @@ "name": "cornflower", "translation_key": "block.minecraft.cornflower", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 237, "loot_table": { "type": "minecraft:block", @@ -42806,6 +42972,7 @@ "name": "wither_rose", "translation_key": "block.minecraft.wither_rose", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 239, "loot_table": { "type": "minecraft:block", @@ -42849,6 +43016,7 @@ "name": "lily_of_the_valley", "translation_key": "block.minecraft.lily_of_the_valley", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 238, "loot_table": { "type": "minecraft:block", @@ -42892,6 +43060,7 @@ "name": "brown_mushroom", "translation_key": "block.minecraft.brown_mushroom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 243, "loot_table": { "type": "minecraft:block", @@ -42935,6 +43104,7 @@ "name": "red_mushroom", "translation_key": "block.minecraft.red_mushroom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 244, "loot_table": { "type": "minecraft:block", @@ -42978,6 +43148,7 @@ "name": "gold_block", "translation_key": "block.minecraft.gold_block", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 92, "loot_table": { "type": "minecraft:block", @@ -43024,6 +43195,7 @@ "name": "iron_block", "translation_key": "block.minecraft.iron_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 90, "loot_table": { "type": "minecraft:block", @@ -43070,6 +43242,7 @@ "name": "bricks", "translation_key": "block.minecraft.bricks", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 298, "loot_table": { "type": "minecraft:block", @@ -43116,6 +43289,7 @@ "name": "tnt", "translation_key": "block.minecraft.tnt", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 702, "loot_table": { "type": "minecraft:block", @@ -43193,6 +43367,7 @@ "name": "bookshelf", "translation_key": "block.minecraft.bookshelf", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 299, "loot_table": { "type": "minecraft:block", @@ -43270,6 +43445,7 @@ "name": "chiseled_bookshelf", "translation_key": "block.minecraft.chiseled_bookshelf", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 300, "loot_table": { "type": "minecraft:block", @@ -47206,6 +47382,7 @@ "name": "mossy_cobblestone", "translation_key": "block.minecraft.mossy_cobblestone", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 302, "loot_table": { "type": "minecraft:block", @@ -47252,6 +47429,7 @@ "name": "obsidian", "translation_key": "block.minecraft.obsidian", "hardness": 50.0, + "blast_resistance": 1200.0, "item_id": 303, "loot_table": { "type": "minecraft:block", @@ -47298,6 +47476,7 @@ "name": "torch", "translation_key": "block.minecraft.torch", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 304, "loot_table": { "type": "minecraft:block", @@ -47341,6 +47520,7 @@ "name": "wall_torch", "translation_key": "block.minecraft.torch", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 304, "loot_table": { "type": "minecraft:block", @@ -47427,6 +47607,7 @@ "name": "fire", "translation_key": "block.minecraft.fire", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -53131,6 +53312,7 @@ "name": "soul_fire", "translation_key": "block.minecraft.soul_fire", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -53157,6 +53339,7 @@ "name": "spawner", "translation_key": "block.minecraft.spawner", "hardness": 5.0, + "blast_resistance": 5.0, "item_id": 311, "loot_table": { "type": "minecraft:block", @@ -53186,6 +53369,7 @@ "name": "creaking_heart", "translation_key": "block.minecraft.creaking_heart", "hardness": 10.0, + "blast_resistance": 10.0, "item_id": 312, "loot_table": { "type": "minecraft:block", @@ -53470,6 +53654,7 @@ "name": "oak_stairs", "translation_key": "block.minecraft.oak_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 405, "loot_table": { "type": "minecraft:block", @@ -54784,6 +54969,7 @@ "name": "chest", "translation_key": "block.minecraft.chest", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 313, "loot_table": { "type": "minecraft:block", @@ -55210,6 +55396,7 @@ "name": "redstone_wire", "translation_key": "block.minecraft.redstone_wire", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 680, "loot_table": { "type": "minecraft:block", @@ -69552,6 +69739,7 @@ "name": "diamond_ore", "translation_key": "block.minecraft.diamond_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 78, "experience": { "experience": { @@ -69637,6 +69825,7 @@ "name": "deepslate_diamond_ore", "translation_key": "block.minecraft.deepslate_diamond_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 79, "experience": { "experience": { @@ -69722,6 +69911,7 @@ "name": "diamond_block", "translation_key": "block.minecraft.diamond_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 93, "loot_table": { "type": "minecraft:block", @@ -69768,6 +69958,7 @@ "name": "crafting_table", "translation_key": "block.minecraft.crafting_table", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 314, "loot_table": { "type": "minecraft:block", @@ -69814,6 +70005,7 @@ "name": "wheat", "translation_key": "block.minecraft.wheat", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 884, "loot_table": { "type": "minecraft:block", @@ -69996,6 +70188,7 @@ "name": "farmland", "translation_key": "block.minecraft.farmland", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 315, "loot_table": { "type": "minecraft:block", @@ -70154,6 +70347,7 @@ "name": "furnace", "translation_key": "block.minecraft.furnace", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 316, "loot_table": { "type": "minecraft:block", @@ -70332,6 +70526,7 @@ "name": "oak_sign", "translation_key": "block.minecraft.oak_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 917, "loot_table": { "type": "minecraft:block", @@ -70777,6 +70972,7 @@ "name": "spruce_sign", "translation_key": "block.minecraft.spruce_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 918, "loot_table": { "type": "minecraft:block", @@ -71222,6 +71418,7 @@ "name": "birch_sign", "translation_key": "block.minecraft.birch_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 919, "loot_table": { "type": "minecraft:block", @@ -71667,6 +71864,7 @@ "name": "acacia_sign", "translation_key": "block.minecraft.acacia_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 921, "loot_table": { "type": "minecraft:block", @@ -72112,6 +72310,7 @@ "name": "cherry_sign", "translation_key": "block.minecraft.cherry_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 922, "loot_table": { "type": "minecraft:block", @@ -72557,6 +72756,7 @@ "name": "jungle_sign", "translation_key": "block.minecraft.jungle_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 920, "loot_table": { "type": "minecraft:block", @@ -73002,6 +73202,7 @@ "name": "dark_oak_sign", "translation_key": "block.minecraft.dark_oak_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 923, "loot_table": { "type": "minecraft:block", @@ -73447,6 +73648,7 @@ "name": "pale_oak_sign", "translation_key": "block.minecraft.pale_oak_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 924, "loot_table": { "type": "minecraft:block", @@ -73892,6 +74094,7 @@ "name": "mangrove_sign", "translation_key": "block.minecraft.mangrove_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 925, "loot_table": { "type": "minecraft:block", @@ -74337,6 +74540,7 @@ "name": "bamboo_sign", "translation_key": "block.minecraft.bamboo_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 926, "loot_table": { "type": "minecraft:block", @@ -74782,6 +74986,7 @@ "name": "oak_door", "translation_key": "block.minecraft.oak_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 736, "loot_table": { "type": "minecraft:block", @@ -75693,6 +75898,7 @@ "name": "ladder", "translation_key": "block.minecraft.ladder", "hardness": 0.4, + "blast_resistance": 0.4, "item_id": 317, "loot_table": { "type": "minecraft:block", @@ -75846,6 +76052,7 @@ "name": "rail", "translation_key": "block.minecraft.rail", "hardness": 0.7, + "blast_resistance": 0.7, "item_id": 791, "loot_table": { "type": "minecraft:block", @@ -76121,6 +76328,7 @@ "name": "cobblestone_stairs", "translation_key": "block.minecraft.cobblestone_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 318, "loot_table": { "type": "minecraft:block", @@ -77435,6 +77643,7 @@ "name": "oak_wall_sign", "translation_key": "block.minecraft.oak_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 917, "loot_table": { "type": "minecraft:block", @@ -77580,6 +77789,7 @@ "name": "spruce_wall_sign", "translation_key": "block.minecraft.spruce_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 918, "loot_table": { "type": "minecraft:block", @@ -77725,6 +77935,7 @@ "name": "birch_wall_sign", "translation_key": "block.minecraft.birch_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 919, "loot_table": { "type": "minecraft:block", @@ -77870,6 +78081,7 @@ "name": "acacia_wall_sign", "translation_key": "block.minecraft.acacia_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 921, "loot_table": { "type": "minecraft:block", @@ -78015,6 +78227,7 @@ "name": "cherry_wall_sign", "translation_key": "block.minecraft.cherry_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 922, "loot_table": { "type": "minecraft:block", @@ -78160,6 +78373,7 @@ "name": "jungle_wall_sign", "translation_key": "block.minecraft.jungle_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 920, "loot_table": { "type": "minecraft:block", @@ -78305,6 +78519,7 @@ "name": "dark_oak_wall_sign", "translation_key": "block.minecraft.dark_oak_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 923, "loot_table": { "type": "minecraft:block", @@ -78450,6 +78665,7 @@ "name": "pale_oak_wall_sign", "translation_key": "block.minecraft.pale_oak_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 924, "loot_table": { "type": "minecraft:block", @@ -78595,6 +78811,7 @@ "name": "mangrove_wall_sign", "translation_key": "block.minecraft.mangrove_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 925, "loot_table": { "type": "minecraft:block", @@ -78740,6 +78957,7 @@ "name": "bamboo_wall_sign", "translation_key": "block.minecraft.bamboo_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 926, "loot_table": { "type": "minecraft:block", @@ -78885,6 +79103,7 @@ "name": "oak_hanging_sign", "translation_key": "block.minecraft.oak_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 929, "loot_table": { "type": "minecraft:block", @@ -79721,6 +79940,7 @@ "name": "spruce_hanging_sign", "translation_key": "block.minecraft.spruce_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 930, "loot_table": { "type": "minecraft:block", @@ -80557,6 +80777,7 @@ "name": "birch_hanging_sign", "translation_key": "block.minecraft.birch_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 931, "loot_table": { "type": "minecraft:block", @@ -81393,6 +81614,7 @@ "name": "acacia_hanging_sign", "translation_key": "block.minecraft.acacia_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 933, "loot_table": { "type": "minecraft:block", @@ -82229,6 +82451,7 @@ "name": "cherry_hanging_sign", "translation_key": "block.minecraft.cherry_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 934, "loot_table": { "type": "minecraft:block", @@ -83065,6 +83288,7 @@ "name": "jungle_hanging_sign", "translation_key": "block.minecraft.jungle_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 932, "loot_table": { "type": "minecraft:block", @@ -83901,6 +84125,7 @@ "name": "dark_oak_hanging_sign", "translation_key": "block.minecraft.dark_oak_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 935, "loot_table": { "type": "minecraft:block", @@ -84737,6 +84962,7 @@ "name": "pale_oak_hanging_sign", "translation_key": "block.minecraft.pale_oak_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 936, "loot_table": { "type": "minecraft:block", @@ -85573,6 +85799,7 @@ "name": "crimson_hanging_sign", "translation_key": "block.minecraft.crimson_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 939, "loot_table": { "type": "minecraft:block", @@ -86409,6 +86636,7 @@ "name": "warped_hanging_sign", "translation_key": "block.minecraft.warped_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 940, "loot_table": { "type": "minecraft:block", @@ -87245,6 +87473,7 @@ "name": "mangrove_hanging_sign", "translation_key": "block.minecraft.mangrove_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 937, "loot_table": { "type": "minecraft:block", @@ -88081,6 +88310,7 @@ "name": "bamboo_hanging_sign", "translation_key": "block.minecraft.bamboo_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 938, "loot_table": { "type": "minecraft:block", @@ -88917,6 +89147,7 @@ "name": "oak_wall_hanging_sign", "translation_key": "block.minecraft.oak_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 929, "loot_table": { "type": "minecraft:block", @@ -89078,6 +89309,7 @@ "name": "spruce_wall_hanging_sign", "translation_key": "block.minecraft.spruce_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 930, "loot_table": { "type": "minecraft:block", @@ -89239,6 +89471,7 @@ "name": "birch_wall_hanging_sign", "translation_key": "block.minecraft.birch_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 931, "loot_table": { "type": "minecraft:block", @@ -89400,6 +89633,7 @@ "name": "acacia_wall_hanging_sign", "translation_key": "block.minecraft.acacia_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 933, "loot_table": { "type": "minecraft:block", @@ -89561,6 +89795,7 @@ "name": "cherry_wall_hanging_sign", "translation_key": "block.minecraft.cherry_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 934, "loot_table": { "type": "minecraft:block", @@ -89722,6 +89957,7 @@ "name": "jungle_wall_hanging_sign", "translation_key": "block.minecraft.jungle_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 932, "loot_table": { "type": "minecraft:block", @@ -89883,6 +90119,7 @@ "name": "dark_oak_wall_hanging_sign", "translation_key": "block.minecraft.dark_oak_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 935, "loot_table": { "type": "minecraft:block", @@ -90044,6 +90281,7 @@ "name": "pale_oak_wall_hanging_sign", "translation_key": "block.minecraft.pale_oak_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 936, "loot_table": { "type": "minecraft:block", @@ -90205,6 +90443,7 @@ "name": "mangrove_wall_hanging_sign", "translation_key": "block.minecraft.mangrove_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 937, "loot_table": { "type": "minecraft:block", @@ -90366,6 +90605,7 @@ "name": "crimson_wall_hanging_sign", "translation_key": "block.minecraft.crimson_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 939, "loot_table": { "type": "minecraft:block", @@ -90527,6 +90767,7 @@ "name": "warped_wall_hanging_sign", "translation_key": "block.minecraft.warped_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 940, "loot_table": { "type": "minecraft:block", @@ -90688,6 +90929,7 @@ "name": "bamboo_wall_hanging_sign", "translation_key": "block.minecraft.bamboo_hanging_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 938, "loot_table": { "type": "minecraft:block", @@ -90849,6 +91091,7 @@ "name": "lever", "translation_key": "block.minecraft.lever", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 695, "loot_table": { "type": "minecraft:block", @@ -91170,6 +91413,7 @@ "name": "stone_pressure_plate", "translation_key": "block.minecraft.stone_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 719, "loot_table": { "type": "minecraft:block", @@ -91232,6 +91476,7 @@ "name": "iron_door", "translation_key": "block.minecraft.iron_door", "hardness": 5.0, + "blast_resistance": 5.0, "item_id": 735, "loot_table": { "type": "minecraft:block", @@ -92143,6 +92388,7 @@ "name": "oak_pressure_plate", "translation_key": "block.minecraft.oak_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 723, "loot_table": { "type": "minecraft:block", @@ -92205,6 +92451,7 @@ "name": "spruce_pressure_plate", "translation_key": "block.minecraft.spruce_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 724, "loot_table": { "type": "minecraft:block", @@ -92267,6 +92514,7 @@ "name": "birch_pressure_plate", "translation_key": "block.minecraft.birch_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 725, "loot_table": { "type": "minecraft:block", @@ -92329,6 +92577,7 @@ "name": "jungle_pressure_plate", "translation_key": "block.minecraft.jungle_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 726, "loot_table": { "type": "minecraft:block", @@ -92391,6 +92640,7 @@ "name": "acacia_pressure_plate", "translation_key": "block.minecraft.acacia_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 727, "loot_table": { "type": "minecraft:block", @@ -92453,6 +92703,7 @@ "name": "cherry_pressure_plate", "translation_key": "block.minecraft.cherry_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 728, "loot_table": { "type": "minecraft:block", @@ -92515,6 +92766,7 @@ "name": "dark_oak_pressure_plate", "translation_key": "block.minecraft.dark_oak_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 729, "loot_table": { "type": "minecraft:block", @@ -92577,6 +92829,7 @@ "name": "pale_oak_pressure_plate", "translation_key": "block.minecraft.pale_oak_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 730, "loot_table": { "type": "minecraft:block", @@ -92639,6 +92892,7 @@ "name": "mangrove_pressure_plate", "translation_key": "block.minecraft.mangrove_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 731, "loot_table": { "type": "minecraft:block", @@ -92701,6 +92955,7 @@ "name": "bamboo_pressure_plate", "translation_key": "block.minecraft.bamboo_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 732, "loot_table": { "type": "minecraft:block", @@ -92763,6 +93018,7 @@ "name": "redstone_ore", "translation_key": "block.minecraft.redstone_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 72, "loot_table": { "type": "minecraft:block", @@ -92874,6 +93130,7 @@ "name": "deepslate_redstone_ore", "translation_key": "block.minecraft.deepslate_redstone_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 73, "loot_table": { "type": "minecraft:block", @@ -92985,6 +93242,7 @@ "name": "redstone_torch", "translation_key": "block.minecraft.redstone_torch", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 681, "loot_table": { "type": "minecraft:block", @@ -93047,6 +93305,7 @@ "name": "redstone_wall_torch", "translation_key": "block.minecraft.redstone_torch", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 681, "loot_table": { "type": "minecraft:block", @@ -93184,6 +93443,7 @@ "name": "stone_button", "translation_key": "block.minecraft.stone_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 705, "loot_table": { "type": "minecraft:block", @@ -93505,6 +93765,7 @@ "name": "snow", "translation_key": "block.minecraft.snow", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 319, "loot_table": { "type": "minecraft:block", @@ -93998,6 +94259,7 @@ "name": "ice", "translation_key": "block.minecraft.ice", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 320, "loot_table": { "type": "minecraft:block", @@ -94055,6 +94317,7 @@ "name": "snow_block", "translation_key": "block.minecraft.snow_block", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 321, "loot_table": { "type": "minecraft:block", @@ -94132,6 +94395,7 @@ "name": "cactus", "translation_key": "block.minecraft.cactus", "hardness": 0.4, + "blast_resistance": 0.4, "item_id": 322, "loot_table": { "type": "minecraft:block", @@ -94410,6 +94674,7 @@ "name": "clay", "translation_key": "block.minecraft.clay", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 323, "loot_table": { "type": "minecraft:block", @@ -94487,6 +94752,7 @@ "name": "sugar_cane", "translation_key": "block.minecraft.sugar_cane", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 252, "loot_table": { "type": "minecraft:block", @@ -94717,6 +94983,7 @@ "name": "jukebox", "translation_key": "block.minecraft.jukebox", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 324, "loot_table": { "type": "minecraft:block", @@ -94787,6 +95054,7 @@ "name": "oak_fence", "translation_key": "block.minecraft.oak_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 325, "loot_table": { "type": "minecraft:block", @@ -95325,6 +95593,7 @@ "name": "netherrack", "translation_key": "block.minecraft.netherrack", "hardness": 0.4, + "blast_resistance": 0.4, "item_id": 340, "loot_table": { "type": "minecraft:block", @@ -95371,6 +95640,7 @@ "name": "soul_sand", "translation_key": "block.minecraft.soul_sand", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 341, "loot_table": { "type": "minecraft:block", @@ -95417,6 +95687,7 @@ "name": "soul_soil", "translation_key": "block.minecraft.soul_soil", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 342, "loot_table": { "type": "minecraft:block", @@ -95463,6 +95734,7 @@ "name": "basalt", "translation_key": "block.minecraft.basalt", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 343, "loot_table": { "type": "minecraft:block", @@ -95546,6 +95818,7 @@ "name": "polished_basalt", "translation_key": "block.minecraft.polished_basalt", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 344, "loot_table": { "type": "minecraft:block", @@ -95629,6 +95902,7 @@ "name": "soul_torch", "translation_key": "block.minecraft.soul_torch", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 346, "loot_table": { "type": "minecraft:block", @@ -95672,6 +95946,7 @@ "name": "soul_wall_torch", "translation_key": "block.minecraft.soul_torch", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 346, "loot_table": { "type": "minecraft:block", @@ -95758,6 +96033,7 @@ "name": "glowstone", "translation_key": "block.minecraft.glowstone", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 347, "loot_table": { "type": "minecraft:block", @@ -95854,6 +96130,7 @@ "name": "nether_portal", "translation_key": "block.minecraft.nether_portal", "hardness": -1.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -95899,6 +96176,7 @@ "name": "carved_pumpkin", "translation_key": "block.minecraft.carved_pumpkin", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 338, "loot_table": { "type": "minecraft:block", @@ -95997,6 +96275,7 @@ "name": "jack_o_lantern", "translation_key": "block.minecraft.jack_o_lantern", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 339, "loot_table": { "type": "minecraft:block", @@ -96095,6 +96374,7 @@ "name": "cake", "translation_key": "block.minecraft.cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 1012, "loot_table": { "type": "minecraft:block", @@ -96221,6 +96501,7 @@ "name": "repeater", "translation_key": "block.minecraft.repeater", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 683, "loot_table": { "type": "minecraft:block", @@ -97182,6 +97463,7 @@ "name": "white_stained_glass", "translation_key": "block.minecraft.white_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 494, "loot_table": { "type": "minecraft:block", @@ -97239,6 +97521,7 @@ "name": "orange_stained_glass", "translation_key": "block.minecraft.orange_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 495, "loot_table": { "type": "minecraft:block", @@ -97296,6 +97579,7 @@ "name": "magenta_stained_glass", "translation_key": "block.minecraft.magenta_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 496, "loot_table": { "type": "minecraft:block", @@ -97353,6 +97637,7 @@ "name": "light_blue_stained_glass", "translation_key": "block.minecraft.light_blue_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 497, "loot_table": { "type": "minecraft:block", @@ -97410,6 +97695,7 @@ "name": "yellow_stained_glass", "translation_key": "block.minecraft.yellow_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 498, "loot_table": { "type": "minecraft:block", @@ -97467,6 +97753,7 @@ "name": "lime_stained_glass", "translation_key": "block.minecraft.lime_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 499, "loot_table": { "type": "minecraft:block", @@ -97524,6 +97811,7 @@ "name": "pink_stained_glass", "translation_key": "block.minecraft.pink_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 500, "loot_table": { "type": "minecraft:block", @@ -97581,6 +97869,7 @@ "name": "gray_stained_glass", "translation_key": "block.minecraft.gray_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 501, "loot_table": { "type": "minecraft:block", @@ -97638,6 +97927,7 @@ "name": "light_gray_stained_glass", "translation_key": "block.minecraft.light_gray_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 502, "loot_table": { "type": "minecraft:block", @@ -97695,6 +97985,7 @@ "name": "cyan_stained_glass", "translation_key": "block.minecraft.cyan_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 503, "loot_table": { "type": "minecraft:block", @@ -97752,6 +98043,7 @@ "name": "purple_stained_glass", "translation_key": "block.minecraft.purple_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 504, "loot_table": { "type": "minecraft:block", @@ -97809,6 +98101,7 @@ "name": "blue_stained_glass", "translation_key": "block.minecraft.blue_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 505, "loot_table": { "type": "minecraft:block", @@ -97866,6 +98159,7 @@ "name": "brown_stained_glass", "translation_key": "block.minecraft.brown_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 506, "loot_table": { "type": "minecraft:block", @@ -97923,6 +98217,7 @@ "name": "green_stained_glass", "translation_key": "block.minecraft.green_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 507, "loot_table": { "type": "minecraft:block", @@ -97980,6 +98275,7 @@ "name": "red_stained_glass", "translation_key": "block.minecraft.red_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 508, "loot_table": { "type": "minecraft:block", @@ -98037,6 +98333,7 @@ "name": "black_stained_glass", "translation_key": "block.minecraft.black_stained_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 509, "loot_table": { "type": "minecraft:block", @@ -98094,6 +98391,7 @@ "name": "oak_trapdoor", "translation_key": "block.minecraft.oak_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 757, "loot_table": { "type": "minecraft:block", @@ -98996,6 +99294,7 @@ "name": "spruce_trapdoor", "translation_key": "block.minecraft.spruce_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 758, "loot_table": { "type": "minecraft:block", @@ -99898,6 +100197,7 @@ "name": "birch_trapdoor", "translation_key": "block.minecraft.birch_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 759, "loot_table": { "type": "minecraft:block", @@ -100800,6 +101100,7 @@ "name": "jungle_trapdoor", "translation_key": "block.minecraft.jungle_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 760, "loot_table": { "type": "minecraft:block", @@ -101702,6 +102003,7 @@ "name": "acacia_trapdoor", "translation_key": "block.minecraft.acacia_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 761, "loot_table": { "type": "minecraft:block", @@ -102604,6 +102906,7 @@ "name": "cherry_trapdoor", "translation_key": "block.minecraft.cherry_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 762, "loot_table": { "type": "minecraft:block", @@ -103506,6 +103809,7 @@ "name": "dark_oak_trapdoor", "translation_key": "block.minecraft.dark_oak_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 763, "loot_table": { "type": "minecraft:block", @@ -104408,6 +104712,7 @@ "name": "pale_oak_trapdoor", "translation_key": "block.minecraft.pale_oak_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 764, "loot_table": { "type": "minecraft:block", @@ -105310,6 +105615,7 @@ "name": "mangrove_trapdoor", "translation_key": "block.minecraft.mangrove_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 765, "loot_table": { "type": "minecraft:block", @@ -106212,6 +106518,7 @@ "name": "bamboo_trapdoor", "translation_key": "block.minecraft.bamboo_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 766, "loot_table": { "type": "minecraft:block", @@ -107114,6 +107421,7 @@ "name": "stone_bricks", "translation_key": "block.minecraft.stone_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 355, "loot_table": { "type": "minecraft:block", @@ -107160,6 +107468,7 @@ "name": "mossy_stone_bricks", "translation_key": "block.minecraft.mossy_stone_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 356, "loot_table": { "type": "minecraft:block", @@ -107206,6 +107515,7 @@ "name": "cracked_stone_bricks", "translation_key": "block.minecraft.cracked_stone_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 357, "loot_table": { "type": "minecraft:block", @@ -107252,6 +107562,7 @@ "name": "chiseled_stone_bricks", "translation_key": "block.minecraft.chiseled_stone_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 358, "loot_table": { "type": "minecraft:block", @@ -107298,6 +107609,7 @@ "name": "packed_mud", "translation_key": "block.minecraft.packed_mud", "hardness": 1.0, + "blast_resistance": 3.0, "item_id": 359, "loot_table": { "type": "minecraft:block", @@ -107344,6 +107656,7 @@ "name": "mud_bricks", "translation_key": "block.minecraft.mud_bricks", "hardness": 1.5, + "blast_resistance": 3.0, "item_id": 360, "loot_table": { "type": "minecraft:block", @@ -107390,6 +107703,7 @@ "name": "infested_stone", "translation_key": "block.minecraft.infested_stone", "hardness": 0.75, + "blast_resistance": 0.75, "item_id": 348, "loot_table": { "type": "minecraft:block", @@ -107448,6 +107762,7 @@ "name": "infested_cobblestone", "translation_key": "block.minecraft.infested_cobblestone", "hardness": 1.0, + "blast_resistance": 0.75, "item_id": 349, "loot_table": { "type": "minecraft:block", @@ -107506,6 +107821,7 @@ "name": "infested_stone_bricks", "translation_key": "block.minecraft.infested_stone_bricks", "hardness": 0.75, + "blast_resistance": 0.75, "item_id": 350, "loot_table": { "type": "minecraft:block", @@ -107564,6 +107880,7 @@ "name": "infested_mossy_stone_bricks", "translation_key": "block.minecraft.infested_mossy_stone_bricks", "hardness": 0.75, + "blast_resistance": 0.75, "item_id": 351, "loot_table": { "type": "minecraft:block", @@ -107622,6 +107939,7 @@ "name": "infested_cracked_stone_bricks", "translation_key": "block.minecraft.infested_cracked_stone_bricks", "hardness": 0.75, + "blast_resistance": 0.75, "item_id": 352, "loot_table": { "type": "minecraft:block", @@ -107680,6 +107998,7 @@ "name": "infested_chiseled_stone_bricks", "translation_key": "block.minecraft.infested_chiseled_stone_bricks", "hardness": 0.75, + "blast_resistance": 0.75, "item_id": 353, "loot_table": { "type": "minecraft:block", @@ -107738,6 +108057,7 @@ "name": "brown_mushroom_block", "translation_key": "block.minecraft.brown_mushroom_block", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 367, "loot_table": { "type": "minecraft:block", @@ -108750,6 +109070,7 @@ "name": "red_mushroom_block", "translation_key": "block.minecraft.red_mushroom_block", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 368, "loot_table": { "type": "minecraft:block", @@ -109762,6 +110083,7 @@ "name": "mushroom_stem", "translation_key": "block.minecraft.mushroom_stem", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 369, "loot_table": { "type": "minecraft:block", @@ -110745,6 +111067,7 @@ "name": "iron_bars", "translation_key": "block.minecraft.iron_bars", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 370, "loot_table": { "type": "minecraft:block", @@ -111251,6 +111574,7 @@ "name": "chain", "translation_key": "block.minecraft.chain", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 371, "loot_table": { "type": "minecraft:block", @@ -111377,6 +111701,7 @@ "name": "glass_pane", "translation_key": "block.minecraft.glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 372, "loot_table": { "type": "minecraft:block", @@ -111895,6 +112220,7 @@ "name": "pumpkin", "translation_key": "block.minecraft.pumpkin", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 337, "loot_table": { "type": "minecraft:block", @@ -111941,6 +112267,7 @@ "name": "melon", "translation_key": "block.minecraft.melon", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 373, "loot_table": { "type": "minecraft:block", @@ -112036,6 +112363,7 @@ "name": "attached_pumpkin_stem", "translation_key": "block.minecraft.attached_pumpkin_stem", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -112133,6 +112461,7 @@ "name": "attached_melon_stem", "translation_key": "block.minecraft.attached_melon_stem", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -112230,6 +112559,7 @@ "name": "pumpkin_stem", "translation_key": "block.minecraft.pumpkin_stem", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1035, "loot_table": { "type": "minecraft:block", @@ -112510,6 +112840,7 @@ "name": "melon_stem", "translation_key": "block.minecraft.melon_stem", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1036, "loot_table": { "type": "minecraft:block", @@ -112790,6 +113121,7 @@ "name": "vine", "translation_key": "block.minecraft.vine", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 374, "loot_table": { "type": "minecraft:block", @@ -113213,6 +113545,7 @@ "name": "glow_lichen", "translation_key": "block.minecraft.glow_lichen", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 375, "loot_table": { "type": "minecraft:block", @@ -114800,6 +115133,7 @@ "name": "resin_clump", "translation_key": "block.minecraft.resin_clump", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 376, "loot_table": { "type": "minecraft:block", @@ -116379,6 +116713,7 @@ "name": "oak_fence_gate", "translation_key": "block.minecraft.oak_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 777, "loot_table": { "type": "minecraft:block", @@ -116858,6 +117193,7 @@ "name": "brick_stairs", "translation_key": "block.minecraft.brick_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 383, "loot_table": { "type": "minecraft:block", @@ -118172,6 +118508,7 @@ "name": "stone_brick_stairs", "translation_key": "block.minecraft.stone_brick_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 384, "loot_table": { "type": "minecraft:block", @@ -119486,6 +119823,7 @@ "name": "mud_brick_stairs", "translation_key": "block.minecraft.mud_brick_stairs", "hardness": 1.5, + "blast_resistance": 3.0, "item_id": 385, "loot_table": { "type": "minecraft:block", @@ -120800,6 +121138,7 @@ "name": "mycelium", "translation_key": "block.minecraft.mycelium", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 386, "loot_table": { "type": "minecraft:block", @@ -120894,6 +121233,7 @@ "name": "lily_pad", "translation_key": "block.minecraft.lily_pad", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 387, "loot_table": { "type": "minecraft:block", @@ -120939,6 +121279,7 @@ "name": "resin_block", "translation_key": "block.minecraft.resin_block", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 377, "loot_table": { "type": "minecraft:block", @@ -120985,6 +121326,7 @@ "name": "resin_bricks", "translation_key": "block.minecraft.resin_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 378, "loot_table": { "type": "minecraft:block", @@ -121031,6 +121373,7 @@ "name": "resin_brick_stairs", "translation_key": "block.minecraft.resin_brick_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 379, "loot_table": { "type": "minecraft:block", @@ -122345,6 +122688,7 @@ "name": "resin_brick_slab", "translation_key": "block.minecraft.resin_brick_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 380, "loot_table": { "type": "minecraft:block", @@ -122477,6 +122821,7 @@ "name": "resin_brick_wall", "translation_key": "block.minecraft.resin_brick_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 381, "loot_table": { "type": "minecraft:block", @@ -127732,6 +128077,7 @@ "name": "chiseled_resin_bricks", "translation_key": "block.minecraft.chiseled_resin_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 382, "loot_table": { "type": "minecraft:block", @@ -127778,6 +128124,7 @@ "name": "nether_bricks", "translation_key": "block.minecraft.nether_bricks", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 388, "loot_table": { "type": "minecraft:block", @@ -127824,6 +128171,7 @@ "name": "nether_brick_fence", "translation_key": "block.minecraft.nether_brick_fence", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 391, "loot_table": { "type": "minecraft:block", @@ -128362,6 +128710,7 @@ "name": "nether_brick_stairs", "translation_key": "block.minecraft.nether_brick_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 392, "loot_table": { "type": "minecraft:block", @@ -129676,6 +130025,7 @@ "name": "nether_wart", "translation_key": "block.minecraft.nether_wart", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1046, "loot_table": { "type": "minecraft:block", @@ -129799,6 +130149,7 @@ "name": "enchanting_table", "translation_key": "block.minecraft.enchanting_table", "hardness": 5.0, + "blast_resistance": 1200.0, "item_id": 397, "loot_table": { "type": "minecraft:block", @@ -129855,6 +130206,7 @@ "name": "brewing_stand", "translation_key": "block.minecraft.brewing_stand", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 1053, "loot_table": { "type": "minecraft:block", @@ -130038,6 +130390,7 @@ "name": "cauldron", "translation_key": "block.minecraft.cauldron", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 1054, "loot_table": { "type": "minecraft:block", @@ -130097,6 +130450,7 @@ "name": "water_cauldron", "translation_key": "block.minecraft.water_cauldron", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 1054, "loot_table": { "type": "minecraft:block", @@ -130219,6 +130573,7 @@ "name": "lava_cauldron", "translation_key": "block.minecraft.lava_cauldron", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 1054, "loot_table": { "type": "minecraft:block", @@ -130278,6 +130633,7 @@ "name": "powder_snow_cauldron", "translation_key": "block.minecraft.powder_snow_cauldron", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 1054, "loot_table": { "type": "minecraft:block", @@ -130400,6 +130756,7 @@ "name": "end_portal", "translation_key": "block.minecraft.end_portal", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 0, "properties": [], "default_state_id": 8180, @@ -130423,6 +130780,7 @@ "name": "end_portal_frame", "translation_key": "block.minecraft.end_portal_frame", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 398, "properties": [ { @@ -130567,6 +130925,7 @@ "name": "end_stone", "translation_key": "block.minecraft.end_stone", "hardness": 3.0, + "blast_resistance": 9.0, "item_id": 399, "loot_table": { "type": "minecraft:block", @@ -130613,6 +130972,7 @@ "name": "dragon_egg", "translation_key": "block.minecraft.dragon_egg", "hardness": 3.0, + "blast_resistance": 9.0, "item_id": 401, "loot_table": { "type": "minecraft:block", @@ -130653,6 +131013,7 @@ "name": "redstone_lamp", "translation_key": "block.minecraft.redstone_lamp", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 703, "loot_table": { "type": "minecraft:block", @@ -130721,6 +131082,7 @@ "name": "cocoa", "translation_key": "block.minecraft.cocoa", "hardness": 0.2, + "blast_resistance": 3.0, "item_id": 992, "loot_table": { "type": "minecraft:block", @@ -130941,6 +131303,7 @@ "name": "sandstone_stairs", "translation_key": "block.minecraft.sandstone_stairs", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 402, "loot_table": { "type": "minecraft:block", @@ -132255,6 +132618,7 @@ "name": "emerald_ore", "translation_key": "block.minecraft.emerald_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 74, "experience": { "experience": { @@ -132340,6 +132704,7 @@ "name": "deepslate_emerald_ore", "translation_key": "block.minecraft.deepslate_emerald_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 75, "experience": { "experience": { @@ -132425,6 +132790,7 @@ "name": "ender_chest", "translation_key": "block.minecraft.ender_chest", "hardness": 22.5, + "blast_resistance": 600.0, "item_id": 403, "loot_table": { "type": "minecraft:block", @@ -132625,6 +132991,7 @@ "name": "tripwire_hook", "translation_key": "block.minecraft.tripwire_hook", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 700, "loot_table": { "type": "minecraft:block", @@ -132857,6 +133224,7 @@ "name": "tripwire", "translation_key": "block.minecraft.tripwire", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 881, "loot_table": { "type": "minecraft:block", @@ -134347,6 +134715,7 @@ "name": "emerald_block", "translation_key": "block.minecraft.emerald_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 404, "loot_table": { "type": "minecraft:block", @@ -134393,6 +134762,7 @@ "name": "spruce_stairs", "translation_key": "block.minecraft.spruce_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 406, "loot_table": { "type": "minecraft:block", @@ -135707,6 +136077,7 @@ "name": "birch_stairs", "translation_key": "block.minecraft.birch_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 407, "loot_table": { "type": "minecraft:block", @@ -137021,6 +137392,7 @@ "name": "jungle_stairs", "translation_key": "block.minecraft.jungle_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 408, "loot_table": { "type": "minecraft:block", @@ -138335,6 +138707,7 @@ "name": "command_block", "translation_key": "block.minecraft.command_block", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 418, "properties": [ { @@ -138545,6 +138918,7 @@ "name": "beacon", "translation_key": "block.minecraft.beacon", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 419, "loot_table": { "type": "minecraft:block", @@ -138595,6 +138969,7 @@ "name": "cobblestone_wall", "translation_key": "block.minecraft.cobblestone_wall", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 420, "loot_table": { "type": "minecraft:block", @@ -143850,6 +144225,7 @@ "name": "mossy_cobblestone_wall", "translation_key": "block.minecraft.mossy_cobblestone_wall", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 421, "loot_table": { "type": "minecraft:block", @@ -149105,6 +149481,7 @@ "name": "flower_pot", "translation_key": "block.minecraft.flower_pot", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1147, "loot_table": { "type": "minecraft:block", @@ -149150,6 +149527,7 @@ "name": "potted_torchflower", "translation_key": "block.minecraft.potted_torchflower", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149210,6 +149588,7 @@ "name": "potted_oak_sapling", "translation_key": "block.minecraft.potted_oak_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149270,6 +149649,7 @@ "name": "potted_spruce_sapling", "translation_key": "block.minecraft.potted_spruce_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149330,6 +149710,7 @@ "name": "potted_birch_sapling", "translation_key": "block.minecraft.potted_birch_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149390,6 +149771,7 @@ "name": "potted_jungle_sapling", "translation_key": "block.minecraft.potted_jungle_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149450,6 +149832,7 @@ "name": "potted_acacia_sapling", "translation_key": "block.minecraft.potted_acacia_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149510,6 +149893,7 @@ "name": "potted_cherry_sapling", "translation_key": "block.minecraft.potted_cherry_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149570,6 +149954,7 @@ "name": "potted_dark_oak_sapling", "translation_key": "block.minecraft.potted_dark_oak_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149630,6 +150015,7 @@ "name": "potted_pale_oak_sapling", "translation_key": "block.minecraft.potted_pale_oak_sapling", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149690,6 +150076,7 @@ "name": "potted_mangrove_propagule", "translation_key": "block.minecraft.potted_mangrove_propagule", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149750,6 +150137,7 @@ "name": "potted_fern", "translation_key": "block.minecraft.potted_fern", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149810,6 +150198,7 @@ "name": "potted_dandelion", "translation_key": "block.minecraft.potted_dandelion", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149870,6 +150259,7 @@ "name": "potted_poppy", "translation_key": "block.minecraft.potted_poppy", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149930,6 +150320,7 @@ "name": "potted_blue_orchid", "translation_key": "block.minecraft.potted_blue_orchid", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -149990,6 +150381,7 @@ "name": "potted_allium", "translation_key": "block.minecraft.potted_allium", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150050,6 +150442,7 @@ "name": "potted_azure_bluet", "translation_key": "block.minecraft.potted_azure_bluet", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150110,6 +150503,7 @@ "name": "potted_red_tulip", "translation_key": "block.minecraft.potted_red_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150170,6 +150564,7 @@ "name": "potted_orange_tulip", "translation_key": "block.minecraft.potted_orange_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150230,6 +150625,7 @@ "name": "potted_white_tulip", "translation_key": "block.minecraft.potted_white_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150290,6 +150686,7 @@ "name": "potted_pink_tulip", "translation_key": "block.minecraft.potted_pink_tulip", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150350,6 +150747,7 @@ "name": "potted_oxeye_daisy", "translation_key": "block.minecraft.potted_oxeye_daisy", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150410,6 +150808,7 @@ "name": "potted_cornflower", "translation_key": "block.minecraft.potted_cornflower", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150470,6 +150869,7 @@ "name": "potted_lily_of_the_valley", "translation_key": "block.minecraft.potted_lily_of_the_valley", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150530,6 +150930,7 @@ "name": "potted_wither_rose", "translation_key": "block.minecraft.potted_wither_rose", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150590,6 +150991,7 @@ "name": "potted_red_mushroom", "translation_key": "block.minecraft.potted_red_mushroom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150650,6 +151052,7 @@ "name": "potted_brown_mushroom", "translation_key": "block.minecraft.potted_brown_mushroom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150710,6 +151113,7 @@ "name": "potted_dead_bush", "translation_key": "block.minecraft.potted_dead_bush", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150770,6 +151174,7 @@ "name": "potted_cactus", "translation_key": "block.minecraft.potted_cactus", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -150830,6 +151235,7 @@ "name": "carrots", "translation_key": "block.minecraft.carrots", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1148, "loot_table": { "type": "minecraft:block", @@ -150994,6 +151400,7 @@ "name": "potatoes", "translation_key": "block.minecraft.potatoes", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1149, "loot_table": { "type": "minecraft:block", @@ -151183,6 +151590,7 @@ "name": "oak_button", "translation_key": "block.minecraft.oak_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 707, "loot_table": { "type": "minecraft:block", @@ -151504,6 +151912,7 @@ "name": "spruce_button", "translation_key": "block.minecraft.spruce_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 708, "loot_table": { "type": "minecraft:block", @@ -151825,6 +152234,7 @@ "name": "birch_button", "translation_key": "block.minecraft.birch_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 709, "loot_table": { "type": "minecraft:block", @@ -152146,6 +152556,7 @@ "name": "jungle_button", "translation_key": "block.minecraft.jungle_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 710, "loot_table": { "type": "minecraft:block", @@ -152467,6 +152878,7 @@ "name": "acacia_button", "translation_key": "block.minecraft.acacia_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 711, "loot_table": { "type": "minecraft:block", @@ -152788,6 +153200,7 @@ "name": "cherry_button", "translation_key": "block.minecraft.cherry_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 712, "loot_table": { "type": "minecraft:block", @@ -153109,6 +153522,7 @@ "name": "dark_oak_button", "translation_key": "block.minecraft.dark_oak_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 713, "loot_table": { "type": "minecraft:block", @@ -153430,6 +153844,7 @@ "name": "pale_oak_button", "translation_key": "block.minecraft.pale_oak_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 714, "loot_table": { "type": "minecraft:block", @@ -153751,6 +154166,7 @@ "name": "mangrove_button", "translation_key": "block.minecraft.mangrove_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 715, "loot_table": { "type": "minecraft:block", @@ -154072,6 +154488,7 @@ "name": "bamboo_button", "translation_key": "block.minecraft.bamboo_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 716, "loot_table": { "type": "minecraft:block", @@ -154393,6 +154810,7 @@ "name": "skeleton_skull", "translation_key": "block.minecraft.skeleton_skull", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1154, "loot_table": { "type": "minecraft:block", @@ -154929,6 +155347,7 @@ "name": "skeleton_wall_skull", "translation_key": "block.minecraft.skeleton_skull", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1154, "loot_table": { "type": "minecraft:block", @@ -155093,6 +155512,7 @@ "name": "wither_skeleton_skull", "translation_key": "block.minecraft.wither_skeleton_skull", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1155, "loot_table": { "type": "minecraft:block", @@ -155629,6 +156049,7 @@ "name": "wither_skeleton_wall_skull", "translation_key": "block.minecraft.wither_skeleton_skull", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1155, "loot_table": { "type": "minecraft:block", @@ -155793,6 +156214,7 @@ "name": "zombie_head", "translation_key": "block.minecraft.zombie_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1157, "loot_table": { "type": "minecraft:block", @@ -156329,6 +156751,7 @@ "name": "zombie_wall_head", "translation_key": "block.minecraft.zombie_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1157, "loot_table": { "type": "minecraft:block", @@ -156493,6 +156916,7 @@ "name": "player_head", "translation_key": "block.minecraft.player_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1156, "loot_table": { "type": "minecraft:block", @@ -157040,6 +157464,7 @@ "name": "player_wall_head", "translation_key": "block.minecraft.player_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1156, "loot_table": { "type": "minecraft:block", @@ -157215,6 +157640,7 @@ "name": "creeper_head", "translation_key": "block.minecraft.creeper_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1158, "loot_table": { "type": "minecraft:block", @@ -157751,6 +158177,7 @@ "name": "creeper_wall_head", "translation_key": "block.minecraft.creeper_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1158, "loot_table": { "type": "minecraft:block", @@ -157915,6 +158342,7 @@ "name": "dragon_head", "translation_key": "block.minecraft.dragon_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1159, "loot_table": { "type": "minecraft:block", @@ -158451,6 +158879,7 @@ "name": "dragon_wall_head", "translation_key": "block.minecraft.dragon_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1159, "loot_table": { "type": "minecraft:block", @@ -158615,6 +159044,7 @@ "name": "piglin_head", "translation_key": "block.minecraft.piglin_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1160, "loot_table": { "type": "minecraft:block", @@ -159151,6 +159581,7 @@ "name": "piglin_wall_head", "translation_key": "block.minecraft.piglin_head", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1160, "loot_table": { "type": "minecraft:block", @@ -159315,6 +159746,7 @@ "name": "anvil", "translation_key": "block.minecraft.anvil", "hardness": 5.0, + "blast_resistance": 1200.0, "item_id": 442, "loot_table": { "type": "minecraft:block", @@ -159437,6 +159869,7 @@ "name": "chipped_anvil", "translation_key": "block.minecraft.chipped_anvil", "hardness": 5.0, + "blast_resistance": 1200.0, "item_id": 443, "loot_table": { "type": "minecraft:block", @@ -159559,6 +159992,7 @@ "name": "damaged_anvil", "translation_key": "block.minecraft.damaged_anvil", "hardness": 5.0, + "blast_resistance": 1200.0, "item_id": 444, "loot_table": { "type": "minecraft:block", @@ -159681,6 +160115,7 @@ "name": "trapped_chest", "translation_key": "block.minecraft.trapped_chest", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 701, "loot_table": { "type": "minecraft:block", @@ -160107,6 +160542,7 @@ "name": "light_weighted_pressure_plate", "translation_key": "block.minecraft.light_weighted_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 721, "loot_table": { "type": "minecraft:block", @@ -160337,6 +160773,7 @@ "name": "heavy_weighted_pressure_plate", "translation_key": "block.minecraft.heavy_weighted_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 722, "loot_table": { "type": "minecraft:block", @@ -160567,6 +161004,7 @@ "name": "comparator", "translation_key": "block.minecraft.comparator", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 684, "loot_table": { "type": "minecraft:block", @@ -160863,6 +161301,7 @@ "name": "daylight_detector", "translation_key": "block.minecraft.daylight_detector", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 697, "loot_table": { "type": "minecraft:block", @@ -161404,6 +161843,7 @@ "name": "redstone_block", "translation_key": "block.minecraft.redstone_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 682, "loot_table": { "type": "minecraft:block", @@ -161450,6 +161890,7 @@ "name": "nether_quartz_ore", "translation_key": "block.minecraft.nether_quartz_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 81, "experience": { "experience": { @@ -161535,6 +161976,7 @@ "name": "hopper", "translation_key": "block.minecraft.hopper", "hardness": 3.0, + "blast_resistance": 4.8, "item_id": 690, "loot_table": { "type": "minecraft:block", @@ -161834,6 +162276,7 @@ "name": "quartz_block", "translation_key": "block.minecraft.quartz_block", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 446, "loot_table": { "type": "minecraft:block", @@ -161880,6 +162323,7 @@ "name": "chiseled_quartz_block", "translation_key": "block.minecraft.chiseled_quartz_block", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 445, "loot_table": { "type": "minecraft:block", @@ -161926,6 +162370,7 @@ "name": "quartz_pillar", "translation_key": "block.minecraft.quartz_pillar", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 448, "loot_table": { "type": "minecraft:block", @@ -162009,6 +162454,7 @@ "name": "quartz_stairs", "translation_key": "block.minecraft.quartz_stairs", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 449, "loot_table": { "type": "minecraft:block", @@ -163323,6 +163769,7 @@ "name": "activator_rail", "translation_key": "block.minecraft.activator_rail", "hardness": 0.7, + "blast_resistance": 0.7, "item_id": 792, "loot_table": { "type": "minecraft:block", @@ -163645,6 +164092,7 @@ "name": "dropper", "translation_key": "block.minecraft.dropper", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 692, "loot_table": { "type": "minecraft:block", @@ -163885,6 +164333,7 @@ "name": "white_terracotta", "translation_key": "block.minecraft.white_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 450, "loot_table": { "type": "minecraft:block", @@ -163931,6 +164380,7 @@ "name": "orange_terracotta", "translation_key": "block.minecraft.orange_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 451, "loot_table": { "type": "minecraft:block", @@ -163977,6 +164427,7 @@ "name": "magenta_terracotta", "translation_key": "block.minecraft.magenta_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 452, "loot_table": { "type": "minecraft:block", @@ -164023,6 +164474,7 @@ "name": "light_blue_terracotta", "translation_key": "block.minecraft.light_blue_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 453, "loot_table": { "type": "minecraft:block", @@ -164069,6 +164521,7 @@ "name": "yellow_terracotta", "translation_key": "block.minecraft.yellow_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 454, "loot_table": { "type": "minecraft:block", @@ -164115,6 +164568,7 @@ "name": "lime_terracotta", "translation_key": "block.minecraft.lime_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 455, "loot_table": { "type": "minecraft:block", @@ -164161,6 +164615,7 @@ "name": "pink_terracotta", "translation_key": "block.minecraft.pink_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 456, "loot_table": { "type": "minecraft:block", @@ -164207,6 +164662,7 @@ "name": "gray_terracotta", "translation_key": "block.minecraft.gray_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 457, "loot_table": { "type": "minecraft:block", @@ -164253,6 +164709,7 @@ "name": "light_gray_terracotta", "translation_key": "block.minecraft.light_gray_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 458, "loot_table": { "type": "minecraft:block", @@ -164299,6 +164756,7 @@ "name": "cyan_terracotta", "translation_key": "block.minecraft.cyan_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 459, "loot_table": { "type": "minecraft:block", @@ -164345,6 +164803,7 @@ "name": "purple_terracotta", "translation_key": "block.minecraft.purple_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 460, "loot_table": { "type": "minecraft:block", @@ -164391,6 +164850,7 @@ "name": "blue_terracotta", "translation_key": "block.minecraft.blue_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 461, "loot_table": { "type": "minecraft:block", @@ -164437,6 +164897,7 @@ "name": "brown_terracotta", "translation_key": "block.minecraft.brown_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 462, "loot_table": { "type": "minecraft:block", @@ -164483,6 +164944,7 @@ "name": "green_terracotta", "translation_key": "block.minecraft.green_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 463, "loot_table": { "type": "minecraft:block", @@ -164529,6 +164991,7 @@ "name": "red_terracotta", "translation_key": "block.minecraft.red_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 464, "loot_table": { "type": "minecraft:block", @@ -164575,6 +165038,7 @@ "name": "black_terracotta", "translation_key": "block.minecraft.black_terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 465, "loot_table": { "type": "minecraft:block", @@ -164621,6 +165085,7 @@ "name": "white_stained_glass_pane", "translation_key": "block.minecraft.white_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 510, "loot_table": { "type": "minecraft:block", @@ -165139,6 +165604,7 @@ "name": "orange_stained_glass_pane", "translation_key": "block.minecraft.orange_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 511, "loot_table": { "type": "minecraft:block", @@ -165657,6 +166123,7 @@ "name": "magenta_stained_glass_pane", "translation_key": "block.minecraft.magenta_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 512, "loot_table": { "type": "minecraft:block", @@ -166175,6 +166642,7 @@ "name": "light_blue_stained_glass_pane", "translation_key": "block.minecraft.light_blue_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 513, "loot_table": { "type": "minecraft:block", @@ -166693,6 +167161,7 @@ "name": "yellow_stained_glass_pane", "translation_key": "block.minecraft.yellow_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 514, "loot_table": { "type": "minecraft:block", @@ -167211,6 +167680,7 @@ "name": "lime_stained_glass_pane", "translation_key": "block.minecraft.lime_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 515, "loot_table": { "type": "minecraft:block", @@ -167729,6 +168199,7 @@ "name": "pink_stained_glass_pane", "translation_key": "block.minecraft.pink_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 516, "loot_table": { "type": "minecraft:block", @@ -168247,6 +168718,7 @@ "name": "gray_stained_glass_pane", "translation_key": "block.minecraft.gray_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 517, "loot_table": { "type": "minecraft:block", @@ -168765,6 +169237,7 @@ "name": "light_gray_stained_glass_pane", "translation_key": "block.minecraft.light_gray_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 518, "loot_table": { "type": "minecraft:block", @@ -169283,6 +169756,7 @@ "name": "cyan_stained_glass_pane", "translation_key": "block.minecraft.cyan_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 519, "loot_table": { "type": "minecraft:block", @@ -169801,6 +170275,7 @@ "name": "purple_stained_glass_pane", "translation_key": "block.minecraft.purple_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 520, "loot_table": { "type": "minecraft:block", @@ -170319,6 +170794,7 @@ "name": "blue_stained_glass_pane", "translation_key": "block.minecraft.blue_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 521, "loot_table": { "type": "minecraft:block", @@ -170837,6 +171313,7 @@ "name": "brown_stained_glass_pane", "translation_key": "block.minecraft.brown_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 522, "loot_table": { "type": "minecraft:block", @@ -171355,6 +171832,7 @@ "name": "green_stained_glass_pane", "translation_key": "block.minecraft.green_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 523, "loot_table": { "type": "minecraft:block", @@ -171873,6 +172351,7 @@ "name": "red_stained_glass_pane", "translation_key": "block.minecraft.red_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 524, "loot_table": { "type": "minecraft:block", @@ -172391,6 +172870,7 @@ "name": "black_stained_glass_pane", "translation_key": "block.minecraft.black_stained_glass_pane", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 525, "loot_table": { "type": "minecraft:block", @@ -172909,6 +173389,7 @@ "name": "acacia_stairs", "translation_key": "block.minecraft.acacia_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 409, "loot_table": { "type": "minecraft:block", @@ -174223,6 +174704,7 @@ "name": "cherry_stairs", "translation_key": "block.minecraft.cherry_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 410, "loot_table": { "type": "minecraft:block", @@ -175537,6 +176019,7 @@ "name": "dark_oak_stairs", "translation_key": "block.minecraft.dark_oak_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 411, "loot_table": { "type": "minecraft:block", @@ -176851,6 +177334,7 @@ "name": "pale_oak_stairs", "translation_key": "block.minecraft.pale_oak_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 412, "loot_table": { "type": "minecraft:block", @@ -178165,6 +178649,7 @@ "name": "mangrove_stairs", "translation_key": "block.minecraft.mangrove_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 413, "loot_table": { "type": "minecraft:block", @@ -179479,6 +179964,7 @@ "name": "bamboo_stairs", "translation_key": "block.minecraft.bamboo_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 414, "loot_table": { "type": "minecraft:block", @@ -180793,6 +181279,7 @@ "name": "bamboo_mosaic_stairs", "translation_key": "block.minecraft.bamboo_mosaic_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 415, "loot_table": { "type": "minecraft:block", @@ -182107,6 +182594,7 @@ "name": "slime_block", "translation_key": "block.minecraft.slime_block", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 687, "loot_table": { "type": "minecraft:block", @@ -182152,6 +182640,7 @@ "name": "barrier", "translation_key": "block.minecraft.barrier", "hardness": -1.0, + "blast_resistance": 3600000.8, "item_id": 466, "properties": [ { @@ -182197,6 +182686,7 @@ "name": "light", "translation_key": "block.minecraft.light", "hardness": -1.0, + "blast_resistance": 3600000.8, "item_id": 467, "properties": [ { @@ -182589,6 +183079,7 @@ "name": "iron_trapdoor", "translation_key": "block.minecraft.iron_trapdoor", "hardness": 5.0, + "blast_resistance": 5.0, "item_id": 756, "loot_table": { "type": "minecraft:block", @@ -183491,6 +183982,7 @@ "name": "prismarine", "translation_key": "block.minecraft.prismarine", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 526, "loot_table": { "type": "minecraft:block", @@ -183537,6 +184029,7 @@ "name": "prismarine_bricks", "translation_key": "block.minecraft.prismarine_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 527, "loot_table": { "type": "minecraft:block", @@ -183583,6 +184076,7 @@ "name": "dark_prismarine", "translation_key": "block.minecraft.dark_prismarine", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 528, "loot_table": { "type": "minecraft:block", @@ -183629,6 +184123,7 @@ "name": "prismarine_stairs", "translation_key": "block.minecraft.prismarine_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 529, "loot_table": { "type": "minecraft:block", @@ -184943,6 +185438,7 @@ "name": "prismarine_brick_stairs", "translation_key": "block.minecraft.prismarine_brick_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 530, "loot_table": { "type": "minecraft:block", @@ -186257,6 +186753,7 @@ "name": "dark_prismarine_stairs", "translation_key": "block.minecraft.dark_prismarine_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 531, "loot_table": { "type": "minecraft:block", @@ -187571,6 +188068,7 @@ "name": "prismarine_slab", "translation_key": "block.minecraft.prismarine_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 291, "loot_table": { "type": "minecraft:block", @@ -187717,6 +188215,7 @@ "name": "prismarine_brick_slab", "translation_key": "block.minecraft.prismarine_brick_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 292, "loot_table": { "type": "minecraft:block", @@ -187863,6 +188362,7 @@ "name": "dark_prismarine_slab", "translation_key": "block.minecraft.dark_prismarine_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 293, "loot_table": { "type": "minecraft:block", @@ -188009,6 +188509,7 @@ "name": "sea_lantern", "translation_key": "block.minecraft.sea_lantern", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 532, "loot_table": { "type": "minecraft:block", @@ -188105,6 +188606,7 @@ "name": "hay_block", "translation_key": "block.minecraft.hay_block", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 468, "loot_table": { "type": "minecraft:block", @@ -188188,6 +188690,7 @@ "name": "white_carpet", "translation_key": "block.minecraft.white_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 469, "loot_table": { "type": "minecraft:block", @@ -188234,6 +188737,7 @@ "name": "orange_carpet", "translation_key": "block.minecraft.orange_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 470, "loot_table": { "type": "minecraft:block", @@ -188280,6 +188784,7 @@ "name": "magenta_carpet", "translation_key": "block.minecraft.magenta_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 471, "loot_table": { "type": "minecraft:block", @@ -188326,6 +188831,7 @@ "name": "light_blue_carpet", "translation_key": "block.minecraft.light_blue_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 472, "loot_table": { "type": "minecraft:block", @@ -188372,6 +188878,7 @@ "name": "yellow_carpet", "translation_key": "block.minecraft.yellow_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 473, "loot_table": { "type": "minecraft:block", @@ -188418,6 +188925,7 @@ "name": "lime_carpet", "translation_key": "block.minecraft.lime_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 474, "loot_table": { "type": "minecraft:block", @@ -188464,6 +188972,7 @@ "name": "pink_carpet", "translation_key": "block.minecraft.pink_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 475, "loot_table": { "type": "minecraft:block", @@ -188510,6 +189019,7 @@ "name": "gray_carpet", "translation_key": "block.minecraft.gray_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 476, "loot_table": { "type": "minecraft:block", @@ -188556,6 +189066,7 @@ "name": "light_gray_carpet", "translation_key": "block.minecraft.light_gray_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 477, "loot_table": { "type": "minecraft:block", @@ -188602,6 +189113,7 @@ "name": "cyan_carpet", "translation_key": "block.minecraft.cyan_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 478, "loot_table": { "type": "minecraft:block", @@ -188648,6 +189160,7 @@ "name": "purple_carpet", "translation_key": "block.minecraft.purple_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 479, "loot_table": { "type": "minecraft:block", @@ -188694,6 +189207,7 @@ "name": "blue_carpet", "translation_key": "block.minecraft.blue_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 480, "loot_table": { "type": "minecraft:block", @@ -188740,6 +189254,7 @@ "name": "brown_carpet", "translation_key": "block.minecraft.brown_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 481, "loot_table": { "type": "minecraft:block", @@ -188786,6 +189301,7 @@ "name": "green_carpet", "translation_key": "block.minecraft.green_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 482, "loot_table": { "type": "minecraft:block", @@ -188832,6 +189348,7 @@ "name": "red_carpet", "translation_key": "block.minecraft.red_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 483, "loot_table": { "type": "minecraft:block", @@ -188878,6 +189395,7 @@ "name": "black_carpet", "translation_key": "block.minecraft.black_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 484, "loot_table": { "type": "minecraft:block", @@ -188924,6 +189442,7 @@ "name": "terracotta", "translation_key": "block.minecraft.terracotta", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 485, "loot_table": { "type": "minecraft:block", @@ -188970,6 +189489,7 @@ "name": "coal_block", "translation_key": "block.minecraft.coal_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 83, "loot_table": { "type": "minecraft:block", @@ -189016,6 +189536,7 @@ "name": "packed_ice", "translation_key": "block.minecraft.packed_ice", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 486, "loot_table": { "type": "minecraft:block", @@ -189074,6 +189595,7 @@ "name": "sunflower", "translation_key": "block.minecraft.sunflower", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 488, "loot_table": { "type": "minecraft:block", @@ -189145,6 +189667,7 @@ "name": "lilac", "translation_key": "block.minecraft.lilac", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 489, "loot_table": { "type": "minecraft:block", @@ -189216,6 +189739,7 @@ "name": "rose_bush", "translation_key": "block.minecraft.rose_bush", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 490, "loot_table": { "type": "minecraft:block", @@ -189287,6 +189811,7 @@ "name": "peony", "translation_key": "block.minecraft.peony", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 491, "loot_table": { "type": "minecraft:block", @@ -189358,6 +189883,7 @@ "name": "tall_grass", "translation_key": "block.minecraft.tall_grass", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 492, "loot_table": { "type": "minecraft:block", @@ -189533,6 +190059,7 @@ "name": "large_fern", "translation_key": "block.minecraft.large_fern", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 493, "loot_table": { "type": "minecraft:block", @@ -189708,6 +190235,7 @@ "name": "white_banner", "translation_key": "block.minecraft.white_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1185, "loot_table": { "type": "minecraft:block", @@ -189967,6 +190495,7 @@ "name": "orange_banner", "translation_key": "block.minecraft.orange_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1186, "loot_table": { "type": "minecraft:block", @@ -190226,6 +190755,7 @@ "name": "magenta_banner", "translation_key": "block.minecraft.magenta_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1187, "loot_table": { "type": "minecraft:block", @@ -190485,6 +191015,7 @@ "name": "light_blue_banner", "translation_key": "block.minecraft.light_blue_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1188, "loot_table": { "type": "minecraft:block", @@ -190744,6 +191275,7 @@ "name": "yellow_banner", "translation_key": "block.minecraft.yellow_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1189, "loot_table": { "type": "minecraft:block", @@ -191003,6 +191535,7 @@ "name": "lime_banner", "translation_key": "block.minecraft.lime_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1190, "loot_table": { "type": "minecraft:block", @@ -191262,6 +191795,7 @@ "name": "pink_banner", "translation_key": "block.minecraft.pink_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1191, "loot_table": { "type": "minecraft:block", @@ -191521,6 +192055,7 @@ "name": "gray_banner", "translation_key": "block.minecraft.gray_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1192, "loot_table": { "type": "minecraft:block", @@ -191780,6 +192315,7 @@ "name": "light_gray_banner", "translation_key": "block.minecraft.light_gray_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1193, "loot_table": { "type": "minecraft:block", @@ -192039,6 +192575,7 @@ "name": "cyan_banner", "translation_key": "block.minecraft.cyan_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1194, "loot_table": { "type": "minecraft:block", @@ -192298,6 +192835,7 @@ "name": "purple_banner", "translation_key": "block.minecraft.purple_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1195, "loot_table": { "type": "minecraft:block", @@ -192557,6 +193095,7 @@ "name": "blue_banner", "translation_key": "block.minecraft.blue_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1196, "loot_table": { "type": "minecraft:block", @@ -192816,6 +193355,7 @@ "name": "brown_banner", "translation_key": "block.minecraft.brown_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1197, "loot_table": { "type": "minecraft:block", @@ -193075,6 +193615,7 @@ "name": "green_banner", "translation_key": "block.minecraft.green_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1198, "loot_table": { "type": "minecraft:block", @@ -193334,6 +193875,7 @@ "name": "red_banner", "translation_key": "block.minecraft.red_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1199, "loot_table": { "type": "minecraft:block", @@ -193593,6 +194135,7 @@ "name": "black_banner", "translation_key": "block.minecraft.black_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1200, "loot_table": { "type": "minecraft:block", @@ -193852,6 +194395,7 @@ "name": "white_wall_banner", "translation_key": "block.minecraft.white_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1185, "loot_table": { "type": "minecraft:block", @@ -193955,6 +194499,7 @@ "name": "orange_wall_banner", "translation_key": "block.minecraft.orange_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1186, "loot_table": { "type": "minecraft:block", @@ -194058,6 +194603,7 @@ "name": "magenta_wall_banner", "translation_key": "block.minecraft.magenta_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1187, "loot_table": { "type": "minecraft:block", @@ -194161,6 +194707,7 @@ "name": "light_blue_wall_banner", "translation_key": "block.minecraft.light_blue_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1188, "loot_table": { "type": "minecraft:block", @@ -194264,6 +194811,7 @@ "name": "yellow_wall_banner", "translation_key": "block.minecraft.yellow_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1189, "loot_table": { "type": "minecraft:block", @@ -194367,6 +194915,7 @@ "name": "lime_wall_banner", "translation_key": "block.minecraft.lime_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1190, "loot_table": { "type": "minecraft:block", @@ -194470,6 +195019,7 @@ "name": "pink_wall_banner", "translation_key": "block.minecraft.pink_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1191, "loot_table": { "type": "minecraft:block", @@ -194573,6 +195123,7 @@ "name": "gray_wall_banner", "translation_key": "block.minecraft.gray_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1192, "loot_table": { "type": "minecraft:block", @@ -194676,6 +195227,7 @@ "name": "light_gray_wall_banner", "translation_key": "block.minecraft.light_gray_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1193, "loot_table": { "type": "minecraft:block", @@ -194779,6 +195331,7 @@ "name": "cyan_wall_banner", "translation_key": "block.minecraft.cyan_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1194, "loot_table": { "type": "minecraft:block", @@ -194882,6 +195435,7 @@ "name": "purple_wall_banner", "translation_key": "block.minecraft.purple_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1195, "loot_table": { "type": "minecraft:block", @@ -194985,6 +195539,7 @@ "name": "blue_wall_banner", "translation_key": "block.minecraft.blue_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1196, "loot_table": { "type": "minecraft:block", @@ -195088,6 +195643,7 @@ "name": "brown_wall_banner", "translation_key": "block.minecraft.brown_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1197, "loot_table": { "type": "minecraft:block", @@ -195191,6 +195747,7 @@ "name": "green_wall_banner", "translation_key": "block.minecraft.green_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1198, "loot_table": { "type": "minecraft:block", @@ -195294,6 +195851,7 @@ "name": "red_wall_banner", "translation_key": "block.minecraft.red_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1199, "loot_table": { "type": "minecraft:block", @@ -195397,6 +195955,7 @@ "name": "black_wall_banner", "translation_key": "block.minecraft.black_banner", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1200, "loot_table": { "type": "minecraft:block", @@ -195500,6 +196059,7 @@ "name": "red_sandstone", "translation_key": "block.minecraft.red_sandstone", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 533, "loot_table": { "type": "minecraft:block", @@ -195546,6 +196106,7 @@ "name": "chiseled_red_sandstone", "translation_key": "block.minecraft.chiseled_red_sandstone", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 534, "loot_table": { "type": "minecraft:block", @@ -195592,6 +196153,7 @@ "name": "cut_red_sandstone", "translation_key": "block.minecraft.cut_red_sandstone", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 535, "loot_table": { "type": "minecraft:block", @@ -195638,6 +196200,7 @@ "name": "red_sandstone_stairs", "translation_key": "block.minecraft.red_sandstone_stairs", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 536, "loot_table": { "type": "minecraft:block", @@ -196952,6 +197515,7 @@ "name": "oak_slab", "translation_key": "block.minecraft.oak_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 264, "loot_table": { "type": "minecraft:block", @@ -197098,6 +197662,7 @@ "name": "spruce_slab", "translation_key": "block.minecraft.spruce_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 265, "loot_table": { "type": "minecraft:block", @@ -197244,6 +197809,7 @@ "name": "birch_slab", "translation_key": "block.minecraft.birch_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 266, "loot_table": { "type": "minecraft:block", @@ -197390,6 +197956,7 @@ "name": "jungle_slab", "translation_key": "block.minecraft.jungle_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 267, "loot_table": { "type": "minecraft:block", @@ -197536,6 +198103,7 @@ "name": "acacia_slab", "translation_key": "block.minecraft.acacia_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 268, "loot_table": { "type": "minecraft:block", @@ -197682,6 +198250,7 @@ "name": "cherry_slab", "translation_key": "block.minecraft.cherry_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 269, "loot_table": { "type": "minecraft:block", @@ -197828,6 +198397,7 @@ "name": "dark_oak_slab", "translation_key": "block.minecraft.dark_oak_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 270, "loot_table": { "type": "minecraft:block", @@ -197974,6 +198544,7 @@ "name": "pale_oak_slab", "translation_key": "block.minecraft.pale_oak_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 271, "loot_table": { "type": "minecraft:block", @@ -198120,6 +198691,7 @@ "name": "mangrove_slab", "translation_key": "block.minecraft.mangrove_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 272, "loot_table": { "type": "minecraft:block", @@ -198266,6 +198838,7 @@ "name": "bamboo_slab", "translation_key": "block.minecraft.bamboo_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 273, "loot_table": { "type": "minecraft:block", @@ -198412,6 +198985,7 @@ "name": "bamboo_mosaic_slab", "translation_key": "block.minecraft.bamboo_mosaic_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 274, "loot_table": { "type": "minecraft:block", @@ -198558,6 +199132,7 @@ "name": "stone_slab", "translation_key": "block.minecraft.stone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 277, "loot_table": { "type": "minecraft:block", @@ -198704,6 +199279,7 @@ "name": "smooth_stone_slab", "translation_key": "block.minecraft.smooth_stone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 278, "loot_table": { "type": "minecraft:block", @@ -198850,6 +199426,7 @@ "name": "sandstone_slab", "translation_key": "block.minecraft.sandstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 279, "loot_table": { "type": "minecraft:block", @@ -198996,6 +199573,7 @@ "name": "cut_sandstone_slab", "translation_key": "block.minecraft.cut_sandstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 280, "loot_table": { "type": "minecraft:block", @@ -199142,6 +199720,7 @@ "name": "petrified_oak_slab", "translation_key": "block.minecraft.petrified_oak_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 281, "loot_table": { "type": "minecraft:block", @@ -199288,6 +199867,7 @@ "name": "cobblestone_slab", "translation_key": "block.minecraft.cobblestone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 282, "loot_table": { "type": "minecraft:block", @@ -199434,6 +200014,7 @@ "name": "brick_slab", "translation_key": "block.minecraft.brick_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 283, "loot_table": { "type": "minecraft:block", @@ -199580,6 +200161,7 @@ "name": "stone_brick_slab", "translation_key": "block.minecraft.stone_brick_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 284, "loot_table": { "type": "minecraft:block", @@ -199726,6 +200308,7 @@ "name": "mud_brick_slab", "translation_key": "block.minecraft.mud_brick_slab", "hardness": 1.5, + "blast_resistance": 3.0, "item_id": 285, "loot_table": { "type": "minecraft:block", @@ -199872,6 +200455,7 @@ "name": "nether_brick_slab", "translation_key": "block.minecraft.nether_brick_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 286, "loot_table": { "type": "minecraft:block", @@ -200018,6 +200602,7 @@ "name": "quartz_slab", "translation_key": "block.minecraft.quartz_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 287, "loot_table": { "type": "minecraft:block", @@ -200164,6 +200749,7 @@ "name": "red_sandstone_slab", "translation_key": "block.minecraft.red_sandstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 288, "loot_table": { "type": "minecraft:block", @@ -200310,6 +200896,7 @@ "name": "cut_red_sandstone_slab", "translation_key": "block.minecraft.cut_red_sandstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 289, "loot_table": { "type": "minecraft:block", @@ -200456,6 +201043,7 @@ "name": "purpur_slab", "translation_key": "block.minecraft.purpur_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 290, "loot_table": { "type": "minecraft:block", @@ -200602,6 +201190,7 @@ "name": "smooth_stone", "translation_key": "block.minecraft.smooth_stone", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 297, "loot_table": { "type": "minecraft:block", @@ -200648,6 +201237,7 @@ "name": "smooth_sandstone", "translation_key": "block.minecraft.smooth_sandstone", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 296, "loot_table": { "type": "minecraft:block", @@ -200694,6 +201284,7 @@ "name": "smooth_quartz", "translation_key": "block.minecraft.smooth_quartz", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 294, "loot_table": { "type": "minecraft:block", @@ -200740,6 +201331,7 @@ "name": "smooth_red_sandstone", "translation_key": "block.minecraft.smooth_red_sandstone", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 295, "loot_table": { "type": "minecraft:block", @@ -200786,6 +201378,7 @@ "name": "spruce_fence_gate", "translation_key": "block.minecraft.spruce_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 778, "loot_table": { "type": "minecraft:block", @@ -201265,6 +201858,7 @@ "name": "birch_fence_gate", "translation_key": "block.minecraft.birch_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 779, "loot_table": { "type": "minecraft:block", @@ -201744,6 +202338,7 @@ "name": "jungle_fence_gate", "translation_key": "block.minecraft.jungle_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 780, "loot_table": { "type": "minecraft:block", @@ -202223,6 +202818,7 @@ "name": "acacia_fence_gate", "translation_key": "block.minecraft.acacia_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 781, "loot_table": { "type": "minecraft:block", @@ -202702,6 +203298,7 @@ "name": "cherry_fence_gate", "translation_key": "block.minecraft.cherry_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 782, "loot_table": { "type": "minecraft:block", @@ -203181,6 +203778,7 @@ "name": "dark_oak_fence_gate", "translation_key": "block.minecraft.dark_oak_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 783, "loot_table": { "type": "minecraft:block", @@ -203660,6 +204258,7 @@ "name": "pale_oak_fence_gate", "translation_key": "block.minecraft.pale_oak_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 784, "loot_table": { "type": "minecraft:block", @@ -204139,6 +204738,7 @@ "name": "mangrove_fence_gate", "translation_key": "block.minecraft.mangrove_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 785, "loot_table": { "type": "minecraft:block", @@ -204618,6 +205218,7 @@ "name": "bamboo_fence_gate", "translation_key": "block.minecraft.bamboo_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 786, "loot_table": { "type": "minecraft:block", @@ -205097,6 +205698,7 @@ "name": "spruce_fence", "translation_key": "block.minecraft.spruce_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 326, "loot_table": { "type": "minecraft:block", @@ -205635,6 +206237,7 @@ "name": "birch_fence", "translation_key": "block.minecraft.birch_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 327, "loot_table": { "type": "minecraft:block", @@ -206173,6 +206776,7 @@ "name": "jungle_fence", "translation_key": "block.minecraft.jungle_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 328, "loot_table": { "type": "minecraft:block", @@ -206711,6 +207315,7 @@ "name": "acacia_fence", "translation_key": "block.minecraft.acacia_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 329, "loot_table": { "type": "minecraft:block", @@ -207249,6 +207854,7 @@ "name": "cherry_fence", "translation_key": "block.minecraft.cherry_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 330, "loot_table": { "type": "minecraft:block", @@ -207787,6 +208393,7 @@ "name": "dark_oak_fence", "translation_key": "block.minecraft.dark_oak_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 331, "loot_table": { "type": "minecraft:block", @@ -208325,6 +208932,7 @@ "name": "pale_oak_fence", "translation_key": "block.minecraft.pale_oak_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 332, "loot_table": { "type": "minecraft:block", @@ -208863,6 +209471,7 @@ "name": "mangrove_fence", "translation_key": "block.minecraft.mangrove_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 333, "loot_table": { "type": "minecraft:block", @@ -209401,6 +210010,7 @@ "name": "bamboo_fence", "translation_key": "block.minecraft.bamboo_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 334, "loot_table": { "type": "minecraft:block", @@ -209939,6 +210549,7 @@ "name": "spruce_door", "translation_key": "block.minecraft.spruce_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 737, "loot_table": { "type": "minecraft:block", @@ -210850,6 +211461,7 @@ "name": "birch_door", "translation_key": "block.minecraft.birch_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 738, "loot_table": { "type": "minecraft:block", @@ -211761,6 +212373,7 @@ "name": "jungle_door", "translation_key": "block.minecraft.jungle_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 739, "loot_table": { "type": "minecraft:block", @@ -212672,6 +213285,7 @@ "name": "acacia_door", "translation_key": "block.minecraft.acacia_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 740, "loot_table": { "type": "minecraft:block", @@ -213583,6 +214197,7 @@ "name": "cherry_door", "translation_key": "block.minecraft.cherry_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 741, "loot_table": { "type": "minecraft:block", @@ -214494,6 +215109,7 @@ "name": "dark_oak_door", "translation_key": "block.minecraft.dark_oak_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 742, "loot_table": { "type": "minecraft:block", @@ -215405,6 +216021,7 @@ "name": "pale_oak_door", "translation_key": "block.minecraft.pale_oak_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 743, "loot_table": { "type": "minecraft:block", @@ -216316,6 +216933,7 @@ "name": "mangrove_door", "translation_key": "block.minecraft.mangrove_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 744, "loot_table": { "type": "minecraft:block", @@ -217227,6 +217845,7 @@ "name": "bamboo_door", "translation_key": "block.minecraft.bamboo_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 745, "loot_table": { "type": "minecraft:block", @@ -218138,6 +218757,7 @@ "name": "end_rod", "translation_key": "block.minecraft.end_rod", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 305, "loot_table": { "type": "minecraft:block", @@ -218260,6 +218880,7 @@ "name": "chorus_plant", "translation_key": "block.minecraft.chorus_plant", "hardness": 0.4, + "blast_resistance": 0.4, "item_id": 306, "loot_table": { "type": "minecraft:block", @@ -219277,6 +219898,7 @@ "name": "chorus_flower", "translation_key": "block.minecraft.chorus_flower", "hardness": 0.4, + "blast_resistance": 0.4, "item_id": 307, "loot_table": { "type": "minecraft:block", @@ -219404,6 +220026,7 @@ "name": "purpur_block", "translation_key": "block.minecraft.purpur_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 308, "loot_table": { "type": "minecraft:block", @@ -219450,6 +220073,7 @@ "name": "purpur_pillar", "translation_key": "block.minecraft.purpur_pillar", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 309, "loot_table": { "type": "minecraft:block", @@ -219533,6 +220157,7 @@ "name": "purpur_stairs", "translation_key": "block.minecraft.purpur_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 310, "loot_table": { "type": "minecraft:block", @@ -220847,6 +221472,7 @@ "name": "end_stone_bricks", "translation_key": "block.minecraft.end_stone_bricks", "hardness": 3.0, + "blast_resistance": 9.0, "item_id": 400, "loot_table": { "type": "minecraft:block", @@ -220893,6 +221519,7 @@ "name": "torchflower_crop", "translation_key": "block.minecraft.torchflower_crop", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1204, "loot_table": { "type": "minecraft:block", @@ -220955,6 +221582,7 @@ "name": "pitcher_crop", "translation_key": "block.minecraft.pitcher_crop", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1205, "loot_table": { "type": "minecraft:block", @@ -221263,6 +221891,7 @@ "name": "pitcher_plant", "translation_key": "block.minecraft.pitcher_plant", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 241, "loot_table": { "type": "minecraft:block", @@ -221334,6 +221963,7 @@ "name": "beetroots", "translation_key": "block.minecraft.beetroots", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1207, "loot_table": { "type": "minecraft:block", @@ -221468,6 +222098,7 @@ "name": "dirt_path", "translation_key": "block.minecraft.dirt_path", "hardness": 0.65, + "blast_resistance": 0.65, "item_id": 487, "loot_table": { "type": "minecraft:block", @@ -221514,6 +222145,7 @@ "name": "end_gateway", "translation_key": "block.minecraft.end_gateway", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 0, "properties": [], "default_state_id": 13527, @@ -221537,6 +222169,7 @@ "name": "repeating_command_block", "translation_key": "block.minecraft.repeating_command_block", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 537, "properties": [ { @@ -221747,6 +222380,7 @@ "name": "chain_command_block", "translation_key": "block.minecraft.chain_command_block", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 538, "properties": [ { @@ -221957,6 +222591,7 @@ "name": "frosted_ice", "translation_key": "block.minecraft.frosted_ice", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -222034,6 +222669,7 @@ "name": "magma_block", "translation_key": "block.minecraft.magma_block", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 539, "loot_table": { "type": "minecraft:block", @@ -222080,6 +222716,7 @@ "name": "nether_wart_block", "translation_key": "block.minecraft.nether_wart_block", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 540, "loot_table": { "type": "minecraft:block", @@ -222126,6 +222763,7 @@ "name": "red_nether_bricks", "translation_key": "block.minecraft.red_nether_bricks", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 542, "loot_table": { "type": "minecraft:block", @@ -222172,6 +222810,7 @@ "name": "bone_block", "translation_key": "block.minecraft.bone_block", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 543, "loot_table": { "type": "minecraft:block", @@ -222255,6 +222894,7 @@ "name": "structure_void", "translation_key": "block.minecraft.structure_void", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 544, "properties": [], "default_state_id": 13562, @@ -222277,6 +222917,7 @@ "name": "observer", "translation_key": "block.minecraft.observer", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 689, "loot_table": { "type": "minecraft:block", @@ -222496,6 +223137,7 @@ "name": "shulker_box", "translation_key": "block.minecraft.shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 545, "loot_table": { "type": "minecraft:block", @@ -222631,6 +223273,7 @@ "name": "white_shulker_box", "translation_key": "block.minecraft.white_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 546, "loot_table": { "type": "minecraft:block", @@ -222766,6 +223409,7 @@ "name": "orange_shulker_box", "translation_key": "block.minecraft.orange_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 547, "loot_table": { "type": "minecraft:block", @@ -222901,6 +223545,7 @@ "name": "magenta_shulker_box", "translation_key": "block.minecraft.magenta_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 548, "loot_table": { "type": "minecraft:block", @@ -223036,6 +223681,7 @@ "name": "light_blue_shulker_box", "translation_key": "block.minecraft.light_blue_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 549, "loot_table": { "type": "minecraft:block", @@ -223171,6 +223817,7 @@ "name": "yellow_shulker_box", "translation_key": "block.minecraft.yellow_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 550, "loot_table": { "type": "minecraft:block", @@ -223306,6 +223953,7 @@ "name": "lime_shulker_box", "translation_key": "block.minecraft.lime_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 551, "loot_table": { "type": "minecraft:block", @@ -223441,6 +224089,7 @@ "name": "pink_shulker_box", "translation_key": "block.minecraft.pink_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 552, "loot_table": { "type": "minecraft:block", @@ -223576,6 +224225,7 @@ "name": "gray_shulker_box", "translation_key": "block.minecraft.gray_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 553, "loot_table": { "type": "minecraft:block", @@ -223711,6 +224361,7 @@ "name": "light_gray_shulker_box", "translation_key": "block.minecraft.light_gray_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 554, "loot_table": { "type": "minecraft:block", @@ -223846,6 +224497,7 @@ "name": "cyan_shulker_box", "translation_key": "block.minecraft.cyan_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 555, "loot_table": { "type": "minecraft:block", @@ -223981,6 +224633,7 @@ "name": "purple_shulker_box", "translation_key": "block.minecraft.purple_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 556, "loot_table": { "type": "minecraft:block", @@ -224116,6 +224769,7 @@ "name": "blue_shulker_box", "translation_key": "block.minecraft.blue_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 557, "loot_table": { "type": "minecraft:block", @@ -224251,6 +224905,7 @@ "name": "brown_shulker_box", "translation_key": "block.minecraft.brown_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 558, "loot_table": { "type": "minecraft:block", @@ -224386,6 +225041,7 @@ "name": "green_shulker_box", "translation_key": "block.minecraft.green_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 559, "loot_table": { "type": "minecraft:block", @@ -224521,6 +225177,7 @@ "name": "red_shulker_box", "translation_key": "block.minecraft.red_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 560, "loot_table": { "type": "minecraft:block", @@ -224656,6 +225313,7 @@ "name": "black_shulker_box", "translation_key": "block.minecraft.black_shulker_box", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 561, "loot_table": { "type": "minecraft:block", @@ -224791,6 +225449,7 @@ "name": "white_glazed_terracotta", "translation_key": "block.minecraft.white_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 562, "loot_table": { "type": "minecraft:block", @@ -224889,6 +225548,7 @@ "name": "orange_glazed_terracotta", "translation_key": "block.minecraft.orange_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 563, "loot_table": { "type": "minecraft:block", @@ -224987,6 +225647,7 @@ "name": "magenta_glazed_terracotta", "translation_key": "block.minecraft.magenta_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 564, "loot_table": { "type": "minecraft:block", @@ -225085,6 +225746,7 @@ "name": "light_blue_glazed_terracotta", "translation_key": "block.minecraft.light_blue_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 565, "loot_table": { "type": "minecraft:block", @@ -225183,6 +225845,7 @@ "name": "yellow_glazed_terracotta", "translation_key": "block.minecraft.yellow_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 566, "loot_table": { "type": "minecraft:block", @@ -225281,6 +225944,7 @@ "name": "lime_glazed_terracotta", "translation_key": "block.minecraft.lime_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 567, "loot_table": { "type": "minecraft:block", @@ -225379,6 +226043,7 @@ "name": "pink_glazed_terracotta", "translation_key": "block.minecraft.pink_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 568, "loot_table": { "type": "minecraft:block", @@ -225477,6 +226142,7 @@ "name": "gray_glazed_terracotta", "translation_key": "block.minecraft.gray_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 569, "loot_table": { "type": "minecraft:block", @@ -225575,6 +226241,7 @@ "name": "light_gray_glazed_terracotta", "translation_key": "block.minecraft.light_gray_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 570, "loot_table": { "type": "minecraft:block", @@ -225673,6 +226340,7 @@ "name": "cyan_glazed_terracotta", "translation_key": "block.minecraft.cyan_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 571, "loot_table": { "type": "minecraft:block", @@ -225771,6 +226439,7 @@ "name": "purple_glazed_terracotta", "translation_key": "block.minecraft.purple_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 572, "loot_table": { "type": "minecraft:block", @@ -225869,6 +226538,7 @@ "name": "blue_glazed_terracotta", "translation_key": "block.minecraft.blue_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 573, "loot_table": { "type": "minecraft:block", @@ -225967,6 +226637,7 @@ "name": "brown_glazed_terracotta", "translation_key": "block.minecraft.brown_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 574, "loot_table": { "type": "minecraft:block", @@ -226065,6 +226736,7 @@ "name": "green_glazed_terracotta", "translation_key": "block.minecraft.green_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 575, "loot_table": { "type": "minecraft:block", @@ -226163,6 +226835,7 @@ "name": "red_glazed_terracotta", "translation_key": "block.minecraft.red_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 576, "loot_table": { "type": "minecraft:block", @@ -226261,6 +226934,7 @@ "name": "black_glazed_terracotta", "translation_key": "block.minecraft.black_glazed_terracotta", "hardness": 1.4, + "blast_resistance": 1.4, "item_id": 577, "loot_table": { "type": "minecraft:block", @@ -226359,6 +227033,7 @@ "name": "white_concrete", "translation_key": "block.minecraft.white_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 578, "loot_table": { "type": "minecraft:block", @@ -226405,6 +227080,7 @@ "name": "orange_concrete", "translation_key": "block.minecraft.orange_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 579, "loot_table": { "type": "minecraft:block", @@ -226451,6 +227127,7 @@ "name": "magenta_concrete", "translation_key": "block.minecraft.magenta_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 580, "loot_table": { "type": "minecraft:block", @@ -226497,6 +227174,7 @@ "name": "light_blue_concrete", "translation_key": "block.minecraft.light_blue_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 581, "loot_table": { "type": "minecraft:block", @@ -226543,6 +227221,7 @@ "name": "yellow_concrete", "translation_key": "block.minecraft.yellow_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 582, "loot_table": { "type": "minecraft:block", @@ -226589,6 +227268,7 @@ "name": "lime_concrete", "translation_key": "block.minecraft.lime_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 583, "loot_table": { "type": "minecraft:block", @@ -226635,6 +227315,7 @@ "name": "pink_concrete", "translation_key": "block.minecraft.pink_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 584, "loot_table": { "type": "minecraft:block", @@ -226681,6 +227362,7 @@ "name": "gray_concrete", "translation_key": "block.minecraft.gray_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 585, "loot_table": { "type": "minecraft:block", @@ -226727,6 +227409,7 @@ "name": "light_gray_concrete", "translation_key": "block.minecraft.light_gray_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 586, "loot_table": { "type": "minecraft:block", @@ -226773,6 +227456,7 @@ "name": "cyan_concrete", "translation_key": "block.minecraft.cyan_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 587, "loot_table": { "type": "minecraft:block", @@ -226819,6 +227503,7 @@ "name": "purple_concrete", "translation_key": "block.minecraft.purple_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 588, "loot_table": { "type": "minecraft:block", @@ -226865,6 +227550,7 @@ "name": "blue_concrete", "translation_key": "block.minecraft.blue_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 589, "loot_table": { "type": "minecraft:block", @@ -226911,6 +227597,7 @@ "name": "brown_concrete", "translation_key": "block.minecraft.brown_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 590, "loot_table": { "type": "minecraft:block", @@ -226957,6 +227644,7 @@ "name": "green_concrete", "translation_key": "block.minecraft.green_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 591, "loot_table": { "type": "minecraft:block", @@ -227003,6 +227691,7 @@ "name": "red_concrete", "translation_key": "block.minecraft.red_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 592, "loot_table": { "type": "minecraft:block", @@ -227049,6 +227738,7 @@ "name": "black_concrete", "translation_key": "block.minecraft.black_concrete", "hardness": 1.8, + "blast_resistance": 1.8, "item_id": 593, "loot_table": { "type": "minecraft:block", @@ -227095,6 +227785,7 @@ "name": "white_concrete_powder", "translation_key": "block.minecraft.white_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 594, "loot_table": { "type": "minecraft:block", @@ -227141,6 +227832,7 @@ "name": "orange_concrete_powder", "translation_key": "block.minecraft.orange_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 595, "loot_table": { "type": "minecraft:block", @@ -227187,6 +227879,7 @@ "name": "magenta_concrete_powder", "translation_key": "block.minecraft.magenta_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 596, "loot_table": { "type": "minecraft:block", @@ -227233,6 +227926,7 @@ "name": "light_blue_concrete_powder", "translation_key": "block.minecraft.light_blue_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 597, "loot_table": { "type": "minecraft:block", @@ -227279,6 +227973,7 @@ "name": "yellow_concrete_powder", "translation_key": "block.minecraft.yellow_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 598, "loot_table": { "type": "minecraft:block", @@ -227325,6 +228020,7 @@ "name": "lime_concrete_powder", "translation_key": "block.minecraft.lime_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 599, "loot_table": { "type": "minecraft:block", @@ -227371,6 +228067,7 @@ "name": "pink_concrete_powder", "translation_key": "block.minecraft.pink_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 600, "loot_table": { "type": "minecraft:block", @@ -227417,6 +228114,7 @@ "name": "gray_concrete_powder", "translation_key": "block.minecraft.gray_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 601, "loot_table": { "type": "minecraft:block", @@ -227463,6 +228161,7 @@ "name": "light_gray_concrete_powder", "translation_key": "block.minecraft.light_gray_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 602, "loot_table": { "type": "minecraft:block", @@ -227509,6 +228208,7 @@ "name": "cyan_concrete_powder", "translation_key": "block.minecraft.cyan_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 603, "loot_table": { "type": "minecraft:block", @@ -227555,6 +228255,7 @@ "name": "purple_concrete_powder", "translation_key": "block.minecraft.purple_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 604, "loot_table": { "type": "minecraft:block", @@ -227601,6 +228302,7 @@ "name": "blue_concrete_powder", "translation_key": "block.minecraft.blue_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 605, "loot_table": { "type": "minecraft:block", @@ -227647,6 +228349,7 @@ "name": "brown_concrete_powder", "translation_key": "block.minecraft.brown_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 606, "loot_table": { "type": "minecraft:block", @@ -227693,6 +228396,7 @@ "name": "green_concrete_powder", "translation_key": "block.minecraft.green_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 607, "loot_table": { "type": "minecraft:block", @@ -227739,6 +228443,7 @@ "name": "red_concrete_powder", "translation_key": "block.minecraft.red_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 608, "loot_table": { "type": "minecraft:block", @@ -227785,6 +228490,7 @@ "name": "black_concrete_powder", "translation_key": "block.minecraft.black_concrete_powder", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 609, "loot_table": { "type": "minecraft:block", @@ -227831,6 +228537,7 @@ "name": "kelp", "translation_key": "block.minecraft.kelp", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 253, "loot_table": { "type": "minecraft:block", @@ -228181,6 +228888,7 @@ "name": "kelp_plant", "translation_key": "block.minecraft.kelp_plant", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -228224,6 +228932,7 @@ "name": "dried_kelp_block", "translation_key": "block.minecraft.dried_kelp_block", "hardness": 0.5, + "blast_resistance": 2.5, "item_id": 956, "loot_table": { "type": "minecraft:block", @@ -228270,6 +228979,7 @@ "name": "turtle_egg", "translation_key": "block.minecraft.turtle_egg", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 610, "loot_table": { "type": "minecraft:block", @@ -228488,6 +229198,7 @@ "name": "sniffer_egg", "translation_key": "block.minecraft.sniffer_egg", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 611, "loot_table": { "type": "minecraft:block", @@ -228568,6 +229279,7 @@ "name": "dead_tube_coral_block", "translation_key": "block.minecraft.dead_tube_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 612, "loot_table": { "type": "minecraft:block", @@ -228614,6 +229326,7 @@ "name": "dead_brain_coral_block", "translation_key": "block.minecraft.dead_brain_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 613, "loot_table": { "type": "minecraft:block", @@ -228660,6 +229373,7 @@ "name": "dead_bubble_coral_block", "translation_key": "block.minecraft.dead_bubble_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 614, "loot_table": { "type": "minecraft:block", @@ -228706,6 +229420,7 @@ "name": "dead_fire_coral_block", "translation_key": "block.minecraft.dead_fire_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 615, "loot_table": { "type": "minecraft:block", @@ -228752,6 +229467,7 @@ "name": "dead_horn_coral_block", "translation_key": "block.minecraft.dead_horn_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 616, "loot_table": { "type": "minecraft:block", @@ -228798,6 +229514,7 @@ "name": "tube_coral_block", "translation_key": "block.minecraft.tube_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 617, "loot_table": { "type": "minecraft:block", @@ -228870,6 +229587,7 @@ "name": "brain_coral_block", "translation_key": "block.minecraft.brain_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 618, "loot_table": { "type": "minecraft:block", @@ -228942,6 +229660,7 @@ "name": "bubble_coral_block", "translation_key": "block.minecraft.bubble_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 619, "loot_table": { "type": "minecraft:block", @@ -229014,6 +229733,7 @@ "name": "fire_coral_block", "translation_key": "block.minecraft.fire_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 620, "loot_table": { "type": "minecraft:block", @@ -229086,6 +229806,7 @@ "name": "horn_coral_block", "translation_key": "block.minecraft.horn_coral_block", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 621, "loot_table": { "type": "minecraft:block", @@ -229158,6 +229879,7 @@ "name": "dead_tube_coral", "translation_key": "block.minecraft.dead_tube_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 631, "loot_table": { "type": "minecraft:block", @@ -229232,6 +229954,7 @@ "name": "dead_brain_coral", "translation_key": "block.minecraft.dead_brain_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 627, "loot_table": { "type": "minecraft:block", @@ -229306,6 +230029,7 @@ "name": "dead_bubble_coral", "translation_key": "block.minecraft.dead_bubble_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 628, "loot_table": { "type": "minecraft:block", @@ -229380,6 +230104,7 @@ "name": "dead_fire_coral", "translation_key": "block.minecraft.dead_fire_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 629, "loot_table": { "type": "minecraft:block", @@ -229454,6 +230179,7 @@ "name": "dead_horn_coral", "translation_key": "block.minecraft.dead_horn_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 630, "loot_table": { "type": "minecraft:block", @@ -229528,6 +230254,7 @@ "name": "tube_coral", "translation_key": "block.minecraft.tube_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 622, "loot_table": { "type": "minecraft:block", @@ -229602,6 +230329,7 @@ "name": "brain_coral", "translation_key": "block.minecraft.brain_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 623, "loot_table": { "type": "minecraft:block", @@ -229676,6 +230404,7 @@ "name": "bubble_coral", "translation_key": "block.minecraft.bubble_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 624, "loot_table": { "type": "minecraft:block", @@ -229750,6 +230479,7 @@ "name": "fire_coral", "translation_key": "block.minecraft.fire_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 625, "loot_table": { "type": "minecraft:block", @@ -229824,6 +230554,7 @@ "name": "horn_coral", "translation_key": "block.minecraft.horn_coral", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 626, "loot_table": { "type": "minecraft:block", @@ -229898,6 +230629,7 @@ "name": "dead_tube_coral_fan", "translation_key": "block.minecraft.dead_tube_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 637, "loot_table": { "type": "minecraft:block", @@ -229972,6 +230704,7 @@ "name": "dead_brain_coral_fan", "translation_key": "block.minecraft.dead_brain_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 638, "loot_table": { "type": "minecraft:block", @@ -230046,6 +230779,7 @@ "name": "dead_bubble_coral_fan", "translation_key": "block.minecraft.dead_bubble_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 639, "loot_table": { "type": "minecraft:block", @@ -230120,6 +230854,7 @@ "name": "dead_fire_coral_fan", "translation_key": "block.minecraft.dead_fire_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 640, "loot_table": { "type": "minecraft:block", @@ -230194,6 +230929,7 @@ "name": "dead_horn_coral_fan", "translation_key": "block.minecraft.dead_horn_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 641, "loot_table": { "type": "minecraft:block", @@ -230268,6 +231004,7 @@ "name": "tube_coral_fan", "translation_key": "block.minecraft.tube_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 632, "loot_table": { "type": "minecraft:block", @@ -230342,6 +231079,7 @@ "name": "brain_coral_fan", "translation_key": "block.minecraft.brain_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 633, "loot_table": { "type": "minecraft:block", @@ -230416,6 +231154,7 @@ "name": "bubble_coral_fan", "translation_key": "block.minecraft.bubble_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 634, "loot_table": { "type": "minecraft:block", @@ -230490,6 +231229,7 @@ "name": "fire_coral_fan", "translation_key": "block.minecraft.fire_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 635, "loot_table": { "type": "minecraft:block", @@ -230564,6 +231304,7 @@ "name": "horn_coral_fan", "translation_key": "block.minecraft.horn_coral_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 636, "loot_table": { "type": "minecraft:block", @@ -230638,6 +231379,7 @@ "name": "dead_tube_coral_wall_fan", "translation_key": "block.minecraft.dead_tube_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 637, "loot_table": { "type": "minecraft:block", @@ -230787,6 +231529,7 @@ "name": "dead_brain_coral_wall_fan", "translation_key": "block.minecraft.dead_brain_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 638, "loot_table": { "type": "minecraft:block", @@ -230936,6 +231679,7 @@ "name": "dead_bubble_coral_wall_fan", "translation_key": "block.minecraft.dead_bubble_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 639, "loot_table": { "type": "minecraft:block", @@ -231085,6 +231829,7 @@ "name": "dead_fire_coral_wall_fan", "translation_key": "block.minecraft.dead_fire_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 640, "loot_table": { "type": "minecraft:block", @@ -231234,6 +231979,7 @@ "name": "dead_horn_coral_wall_fan", "translation_key": "block.minecraft.dead_horn_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 641, "loot_table": { "type": "minecraft:block", @@ -231383,6 +232129,7 @@ "name": "tube_coral_wall_fan", "translation_key": "block.minecraft.tube_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 632, "loot_table": { "type": "minecraft:block", @@ -231532,6 +232279,7 @@ "name": "brain_coral_wall_fan", "translation_key": "block.minecraft.brain_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 633, "loot_table": { "type": "minecraft:block", @@ -231681,6 +232429,7 @@ "name": "bubble_coral_wall_fan", "translation_key": "block.minecraft.bubble_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 634, "loot_table": { "type": "minecraft:block", @@ -231830,6 +232579,7 @@ "name": "fire_coral_wall_fan", "translation_key": "block.minecraft.fire_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 635, "loot_table": { "type": "minecraft:block", @@ -231979,6 +232729,7 @@ "name": "horn_coral_wall_fan", "translation_key": "block.minecraft.horn_coral_wall_fan", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 636, "loot_table": { "type": "minecraft:block", @@ -232128,6 +232879,7 @@ "name": "sea_pickle", "translation_key": "block.minecraft.sea_pickle", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 208, "loot_table": { "type": "minecraft:block", @@ -232323,6 +233075,7 @@ "name": "blue_ice", "translation_key": "block.minecraft.blue_ice", "hardness": 2.8, + "blast_resistance": 2.8, "item_id": 642, "loot_table": { "type": "minecraft:block", @@ -232381,6 +233134,7 @@ "name": "conduit", "translation_key": "block.minecraft.conduit", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 643, "loot_table": { "type": "minecraft:block", @@ -232444,6 +233198,7 @@ "name": "bamboo_sapling", "translation_key": "block.minecraft.bamboo_sapling", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -232487,6 +233242,7 @@ "name": "bamboo", "translation_key": "block.minecraft.bamboo", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 263, "loot_table": { "type": "minecraft:block", @@ -232698,6 +233454,7 @@ "name": "potted_bamboo", "translation_key": "block.minecraft.potted_bamboo", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -232758,6 +233515,7 @@ "name": "void_air", "translation_key": "block.minecraft.void_air", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "properties": [], "default_state_id": 13971, @@ -232780,6 +233538,7 @@ "name": "cave_air", "translation_key": "block.minecraft.cave_air", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "properties": [], "default_state_id": 13972, @@ -232802,6 +233561,7 @@ "name": "bubble_column", "translation_key": "block.minecraft.bubble_column", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "properties": [ { @@ -232843,6 +233603,7 @@ "name": "polished_granite_stairs", "translation_key": "block.minecraft.polished_granite_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 644, "loot_table": { "type": "minecraft:block", @@ -234157,6 +234918,7 @@ "name": "smooth_red_sandstone_stairs", "translation_key": "block.minecraft.smooth_red_sandstone_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 645, "loot_table": { "type": "minecraft:block", @@ -235471,6 +236233,7 @@ "name": "mossy_stone_brick_stairs", "translation_key": "block.minecraft.mossy_stone_brick_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 646, "loot_table": { "type": "minecraft:block", @@ -236785,6 +237548,7 @@ "name": "polished_diorite_stairs", "translation_key": "block.minecraft.polished_diorite_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 647, "loot_table": { "type": "minecraft:block", @@ -238099,6 +238863,7 @@ "name": "mossy_cobblestone_stairs", "translation_key": "block.minecraft.mossy_cobblestone_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 648, "loot_table": { "type": "minecraft:block", @@ -239413,6 +240178,7 @@ "name": "end_stone_brick_stairs", "translation_key": "block.minecraft.end_stone_brick_stairs", "hardness": 3.0, + "blast_resistance": 9.0, "item_id": 649, "loot_table": { "type": "minecraft:block", @@ -240727,6 +241493,7 @@ "name": "stone_stairs", "translation_key": "block.minecraft.stone_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 650, "loot_table": { "type": "minecraft:block", @@ -242041,6 +242808,7 @@ "name": "smooth_sandstone_stairs", "translation_key": "block.minecraft.smooth_sandstone_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 651, "loot_table": { "type": "minecraft:block", @@ -243355,6 +244123,7 @@ "name": "smooth_quartz_stairs", "translation_key": "block.minecraft.smooth_quartz_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 652, "loot_table": { "type": "minecraft:block", @@ -244669,6 +245438,7 @@ "name": "granite_stairs", "translation_key": "block.minecraft.granite_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 653, "loot_table": { "type": "minecraft:block", @@ -245983,6 +246753,7 @@ "name": "andesite_stairs", "translation_key": "block.minecraft.andesite_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 654, "loot_table": { "type": "minecraft:block", @@ -247297,6 +248068,7 @@ "name": "red_nether_brick_stairs", "translation_key": "block.minecraft.red_nether_brick_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 655, "loot_table": { "type": "minecraft:block", @@ -248611,6 +249383,7 @@ "name": "polished_andesite_stairs", "translation_key": "block.minecraft.polished_andesite_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 656, "loot_table": { "type": "minecraft:block", @@ -249925,6 +250698,7 @@ "name": "diorite_stairs", "translation_key": "block.minecraft.diorite_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 657, "loot_table": { "type": "minecraft:block", @@ -251239,6 +252013,7 @@ "name": "polished_granite_slab", "translation_key": "block.minecraft.polished_granite_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 662, "loot_table": { "type": "minecraft:block", @@ -251385,6 +252160,7 @@ "name": "smooth_red_sandstone_slab", "translation_key": "block.minecraft.smooth_red_sandstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 663, "loot_table": { "type": "minecraft:block", @@ -251531,6 +252307,7 @@ "name": "mossy_stone_brick_slab", "translation_key": "block.minecraft.mossy_stone_brick_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 664, "loot_table": { "type": "minecraft:block", @@ -251677,6 +252454,7 @@ "name": "polished_diorite_slab", "translation_key": "block.minecraft.polished_diorite_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 665, "loot_table": { "type": "minecraft:block", @@ -251823,6 +252601,7 @@ "name": "mossy_cobblestone_slab", "translation_key": "block.minecraft.mossy_cobblestone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 666, "loot_table": { "type": "minecraft:block", @@ -251969,6 +252748,7 @@ "name": "end_stone_brick_slab", "translation_key": "block.minecraft.end_stone_brick_slab", "hardness": 3.0, + "blast_resistance": 9.0, "item_id": 667, "loot_table": { "type": "minecraft:block", @@ -252115,6 +252895,7 @@ "name": "smooth_sandstone_slab", "translation_key": "block.minecraft.smooth_sandstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 668, "loot_table": { "type": "minecraft:block", @@ -252261,6 +253042,7 @@ "name": "smooth_quartz_slab", "translation_key": "block.minecraft.smooth_quartz_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 669, "loot_table": { "type": "minecraft:block", @@ -252407,6 +253189,7 @@ "name": "granite_slab", "translation_key": "block.minecraft.granite_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 670, "loot_table": { "type": "minecraft:block", @@ -252553,6 +253336,7 @@ "name": "andesite_slab", "translation_key": "block.minecraft.andesite_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 671, "loot_table": { "type": "minecraft:block", @@ -252699,6 +253483,7 @@ "name": "red_nether_brick_slab", "translation_key": "block.minecraft.red_nether_brick_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 672, "loot_table": { "type": "minecraft:block", @@ -252845,6 +253630,7 @@ "name": "polished_andesite_slab", "translation_key": "block.minecraft.polished_andesite_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 673, "loot_table": { "type": "minecraft:block", @@ -252991,6 +253777,7 @@ "name": "diorite_slab", "translation_key": "block.minecraft.diorite_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 674, "loot_table": { "type": "minecraft:block", @@ -253137,6 +253924,7 @@ "name": "brick_wall", "translation_key": "block.minecraft.brick_wall", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 422, "loot_table": { "type": "minecraft:block", @@ -258392,6 +259180,7 @@ "name": "prismarine_wall", "translation_key": "block.minecraft.prismarine_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 423, "loot_table": { "type": "minecraft:block", @@ -263647,6 +264436,7 @@ "name": "red_sandstone_wall", "translation_key": "block.minecraft.red_sandstone_wall", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 424, "loot_table": { "type": "minecraft:block", @@ -268902,6 +269692,7 @@ "name": "mossy_stone_brick_wall", "translation_key": "block.minecraft.mossy_stone_brick_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 425, "loot_table": { "type": "minecraft:block", @@ -274157,6 +274948,7 @@ "name": "granite_wall", "translation_key": "block.minecraft.granite_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 426, "loot_table": { "type": "minecraft:block", @@ -279412,6 +280204,7 @@ "name": "stone_brick_wall", "translation_key": "block.minecraft.stone_brick_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 427, "loot_table": { "type": "minecraft:block", @@ -284667,6 +285460,7 @@ "name": "mud_brick_wall", "translation_key": "block.minecraft.mud_brick_wall", "hardness": 1.5, + "blast_resistance": 3.0, "item_id": 428, "loot_table": { "type": "minecraft:block", @@ -289922,6 +290716,7 @@ "name": "nether_brick_wall", "translation_key": "block.minecraft.nether_brick_wall", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 429, "loot_table": { "type": "minecraft:block", @@ -295177,6 +295972,7 @@ "name": "andesite_wall", "translation_key": "block.minecraft.andesite_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 430, "loot_table": { "type": "minecraft:block", @@ -300432,6 +301228,7 @@ "name": "red_nether_brick_wall", "translation_key": "block.minecraft.red_nether_brick_wall", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 431, "loot_table": { "type": "minecraft:block", @@ -305687,6 +306484,7 @@ "name": "sandstone_wall", "translation_key": "block.minecraft.sandstone_wall", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 432, "loot_table": { "type": "minecraft:block", @@ -310942,6 +311740,7 @@ "name": "end_stone_brick_wall", "translation_key": "block.minecraft.end_stone_brick_wall", "hardness": 3.0, + "blast_resistance": 9.0, "item_id": 433, "loot_table": { "type": "minecraft:block", @@ -316197,6 +316996,7 @@ "name": "diorite_wall", "translation_key": "block.minecraft.diorite_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 434, "loot_table": { "type": "minecraft:block", @@ -321452,6 +322252,7 @@ "name": "scaffolding", "translation_key": "block.minecraft.scaffolding", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 679, "loot_table": { "type": "minecraft:block", @@ -322120,6 +322921,7 @@ "name": "loom", "translation_key": "block.minecraft.loom", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 1245, "loot_table": { "type": "minecraft:block", @@ -322218,6 +323020,7 @@ "name": "barrel", "translation_key": "block.minecraft.barrel", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 1258, "loot_table": { "type": "minecraft:block", @@ -322458,6 +323261,7 @@ "name": "smoker", "translation_key": "block.minecraft.smoker", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 1259, "loot_table": { "type": "minecraft:block", @@ -322636,6 +323440,7 @@ "name": "blast_furnace", "translation_key": "block.minecraft.blast_furnace", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 1260, "loot_table": { "type": "minecraft:block", @@ -322814,6 +323619,7 @@ "name": "cartography_table", "translation_key": "block.minecraft.cartography_table", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 1261, "loot_table": { "type": "minecraft:block", @@ -322860,6 +323666,7 @@ "name": "fletching_table", "translation_key": "block.minecraft.fletching_table", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 1262, "loot_table": { "type": "minecraft:block", @@ -322906,6 +323713,7 @@ "name": "grindstone", "translation_key": "block.minecraft.grindstone", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 1263, "loot_table": { "type": "minecraft:block", @@ -323180,6 +323988,7 @@ "name": "lectern", "translation_key": "block.minecraft.lectern", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 693, "loot_table": { "type": "minecraft:block", @@ -323492,6 +324301,7 @@ "name": "smithing_table", "translation_key": "block.minecraft.smithing_table", "hardness": 2.5, + "blast_resistance": 2.5, "item_id": 1264, "loot_table": { "type": "minecraft:block", @@ -323538,6 +324348,7 @@ "name": "stonecutter", "translation_key": "block.minecraft.stonecutter", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 1265, "loot_table": { "type": "minecraft:block", @@ -323636,6 +324447,7 @@ "name": "bell", "translation_key": "block.minecraft.bell", "hardness": 5.0, + "blast_resistance": 5.0, "item_id": 1266, "loot_table": { "type": "minecraft:block", @@ -324222,6 +325034,7 @@ "name": "lantern", "translation_key": "block.minecraft.lantern", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 1267, "loot_table": { "type": "minecraft:block", @@ -324325,6 +325138,7 @@ "name": "soul_lantern", "translation_key": "block.minecraft.soul_lantern", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 1268, "loot_table": { "type": "minecraft:block", @@ -324428,6 +325242,7 @@ "name": "campfire", "translation_key": "block.minecraft.campfire", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 1271, "loot_table": { "type": "minecraft:block", @@ -324972,6 +325787,7 @@ "name": "soul_campfire", "translation_key": "block.minecraft.soul_campfire", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 1272, "loot_table": { "type": "minecraft:block", @@ -325516,6 +326332,7 @@ "name": "sweet_berry_bush", "translation_key": "block.minecraft.sweet_berry_bush", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1269, "loot_table": { "type": "minecraft:block", @@ -325668,6 +326485,7 @@ "name": "warped_stem", "translation_key": "block.minecraft.warped_stem", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 146, "loot_table": { "type": "minecraft:block", @@ -325751,6 +326569,7 @@ "name": "stripped_warped_stem", "translation_key": "block.minecraft.stripped_warped_stem", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 158, "loot_table": { "type": "minecraft:block", @@ -325834,6 +326653,7 @@ "name": "warped_hyphae", "translation_key": "block.minecraft.warped_hyphae", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 181, "loot_table": { "type": "minecraft:block", @@ -325917,6 +326737,7 @@ "name": "stripped_warped_hyphae", "translation_key": "block.minecraft.stripped_warped_hyphae", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 169, "loot_table": { "type": "minecraft:block", @@ -326000,6 +326821,7 @@ "name": "warped_nylium", "translation_key": "block.minecraft.warped_nylium", "hardness": 0.4, + "blast_resistance": 0.4, "item_id": 34, "loot_table": { "type": "minecraft:block", @@ -326072,6 +326894,7 @@ "name": "warped_fungus", "translation_key": "block.minecraft.warped_fungus", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 246, "loot_table": { "type": "minecraft:block", @@ -326115,6 +326938,7 @@ "name": "warped_wart_block", "translation_key": "block.minecraft.warped_wart_block", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 541, "loot_table": { "type": "minecraft:block", @@ -326161,6 +326985,7 @@ "name": "warped_roots", "translation_key": "block.minecraft.warped_roots", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 248, "loot_table": { "type": "minecraft:block", @@ -326204,6 +327029,7 @@ "name": "nether_sprouts", "translation_key": "block.minecraft.nether_sprouts", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 249, "loot_table": { "type": "minecraft:block", @@ -326250,6 +327076,7 @@ "name": "crimson_stem", "translation_key": "block.minecraft.crimson_stem", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 145, "loot_table": { "type": "minecraft:block", @@ -326333,6 +327160,7 @@ "name": "stripped_crimson_stem", "translation_key": "block.minecraft.stripped_crimson_stem", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 157, "loot_table": { "type": "minecraft:block", @@ -326416,6 +327244,7 @@ "name": "crimson_hyphae", "translation_key": "block.minecraft.crimson_hyphae", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 180, "loot_table": { "type": "minecraft:block", @@ -326499,6 +327328,7 @@ "name": "stripped_crimson_hyphae", "translation_key": "block.minecraft.stripped_crimson_hyphae", "hardness": 2.0, + "blast_resistance": 2.0, "item_id": 168, "loot_table": { "type": "minecraft:block", @@ -326582,6 +327412,7 @@ "name": "crimson_nylium", "translation_key": "block.minecraft.crimson_nylium", "hardness": 0.4, + "blast_resistance": 0.4, "item_id": 33, "loot_table": { "type": "minecraft:block", @@ -326654,6 +327485,7 @@ "name": "crimson_fungus", "translation_key": "block.minecraft.crimson_fungus", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 245, "loot_table": { "type": "minecraft:block", @@ -326697,6 +327529,7 @@ "name": "shroomlight", "translation_key": "block.minecraft.shroomlight", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 1273, "loot_table": { "type": "minecraft:block", @@ -326743,6 +327576,7 @@ "name": "weeping_vines", "translation_key": "block.minecraft.weeping_vines", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 250, "loot_table": { "type": "minecraft:block", @@ -327137,6 +327971,7 @@ "name": "weeping_vines_plant", "translation_key": "block.minecraft.weeping_vines_plant", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -327224,6 +328059,7 @@ "name": "twisting_vines", "translation_key": "block.minecraft.twisting_vines", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 251, "loot_table": { "type": "minecraft:block", @@ -327618,6 +328454,7 @@ "name": "twisting_vines_plant", "translation_key": "block.minecraft.twisting_vines_plant", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -327705,6 +328542,7 @@ "name": "crimson_roots", "translation_key": "block.minecraft.crimson_roots", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 247, "loot_table": { "type": "minecraft:block", @@ -327748,6 +328586,7 @@ "name": "crimson_planks", "translation_key": "block.minecraft.crimson_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 46, "loot_table": { "type": "minecraft:block", @@ -327794,6 +328633,7 @@ "name": "warped_planks", "translation_key": "block.minecraft.warped_planks", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 47, "loot_table": { "type": "minecraft:block", @@ -327840,6 +328680,7 @@ "name": "crimson_slab", "translation_key": "block.minecraft.crimson_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 275, "loot_table": { "type": "minecraft:block", @@ -327986,6 +328827,7 @@ "name": "warped_slab", "translation_key": "block.minecraft.warped_slab", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 276, "loot_table": { "type": "minecraft:block", @@ -328132,6 +328974,7 @@ "name": "crimson_pressure_plate", "translation_key": "block.minecraft.crimson_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 733, "loot_table": { "type": "minecraft:block", @@ -328194,6 +329037,7 @@ "name": "warped_pressure_plate", "translation_key": "block.minecraft.warped_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 734, "loot_table": { "type": "minecraft:block", @@ -328256,6 +329100,7 @@ "name": "crimson_fence", "translation_key": "block.minecraft.crimson_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 335, "loot_table": { "type": "minecraft:block", @@ -328794,6 +329639,7 @@ "name": "warped_fence", "translation_key": "block.minecraft.warped_fence", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 336, "loot_table": { "type": "minecraft:block", @@ -329332,6 +330178,7 @@ "name": "crimson_trapdoor", "translation_key": "block.minecraft.crimson_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 767, "loot_table": { "type": "minecraft:block", @@ -330234,6 +331081,7 @@ "name": "warped_trapdoor", "translation_key": "block.minecraft.warped_trapdoor", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 768, "loot_table": { "type": "minecraft:block", @@ -331136,6 +331984,7 @@ "name": "crimson_fence_gate", "translation_key": "block.minecraft.crimson_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 787, "loot_table": { "type": "minecraft:block", @@ -331615,6 +332464,7 @@ "name": "warped_fence_gate", "translation_key": "block.minecraft.warped_fence_gate", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 788, "loot_table": { "type": "minecraft:block", @@ -332094,6 +332944,7 @@ "name": "crimson_stairs", "translation_key": "block.minecraft.crimson_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 416, "loot_table": { "type": "minecraft:block", @@ -333408,6 +334259,7 @@ "name": "warped_stairs", "translation_key": "block.minecraft.warped_stairs", "hardness": 2.0, + "blast_resistance": 3.0, "item_id": 417, "loot_table": { "type": "minecraft:block", @@ -334722,6 +335574,7 @@ "name": "crimson_button", "translation_key": "block.minecraft.crimson_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 717, "loot_table": { "type": "minecraft:block", @@ -335043,6 +335896,7 @@ "name": "warped_button", "translation_key": "block.minecraft.warped_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 718, "loot_table": { "type": "minecraft:block", @@ -335364,6 +336218,7 @@ "name": "crimson_door", "translation_key": "block.minecraft.crimson_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 746, "loot_table": { "type": "minecraft:block", @@ -336275,6 +337130,7 @@ "name": "warped_door", "translation_key": "block.minecraft.warped_door", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 747, "loot_table": { "type": "minecraft:block", @@ -337186,6 +338042,7 @@ "name": "crimson_sign", "translation_key": "block.minecraft.crimson_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 927, "loot_table": { "type": "minecraft:block", @@ -337631,6 +338488,7 @@ "name": "warped_sign", "translation_key": "block.minecraft.warped_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 928, "loot_table": { "type": "minecraft:block", @@ -338076,6 +338934,7 @@ "name": "crimson_wall_sign", "translation_key": "block.minecraft.crimson_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 927, "loot_table": { "type": "minecraft:block", @@ -338221,6 +339080,7 @@ "name": "warped_wall_sign", "translation_key": "block.minecraft.warped_sign", "hardness": 1.0, + "blast_resistance": 1.0, "item_id": 928, "loot_table": { "type": "minecraft:block", @@ -338366,6 +339226,7 @@ "name": "structure_block", "translation_key": "block.minecraft.structure_block", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 823, "properties": [ { @@ -338447,6 +339308,7 @@ "name": "jigsaw", "translation_key": "block.minecraft.jigsaw", "hardness": -1.0, + "blast_resistance": 3600000.0, "item_id": 824, "properties": [ { @@ -338656,6 +339518,7 @@ "name": "composter", "translation_key": "block.minecraft.composter", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 1257, "loot_table": { "type": "minecraft:block", @@ -338884,6 +339747,7 @@ "name": "target", "translation_key": "block.minecraft.target", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 694, "loot_table": { "type": "minecraft:block", @@ -339162,6 +340026,7 @@ "name": "bee_nest", "translation_key": "block.minecraft.bee_nest", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 1275, "loot_table": { "type": "minecraft:block", @@ -339603,6 +340468,7 @@ "name": "beehive", "translation_key": "block.minecraft.beehive", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 1276, "loot_table": { "type": "minecraft:block", @@ -340053,6 +340919,7 @@ "name": "honey_block", "translation_key": "block.minecraft.honey_block", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 688, "loot_table": { "type": "minecraft:block", @@ -340098,6 +340965,7 @@ "name": "honeycomb_block", "translation_key": "block.minecraft.honeycomb_block", "hardness": 0.6, + "blast_resistance": 0.6, "item_id": 1278, "loot_table": { "type": "minecraft:block", @@ -340144,6 +341012,7 @@ "name": "netherite_block", "translation_key": "block.minecraft.netherite_block", "hardness": 50.0, + "blast_resistance": 1200.0, "item_id": 94, "loot_table": { "type": "minecraft:block", @@ -340190,6 +341059,7 @@ "name": "ancient_debris", "translation_key": "block.minecraft.ancient_debris", "hardness": 30.0, + "blast_resistance": 1200.0, "item_id": 82, "loot_table": { "type": "minecraft:block", @@ -340236,6 +341106,7 @@ "name": "crying_obsidian", "translation_key": "block.minecraft.crying_obsidian", "hardness": 50.0, + "blast_resistance": 1200.0, "item_id": 1280, "loot_table": { "type": "minecraft:block", @@ -340282,6 +341153,7 @@ "name": "respawn_anchor", "translation_key": "block.minecraft.respawn_anchor", "hardness": 50.0, + "blast_resistance": 1200.0, "item_id": 1293, "loot_table": { "type": "minecraft:block", @@ -340395,6 +341267,7 @@ "name": "potted_crimson_fungus", "translation_key": "block.minecraft.potted_crimson_fungus", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -340455,6 +341328,7 @@ "name": "potted_warped_fungus", "translation_key": "block.minecraft.potted_warped_fungus", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -340515,6 +341389,7 @@ "name": "potted_crimson_roots", "translation_key": "block.minecraft.potted_crimson_roots", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -340575,6 +341450,7 @@ "name": "potted_warped_roots", "translation_key": "block.minecraft.potted_warped_roots", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -340635,6 +341511,7 @@ "name": "lodestone", "translation_key": "block.minecraft.lodestone", "hardness": 3.5, + "blast_resistance": 3.5, "item_id": 1279, "loot_table": { "type": "minecraft:block", @@ -340681,6 +341558,7 @@ "name": "blackstone", "translation_key": "block.minecraft.blackstone", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1281, "loot_table": { "type": "minecraft:block", @@ -340727,6 +341605,7 @@ "name": "blackstone_stairs", "translation_key": "block.minecraft.blackstone_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1283, "loot_table": { "type": "minecraft:block", @@ -342041,6 +342920,7 @@ "name": "blackstone_wall", "translation_key": "block.minecraft.blackstone_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 435, "loot_table": { "type": "minecraft:block", @@ -347296,6 +348176,7 @@ "name": "blackstone_slab", "translation_key": "block.minecraft.blackstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 1282, "loot_table": { "type": "minecraft:block", @@ -347442,6 +348323,7 @@ "name": "polished_blackstone", "translation_key": "block.minecraft.polished_blackstone", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 1285, "loot_table": { "type": "minecraft:block", @@ -347488,6 +348370,7 @@ "name": "polished_blackstone_bricks", "translation_key": "block.minecraft.polished_blackstone_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1289, "loot_table": { "type": "minecraft:block", @@ -347534,6 +348417,7 @@ "name": "cracked_polished_blackstone_bricks", "translation_key": "block.minecraft.cracked_polished_blackstone_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1292, "loot_table": { "type": "minecraft:block", @@ -347580,6 +348464,7 @@ "name": "chiseled_polished_blackstone", "translation_key": "block.minecraft.chiseled_polished_blackstone", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1288, "loot_table": { "type": "minecraft:block", @@ -347626,6 +348511,7 @@ "name": "polished_blackstone_brick_slab", "translation_key": "block.minecraft.polished_blackstone_brick_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 1290, "loot_table": { "type": "minecraft:block", @@ -347772,6 +348658,7 @@ "name": "polished_blackstone_brick_stairs", "translation_key": "block.minecraft.polished_blackstone_brick_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1291, "loot_table": { "type": "minecraft:block", @@ -349086,6 +349973,7 @@ "name": "polished_blackstone_brick_wall", "translation_key": "block.minecraft.polished_blackstone_brick_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 437, "loot_table": { "type": "minecraft:block", @@ -354341,6 +355229,7 @@ "name": "gilded_blackstone", "translation_key": "block.minecraft.gilded_blackstone", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 1284, "loot_table": { "type": "minecraft:block", @@ -354445,6 +355334,7 @@ "name": "polished_blackstone_stairs", "translation_key": "block.minecraft.polished_blackstone_stairs", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 1287, "loot_table": { "type": "minecraft:block", @@ -355759,6 +356649,7 @@ "name": "polished_blackstone_slab", "translation_key": "block.minecraft.polished_blackstone_slab", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 1286, "loot_table": { "type": "minecraft:block", @@ -355905,6 +356796,7 @@ "name": "polished_blackstone_pressure_plate", "translation_key": "block.minecraft.polished_blackstone_pressure_plate", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 720, "loot_table": { "type": "minecraft:block", @@ -355967,6 +356859,7 @@ "name": "polished_blackstone_button", "translation_key": "block.minecraft.polished_blackstone_button", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 706, "loot_table": { "type": "minecraft:block", @@ -356288,6 +357181,7 @@ "name": "polished_blackstone_wall", "translation_key": "block.minecraft.polished_blackstone_wall", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 436, "loot_table": { "type": "minecraft:block", @@ -361543,6 +362437,7 @@ "name": "chiseled_nether_bricks", "translation_key": "block.minecraft.chiseled_nether_bricks", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 390, "loot_table": { "type": "minecraft:block", @@ -361589,6 +362484,7 @@ "name": "cracked_nether_bricks", "translation_key": "block.minecraft.cracked_nether_bricks", "hardness": 2.0, + "blast_resistance": 6.0, "item_id": 389, "loot_table": { "type": "minecraft:block", @@ -361635,6 +362531,7 @@ "name": "quartz_bricks", "translation_key": "block.minecraft.quartz_bricks", "hardness": 0.8, + "blast_resistance": 0.8, "item_id": 447, "loot_table": { "type": "minecraft:block", @@ -361681,6 +362578,7 @@ "name": "candle", "translation_key": "block.minecraft.candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1294, "loot_table": { "type": "minecraft:block", @@ -361987,6 +362885,7 @@ "name": "white_candle", "translation_key": "block.minecraft.white_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1295, "loot_table": { "type": "minecraft:block", @@ -362293,6 +363192,7 @@ "name": "orange_candle", "translation_key": "block.minecraft.orange_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1296, "loot_table": { "type": "minecraft:block", @@ -362599,6 +363499,7 @@ "name": "magenta_candle", "translation_key": "block.minecraft.magenta_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1297, "loot_table": { "type": "minecraft:block", @@ -362905,6 +363806,7 @@ "name": "light_blue_candle", "translation_key": "block.minecraft.light_blue_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1298, "loot_table": { "type": "minecraft:block", @@ -363211,6 +364113,7 @@ "name": "yellow_candle", "translation_key": "block.minecraft.yellow_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1299, "loot_table": { "type": "minecraft:block", @@ -363517,6 +364420,7 @@ "name": "lime_candle", "translation_key": "block.minecraft.lime_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1300, "loot_table": { "type": "minecraft:block", @@ -363823,6 +364727,7 @@ "name": "pink_candle", "translation_key": "block.minecraft.pink_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1301, "loot_table": { "type": "minecraft:block", @@ -364129,6 +365034,7 @@ "name": "gray_candle", "translation_key": "block.minecraft.gray_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1302, "loot_table": { "type": "minecraft:block", @@ -364435,6 +365341,7 @@ "name": "light_gray_candle", "translation_key": "block.minecraft.light_gray_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1303, "loot_table": { "type": "minecraft:block", @@ -364741,6 +365648,7 @@ "name": "cyan_candle", "translation_key": "block.minecraft.cyan_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1304, "loot_table": { "type": "minecraft:block", @@ -365047,6 +365955,7 @@ "name": "purple_candle", "translation_key": "block.minecraft.purple_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1305, "loot_table": { "type": "minecraft:block", @@ -365353,6 +366262,7 @@ "name": "blue_candle", "translation_key": "block.minecraft.blue_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1306, "loot_table": { "type": "minecraft:block", @@ -365659,6 +366569,7 @@ "name": "brown_candle", "translation_key": "block.minecraft.brown_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1307, "loot_table": { "type": "minecraft:block", @@ -365965,6 +366876,7 @@ "name": "green_candle", "translation_key": "block.minecraft.green_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1308, "loot_table": { "type": "minecraft:block", @@ -366271,6 +367183,7 @@ "name": "red_candle", "translation_key": "block.minecraft.red_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1309, "loot_table": { "type": "minecraft:block", @@ -366577,6 +367490,7 @@ "name": "black_candle", "translation_key": "block.minecraft.black_candle", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 1310, "loot_table": { "type": "minecraft:block", @@ -366883,6 +367797,7 @@ "name": "candle_cake", "translation_key": "block.minecraft.candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -366948,6 +367863,7 @@ "name": "white_candle_cake", "translation_key": "block.minecraft.white_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367013,6 +367929,7 @@ "name": "orange_candle_cake", "translation_key": "block.minecraft.orange_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367078,6 +367995,7 @@ "name": "magenta_candle_cake", "translation_key": "block.minecraft.magenta_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367143,6 +368061,7 @@ "name": "light_blue_candle_cake", "translation_key": "block.minecraft.light_blue_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367208,6 +368127,7 @@ "name": "yellow_candle_cake", "translation_key": "block.minecraft.yellow_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367273,6 +368193,7 @@ "name": "lime_candle_cake", "translation_key": "block.minecraft.lime_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367338,6 +368259,7 @@ "name": "pink_candle_cake", "translation_key": "block.minecraft.pink_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367403,6 +368325,7 @@ "name": "gray_candle_cake", "translation_key": "block.minecraft.gray_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367468,6 +368391,7 @@ "name": "light_gray_candle_cake", "translation_key": "block.minecraft.light_gray_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367533,6 +368457,7 @@ "name": "cyan_candle_cake", "translation_key": "block.minecraft.cyan_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367598,6 +368523,7 @@ "name": "purple_candle_cake", "translation_key": "block.minecraft.purple_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367663,6 +368589,7 @@ "name": "blue_candle_cake", "translation_key": "block.minecraft.blue_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367728,6 +368655,7 @@ "name": "brown_candle_cake", "translation_key": "block.minecraft.brown_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367793,6 +368721,7 @@ "name": "green_candle_cake", "translation_key": "block.minecraft.green_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367858,6 +368787,7 @@ "name": "red_candle_cake", "translation_key": "block.minecraft.red_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367923,6 +368853,7 @@ "name": "black_candle_cake", "translation_key": "block.minecraft.black_candle_cake", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -367988,6 +368919,7 @@ "name": "amethyst_block", "translation_key": "block.minecraft.amethyst_block", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 88, "loot_table": { "type": "minecraft:block", @@ -368034,6 +368966,7 @@ "name": "budding_amethyst", "translation_key": "block.minecraft.budding_amethyst", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 89, "loot_table": { "type": "minecraft:block", @@ -368063,6 +368996,7 @@ "name": "amethyst_cluster", "translation_key": "block.minecraft.amethyst_cluster", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 1314, "loot_table": { "type": "minecraft:block", @@ -368330,6 +369264,7 @@ "name": "large_amethyst_bud", "translation_key": "block.minecraft.large_amethyst_bud", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 1313, "loot_table": { "type": "minecraft:block", @@ -368549,6 +369484,7 @@ "name": "medium_amethyst_bud", "translation_key": "block.minecraft.medium_amethyst_bud", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 1312, "loot_table": { "type": "minecraft:block", @@ -368768,6 +369704,7 @@ "name": "small_amethyst_bud", "translation_key": "block.minecraft.small_amethyst_bud", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 1311, "loot_table": { "type": "minecraft:block", @@ -368987,6 +369924,7 @@ "name": "tuff", "translation_key": "block.minecraft.tuff", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 12, "loot_table": { "type": "minecraft:block", @@ -369033,6 +369971,7 @@ "name": "tuff_slab", "translation_key": "block.minecraft.tuff_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 13, "loot_table": { "type": "minecraft:block", @@ -369179,6 +370118,7 @@ "name": "tuff_stairs", "translation_key": "block.minecraft.tuff_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 14, "loot_table": { "type": "minecraft:block", @@ -370493,6 +371433,7 @@ "name": "tuff_wall", "translation_key": "block.minecraft.tuff_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 15, "loot_table": { "type": "minecraft:block", @@ -375748,6 +376689,7 @@ "name": "polished_tuff", "translation_key": "block.minecraft.polished_tuff", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 17, "loot_table": { "type": "minecraft:block", @@ -375794,6 +376736,7 @@ "name": "polished_tuff_slab", "translation_key": "block.minecraft.polished_tuff_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 18, "loot_table": { "type": "minecraft:block", @@ -375940,6 +376883,7 @@ "name": "polished_tuff_stairs", "translation_key": "block.minecraft.polished_tuff_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 19, "loot_table": { "type": "minecraft:block", @@ -377254,6 +378198,7 @@ "name": "polished_tuff_wall", "translation_key": "block.minecraft.polished_tuff_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 20, "loot_table": { "type": "minecraft:block", @@ -382509,6 +383454,7 @@ "name": "chiseled_tuff", "translation_key": "block.minecraft.chiseled_tuff", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 16, "loot_table": { "type": "minecraft:block", @@ -382555,6 +383501,7 @@ "name": "tuff_bricks", "translation_key": "block.minecraft.tuff_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 21, "loot_table": { "type": "minecraft:block", @@ -382601,6 +383548,7 @@ "name": "tuff_brick_slab", "translation_key": "block.minecraft.tuff_brick_slab", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 22, "loot_table": { "type": "minecraft:block", @@ -382747,6 +383695,7 @@ "name": "tuff_brick_stairs", "translation_key": "block.minecraft.tuff_brick_stairs", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 23, "loot_table": { "type": "minecraft:block", @@ -384061,6 +385010,7 @@ "name": "tuff_brick_wall", "translation_key": "block.minecraft.tuff_brick_wall", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 24, "loot_table": { "type": "minecraft:block", @@ -389316,6 +390266,7 @@ "name": "chiseled_tuff_bricks", "translation_key": "block.minecraft.chiseled_tuff_bricks", "hardness": 1.5, + "blast_resistance": 6.0, "item_id": 25, "loot_table": { "type": "minecraft:block", @@ -389362,6 +390313,7 @@ "name": "calcite", "translation_key": "block.minecraft.calcite", "hardness": 0.75, + "blast_resistance": 0.75, "item_id": 11, "loot_table": { "type": "minecraft:block", @@ -389408,6 +390360,7 @@ "name": "tinted_glass", "translation_key": "block.minecraft.tinted_glass", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 196, "loot_table": { "type": "minecraft:block", @@ -389453,6 +390406,7 @@ "name": "powder_snow", "translation_key": "block.minecraft.powder_snow", "hardness": 0.25, + "blast_resistance": 0.25, "item_id": 944, "loot_table": { "type": "minecraft:block", @@ -389479,6 +390433,7 @@ "name": "sculk_sensor", "translation_key": "block.minecraft.sculk_sensor", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 698, "loot_table": { "type": "minecraft:block", @@ -391000,6 +391955,7 @@ "name": "calibrated_sculk_sensor", "translation_key": "block.minecraft.calibrated_sculk_sensor", "hardness": 1.5, + "blast_resistance": 1.5, "item_id": 699, "loot_table": { "type": "minecraft:block", @@ -396850,6 +397806,7 @@ "name": "sculk", "translation_key": "block.minecraft.sculk", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 393, "experience": { "experience": 1, @@ -396912,6 +397869,7 @@ "name": "sculk_vein", "translation_key": "block.minecraft.sculk_vein", "hardness": 0.2, + "blast_resistance": 0.2, "item_id": 394, "loot_table": { "type": "minecraft:block", @@ -398508,6 +399466,7 @@ "name": "sculk_catalyst", "translation_key": "block.minecraft.sculk_catalyst", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 395, "loot_table": { "type": "minecraft:block", @@ -398590,6 +399549,7 @@ "name": "sculk_shrieker", "translation_key": "block.minecraft.sculk_shrieker", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 396, "loot_table": { "type": "minecraft:block", @@ -398776,6 +399736,7 @@ "name": "copper_block", "translation_key": "block.minecraft.copper_block", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 91, "loot_table": { "type": "minecraft:block", @@ -398822,6 +399783,7 @@ "name": "exposed_copper", "translation_key": "block.minecraft.exposed_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 95, "loot_table": { "type": "minecraft:block", @@ -398868,6 +399830,7 @@ "name": "weathered_copper", "translation_key": "block.minecraft.weathered_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 96, "loot_table": { "type": "minecraft:block", @@ -398914,6 +399877,7 @@ "name": "oxidized_copper", "translation_key": "block.minecraft.oxidized_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 97, "loot_table": { "type": "minecraft:block", @@ -398960,6 +399924,7 @@ "name": "copper_ore", "translation_key": "block.minecraft.copper_ore", "hardness": 3.0, + "blast_resistance": 3.0, "item_id": 68, "experience": { "experience": 0, @@ -399050,6 +400015,7 @@ "name": "deepslate_copper_ore", "translation_key": "block.minecraft.deepslate_copper_ore", "hardness": 4.5, + "blast_resistance": 3.0, "item_id": 69, "experience": { "experience": 0, @@ -399140,6 +400106,7 @@ "name": "oxidized_cut_copper", "translation_key": "block.minecraft.oxidized_cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 105, "loot_table": { "type": "minecraft:block", @@ -399186,6 +400153,7 @@ "name": "weathered_cut_copper", "translation_key": "block.minecraft.weathered_cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 104, "loot_table": { "type": "minecraft:block", @@ -399232,6 +400200,7 @@ "name": "exposed_cut_copper", "translation_key": "block.minecraft.exposed_cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 103, "loot_table": { "type": "minecraft:block", @@ -399278,6 +400247,7 @@ "name": "cut_copper", "translation_key": "block.minecraft.cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 102, "loot_table": { "type": "minecraft:block", @@ -399324,6 +400294,7 @@ "name": "oxidized_chiseled_copper", "translation_key": "block.minecraft.oxidized_chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 101, "loot_table": { "type": "minecraft:block", @@ -399370,6 +400341,7 @@ "name": "weathered_chiseled_copper", "translation_key": "block.minecraft.weathered_chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 100, "loot_table": { "type": "minecraft:block", @@ -399416,6 +400388,7 @@ "name": "exposed_chiseled_copper", "translation_key": "block.minecraft.exposed_chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 99, "loot_table": { "type": "minecraft:block", @@ -399462,6 +400435,7 @@ "name": "chiseled_copper", "translation_key": "block.minecraft.chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 98, "loot_table": { "type": "minecraft:block", @@ -399508,6 +400482,7 @@ "name": "waxed_oxidized_chiseled_copper", "translation_key": "block.minecraft.waxed_oxidized_chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 121, "loot_table": { "type": "minecraft:block", @@ -399554,6 +400529,7 @@ "name": "waxed_weathered_chiseled_copper", "translation_key": "block.minecraft.waxed_weathered_chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 120, "loot_table": { "type": "minecraft:block", @@ -399600,6 +400576,7 @@ "name": "waxed_exposed_chiseled_copper", "translation_key": "block.minecraft.waxed_exposed_chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 119, "loot_table": { "type": "minecraft:block", @@ -399646,6 +400623,7 @@ "name": "waxed_chiseled_copper", "translation_key": "block.minecraft.waxed_chiseled_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 118, "loot_table": { "type": "minecraft:block", @@ -399692,6 +400670,7 @@ "name": "oxidized_cut_copper_stairs", "translation_key": "block.minecraft.oxidized_cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 109, "loot_table": { "type": "minecraft:block", @@ -401006,6 +401985,7 @@ "name": "weathered_cut_copper_stairs", "translation_key": "block.minecraft.weathered_cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 108, "loot_table": { "type": "minecraft:block", @@ -402320,6 +403300,7 @@ "name": "exposed_cut_copper_stairs", "translation_key": "block.minecraft.exposed_cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 107, "loot_table": { "type": "minecraft:block", @@ -403634,6 +404615,7 @@ "name": "cut_copper_stairs", "translation_key": "block.minecraft.cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 106, "loot_table": { "type": "minecraft:block", @@ -404948,6 +405930,7 @@ "name": "oxidized_cut_copper_slab", "translation_key": "block.minecraft.oxidized_cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 113, "loot_table": { "type": "minecraft:block", @@ -405094,6 +406077,7 @@ "name": "weathered_cut_copper_slab", "translation_key": "block.minecraft.weathered_cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 112, "loot_table": { "type": "minecraft:block", @@ -405240,6 +406224,7 @@ "name": "exposed_cut_copper_slab", "translation_key": "block.minecraft.exposed_cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 111, "loot_table": { "type": "minecraft:block", @@ -405386,6 +406371,7 @@ "name": "cut_copper_slab", "translation_key": "block.minecraft.cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 110, "loot_table": { "type": "minecraft:block", @@ -405532,6 +406518,7 @@ "name": "waxed_copper_block", "translation_key": "block.minecraft.waxed_copper_block", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 114, "loot_table": { "type": "minecraft:block", @@ -405578,6 +406565,7 @@ "name": "waxed_weathered_copper", "translation_key": "block.minecraft.waxed_weathered_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 116, "loot_table": { "type": "minecraft:block", @@ -405624,6 +406612,7 @@ "name": "waxed_exposed_copper", "translation_key": "block.minecraft.waxed_exposed_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 115, "loot_table": { "type": "minecraft:block", @@ -405670,6 +406659,7 @@ "name": "waxed_oxidized_copper", "translation_key": "block.minecraft.waxed_oxidized_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 117, "loot_table": { "type": "minecraft:block", @@ -405716,6 +406706,7 @@ "name": "waxed_oxidized_cut_copper", "translation_key": "block.minecraft.waxed_oxidized_cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 125, "loot_table": { "type": "minecraft:block", @@ -405762,6 +406753,7 @@ "name": "waxed_weathered_cut_copper", "translation_key": "block.minecraft.waxed_weathered_cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 124, "loot_table": { "type": "minecraft:block", @@ -405808,6 +406800,7 @@ "name": "waxed_exposed_cut_copper", "translation_key": "block.minecraft.waxed_exposed_cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 123, "loot_table": { "type": "minecraft:block", @@ -405854,6 +406847,7 @@ "name": "waxed_cut_copper", "translation_key": "block.minecraft.waxed_cut_copper", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 122, "loot_table": { "type": "minecraft:block", @@ -405900,6 +406894,7 @@ "name": "waxed_oxidized_cut_copper_stairs", "translation_key": "block.minecraft.waxed_oxidized_cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 129, "loot_table": { "type": "minecraft:block", @@ -407214,6 +408209,7 @@ "name": "waxed_weathered_cut_copper_stairs", "translation_key": "block.minecraft.waxed_weathered_cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 128, "loot_table": { "type": "minecraft:block", @@ -408528,6 +409524,7 @@ "name": "waxed_exposed_cut_copper_stairs", "translation_key": "block.minecraft.waxed_exposed_cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 127, "loot_table": { "type": "minecraft:block", @@ -409842,6 +410839,7 @@ "name": "waxed_cut_copper_stairs", "translation_key": "block.minecraft.waxed_cut_copper_stairs", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 126, "loot_table": { "type": "minecraft:block", @@ -411156,6 +412154,7 @@ "name": "waxed_oxidized_cut_copper_slab", "translation_key": "block.minecraft.waxed_oxidized_cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 133, "loot_table": { "type": "minecraft:block", @@ -411302,6 +412301,7 @@ "name": "waxed_weathered_cut_copper_slab", "translation_key": "block.minecraft.waxed_weathered_cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 132, "loot_table": { "type": "minecraft:block", @@ -411448,6 +412448,7 @@ "name": "waxed_exposed_cut_copper_slab", "translation_key": "block.minecraft.waxed_exposed_cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 131, "loot_table": { "type": "minecraft:block", @@ -411594,6 +412595,7 @@ "name": "waxed_cut_copper_slab", "translation_key": "block.minecraft.waxed_cut_copper_slab", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 130, "loot_table": { "type": "minecraft:block", @@ -411740,6 +412742,7 @@ "name": "copper_door", "translation_key": "block.minecraft.copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 748, "loot_table": { "type": "minecraft:block", @@ -412651,6 +413654,7 @@ "name": "exposed_copper_door", "translation_key": "block.minecraft.exposed_copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 749, "loot_table": { "type": "minecraft:block", @@ -413562,6 +414566,7 @@ "name": "oxidized_copper_door", "translation_key": "block.minecraft.oxidized_copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 751, "loot_table": { "type": "minecraft:block", @@ -414473,6 +415478,7 @@ "name": "weathered_copper_door", "translation_key": "block.minecraft.weathered_copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 750, "loot_table": { "type": "minecraft:block", @@ -415384,6 +416390,7 @@ "name": "waxed_copper_door", "translation_key": "block.minecraft.waxed_copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 752, "loot_table": { "type": "minecraft:block", @@ -416295,6 +417302,7 @@ "name": "waxed_exposed_copper_door", "translation_key": "block.minecraft.waxed_exposed_copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 753, "loot_table": { "type": "minecraft:block", @@ -417206,6 +418214,7 @@ "name": "waxed_oxidized_copper_door", "translation_key": "block.minecraft.waxed_oxidized_copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 755, "loot_table": { "type": "minecraft:block", @@ -418117,6 +419126,7 @@ "name": "waxed_weathered_copper_door", "translation_key": "block.minecraft.waxed_weathered_copper_door", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 754, "loot_table": { "type": "minecraft:block", @@ -419028,6 +420038,7 @@ "name": "copper_trapdoor", "translation_key": "block.minecraft.copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 769, "loot_table": { "type": "minecraft:block", @@ -419930,6 +420941,7 @@ "name": "exposed_copper_trapdoor", "translation_key": "block.minecraft.exposed_copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 770, "loot_table": { "type": "minecraft:block", @@ -420832,6 +421844,7 @@ "name": "oxidized_copper_trapdoor", "translation_key": "block.minecraft.oxidized_copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 772, "loot_table": { "type": "minecraft:block", @@ -421734,6 +422747,7 @@ "name": "weathered_copper_trapdoor", "translation_key": "block.minecraft.weathered_copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 771, "loot_table": { "type": "minecraft:block", @@ -422636,6 +423650,7 @@ "name": "waxed_copper_trapdoor", "translation_key": "block.minecraft.waxed_copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 773, "loot_table": { "type": "minecraft:block", @@ -423538,6 +424553,7 @@ "name": "waxed_exposed_copper_trapdoor", "translation_key": "block.minecraft.waxed_exposed_copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 774, "loot_table": { "type": "minecraft:block", @@ -424440,6 +425456,7 @@ "name": "waxed_oxidized_copper_trapdoor", "translation_key": "block.minecraft.waxed_oxidized_copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 776, "loot_table": { "type": "minecraft:block", @@ -425342,6 +426359,7 @@ "name": "waxed_weathered_copper_trapdoor", "translation_key": "block.minecraft.waxed_weathered_copper_trapdoor", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 775, "loot_table": { "type": "minecraft:block", @@ -426244,6 +427262,7 @@ "name": "copper_grate", "translation_key": "block.minecraft.copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1364, "loot_table": { "type": "minecraft:block", @@ -426310,6 +427329,7 @@ "name": "exposed_copper_grate", "translation_key": "block.minecraft.exposed_copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1365, "loot_table": { "type": "minecraft:block", @@ -426376,6 +427396,7 @@ "name": "weathered_copper_grate", "translation_key": "block.minecraft.weathered_copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1366, "loot_table": { "type": "minecraft:block", @@ -426442,6 +427463,7 @@ "name": "oxidized_copper_grate", "translation_key": "block.minecraft.oxidized_copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1367, "loot_table": { "type": "minecraft:block", @@ -426508,6 +427530,7 @@ "name": "waxed_copper_grate", "translation_key": "block.minecraft.waxed_copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1368, "loot_table": { "type": "minecraft:block", @@ -426574,6 +427597,7 @@ "name": "waxed_exposed_copper_grate", "translation_key": "block.minecraft.waxed_exposed_copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1369, "loot_table": { "type": "minecraft:block", @@ -426640,6 +427664,7 @@ "name": "waxed_weathered_copper_grate", "translation_key": "block.minecraft.waxed_weathered_copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1370, "loot_table": { "type": "minecraft:block", @@ -426706,6 +427731,7 @@ "name": "waxed_oxidized_copper_grate", "translation_key": "block.minecraft.waxed_oxidized_copper_grate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1371, "loot_table": { "type": "minecraft:block", @@ -426772,6 +427798,7 @@ "name": "copper_bulb", "translation_key": "block.minecraft.copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1372, "loot_table": { "type": "minecraft:block", @@ -426875,6 +427902,7 @@ "name": "exposed_copper_bulb", "translation_key": "block.minecraft.exposed_copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1373, "loot_table": { "type": "minecraft:block", @@ -426978,6 +428006,7 @@ "name": "weathered_copper_bulb", "translation_key": "block.minecraft.weathered_copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1374, "loot_table": { "type": "minecraft:block", @@ -427081,6 +428110,7 @@ "name": "oxidized_copper_bulb", "translation_key": "block.minecraft.oxidized_copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1375, "loot_table": { "type": "minecraft:block", @@ -427184,6 +428214,7 @@ "name": "waxed_copper_bulb", "translation_key": "block.minecraft.waxed_copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1376, "loot_table": { "type": "minecraft:block", @@ -427287,6 +428318,7 @@ "name": "waxed_exposed_copper_bulb", "translation_key": "block.minecraft.waxed_exposed_copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1377, "loot_table": { "type": "minecraft:block", @@ -427390,6 +428422,7 @@ "name": "waxed_weathered_copper_bulb", "translation_key": "block.minecraft.waxed_weathered_copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1378, "loot_table": { "type": "minecraft:block", @@ -427493,6 +428526,7 @@ "name": "waxed_oxidized_copper_bulb", "translation_key": "block.minecraft.waxed_oxidized_copper_bulb", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 1379, "loot_table": { "type": "minecraft:block", @@ -427596,6 +428630,7 @@ "name": "lightning_rod", "translation_key": "block.minecraft.lightning_rod", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 696, "loot_table": { "type": "minecraft:block", @@ -427966,6 +429001,7 @@ "name": "pointed_dripstone", "translation_key": "block.minecraft.pointed_dripstone", "hardness": 1.5, + "blast_resistance": 3.0, "item_id": 1315, "loot_table": { "type": "minecraft:block", @@ -428283,6 +429319,7 @@ "name": "dripstone_block", "translation_key": "block.minecraft.dripstone_block", "hardness": 1.5, + "blast_resistance": 1.0, "item_id": 26, "loot_table": { "type": "minecraft:block", @@ -428329,6 +429366,7 @@ "name": "cave_vines", "translation_key": "block.minecraft.cave_vines", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1270, "loot_table": { "type": "minecraft:block", @@ -428976,6 +430014,7 @@ "name": "cave_vines_plant", "translation_key": "block.minecraft.cave_vines_plant", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -429042,6 +430081,7 @@ "name": "spore_blossom", "translation_key": "block.minecraft.spore_blossom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 242, "loot_table": { "type": "minecraft:block", @@ -429085,6 +430125,7 @@ "name": "azalea", "translation_key": "block.minecraft.azalea", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 204, "loot_table": { "type": "minecraft:block", @@ -429134,6 +430175,7 @@ "name": "flowering_azalea", "translation_key": "block.minecraft.flowering_azalea", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 205, "loot_table": { "type": "minecraft:block", @@ -429183,6 +430225,7 @@ "name": "moss_carpet", "translation_key": "block.minecraft.moss_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 255, "loot_table": { "type": "minecraft:block", @@ -429229,6 +430272,7 @@ "name": "pink_petals", "translation_key": "block.minecraft.pink_petals", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 254, "loot_table": { "type": "minecraft:block", @@ -429512,6 +430556,7 @@ "name": "moss_block", "translation_key": "block.minecraft.moss_block", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 256, "loot_table": { "type": "minecraft:block", @@ -429558,6 +430603,7 @@ "name": "big_dripleaf", "translation_key": "block.minecraft.big_dripleaf", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 261, "loot_table": { "type": "minecraft:block", @@ -430048,6 +431094,7 @@ "name": "big_dripleaf_stem", "translation_key": "block.minecraft.big_dripleaf_stem", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 261, "loot_table": { "type": "minecraft:block", @@ -430185,6 +431232,7 @@ "name": "small_dripleaf", "translation_key": "block.minecraft.small_dripleaf", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 262, "loot_table": { "type": "minecraft:block", @@ -430420,6 +431468,7 @@ "name": "hanging_roots", "translation_key": "block.minecraft.hanging_roots", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 260, "loot_table": { "type": "minecraft:block", @@ -430485,6 +431534,7 @@ "name": "rooted_dirt", "translation_key": "block.minecraft.rooted_dirt", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 31, "loot_table": { "type": "minecraft:block", @@ -430531,6 +431581,7 @@ "name": "mud", "translation_key": "block.minecraft.mud", "hardness": 0.5, + "blast_resistance": 0.5, "item_id": 32, "loot_table": { "type": "minecraft:block", @@ -430577,6 +431628,7 @@ "name": "deepslate", "translation_key": "block.minecraft.deepslate", "hardness": 3.0, + "blast_resistance": 6.0, "item_id": 8, "loot_table": { "type": "minecraft:block", @@ -430686,6 +431738,7 @@ "name": "cobbled_deepslate", "translation_key": "block.minecraft.cobbled_deepslate", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 9, "loot_table": { "type": "minecraft:block", @@ -430732,6 +431785,7 @@ "name": "cobbled_deepslate_stairs", "translation_key": "block.minecraft.cobbled_deepslate_stairs", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 658, "loot_table": { "type": "minecraft:block", @@ -432046,6 +433100,7 @@ "name": "cobbled_deepslate_slab", "translation_key": "block.minecraft.cobbled_deepslate_slab", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 675, "loot_table": { "type": "minecraft:block", @@ -432192,6 +433247,7 @@ "name": "cobbled_deepslate_wall", "translation_key": "block.minecraft.cobbled_deepslate_wall", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 438, "loot_table": { "type": "minecraft:block", @@ -437447,6 +438503,7 @@ "name": "polished_deepslate", "translation_key": "block.minecraft.polished_deepslate", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 10, "loot_table": { "type": "minecraft:block", @@ -437493,6 +438550,7 @@ "name": "polished_deepslate_stairs", "translation_key": "block.minecraft.polished_deepslate_stairs", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 659, "loot_table": { "type": "minecraft:block", @@ -438807,6 +439865,7 @@ "name": "polished_deepslate_slab", "translation_key": "block.minecraft.polished_deepslate_slab", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 676, "loot_table": { "type": "minecraft:block", @@ -438953,6 +440012,7 @@ "name": "polished_deepslate_wall", "translation_key": "block.minecraft.polished_deepslate_wall", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 439, "loot_table": { "type": "minecraft:block", @@ -444208,6 +445268,7 @@ "name": "deepslate_tiles", "translation_key": "block.minecraft.deepslate_tiles", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 363, "loot_table": { "type": "minecraft:block", @@ -444254,6 +445315,7 @@ "name": "deepslate_tile_stairs", "translation_key": "block.minecraft.deepslate_tile_stairs", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 661, "loot_table": { "type": "minecraft:block", @@ -445568,6 +446630,7 @@ "name": "deepslate_tile_slab", "translation_key": "block.minecraft.deepslate_tile_slab", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 678, "loot_table": { "type": "minecraft:block", @@ -445714,6 +446777,7 @@ "name": "deepslate_tile_wall", "translation_key": "block.minecraft.deepslate_tile_wall", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 441, "loot_table": { "type": "minecraft:block", @@ -450969,6 +452033,7 @@ "name": "deepslate_bricks", "translation_key": "block.minecraft.deepslate_bricks", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 361, "loot_table": { "type": "minecraft:block", @@ -451015,6 +452080,7 @@ "name": "deepslate_brick_stairs", "translation_key": "block.minecraft.deepslate_brick_stairs", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 660, "loot_table": { "type": "minecraft:block", @@ -452329,6 +453395,7 @@ "name": "deepslate_brick_slab", "translation_key": "block.minecraft.deepslate_brick_slab", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 677, "loot_table": { "type": "minecraft:block", @@ -452475,6 +453542,7 @@ "name": "deepslate_brick_wall", "translation_key": "block.minecraft.deepslate_brick_wall", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 440, "loot_table": { "type": "minecraft:block", @@ -457730,6 +458798,7 @@ "name": "chiseled_deepslate", "translation_key": "block.minecraft.chiseled_deepslate", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 365, "loot_table": { "type": "minecraft:block", @@ -457776,6 +458845,7 @@ "name": "cracked_deepslate_bricks", "translation_key": "block.minecraft.cracked_deepslate_bricks", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 362, "loot_table": { "type": "minecraft:block", @@ -457822,6 +458892,7 @@ "name": "cracked_deepslate_tiles", "translation_key": "block.minecraft.cracked_deepslate_tiles", "hardness": 3.5, + "blast_resistance": 6.0, "item_id": 364, "loot_table": { "type": "minecraft:block", @@ -457868,6 +458939,7 @@ "name": "infested_deepslate", "translation_key": "block.minecraft.infested_deepslate", "hardness": 1.5, + "blast_resistance": 0.75, "item_id": 354, "loot_table": { "type": "minecraft:block", @@ -457963,6 +459035,7 @@ "name": "smooth_basalt", "translation_key": "block.minecraft.smooth_basalt", "hardness": 1.25, + "blast_resistance": 4.2, "item_id": 345, "loot_table": { "type": "minecraft:block", @@ -458009,6 +459082,7 @@ "name": "raw_iron_block", "translation_key": "block.minecraft.raw_iron_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 84, "loot_table": { "type": "minecraft:block", @@ -458055,6 +459129,7 @@ "name": "raw_copper_block", "translation_key": "block.minecraft.raw_copper_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 85, "loot_table": { "type": "minecraft:block", @@ -458101,6 +459176,7 @@ "name": "raw_gold_block", "translation_key": "block.minecraft.raw_gold_block", "hardness": 5.0, + "blast_resistance": 6.0, "item_id": 86, "loot_table": { "type": "minecraft:block", @@ -458147,6 +459223,7 @@ "name": "potted_azalea_bush", "translation_key": "block.minecraft.potted_azalea_bush", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -458207,6 +459284,7 @@ "name": "potted_flowering_azalea_bush", "translation_key": "block.minecraft.potted_flowering_azalea_bush", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -458267,6 +459345,7 @@ "name": "ochre_froglight", "translation_key": "block.minecraft.ochre_froglight", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 1316, "loot_table": { "type": "minecraft:block", @@ -458350,6 +459429,7 @@ "name": "verdant_froglight", "translation_key": "block.minecraft.verdant_froglight", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 1317, "loot_table": { "type": "minecraft:block", @@ -458433,6 +459513,7 @@ "name": "pearlescent_froglight", "translation_key": "block.minecraft.pearlescent_froglight", "hardness": 0.3, + "blast_resistance": 0.3, "item_id": 1318, "loot_table": { "type": "minecraft:block", @@ -458516,6 +459597,7 @@ "name": "frogspawn", "translation_key": "block.minecraft.frogspawn", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 1319, "loot_table": { "type": "minecraft:block", @@ -458542,6 +459624,7 @@ "name": "reinforced_deepslate", "translation_key": "block.minecraft.reinforced_deepslate", "hardness": 55.0, + "blast_resistance": 1200.0, "item_id": 366, "loot_table": { "type": "minecraft:block", @@ -458571,6 +459654,7 @@ "name": "decorated_pot", "translation_key": "block.minecraft.decorated_pot", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 301, "loot_table": { "type": "minecraft:block", @@ -458873,6 +459957,7 @@ "name": "crafter", "translation_key": "block.minecraft.crafter", "hardness": 1.5, + "blast_resistance": 3.5, "item_id": 1030, "loot_table": { "type": "minecraft:block", @@ -459657,6 +460742,7 @@ "name": "trial_spawner", "translation_key": "block.minecraft.trial_spawner", "hardness": 50.0, + "blast_resistance": 50.0, "item_id": 1380, "loot_table": { "type": "minecraft:block", @@ -459859,6 +460945,7 @@ "name": "vault", "translation_key": "block.minecraft.vault", "hardness": 50.0, + "blast_resistance": 50.0, "item_id": 1383, "loot_table": { "type": "minecraft:block", @@ -460348,6 +461435,7 @@ "name": "heavy_core", "translation_key": "block.minecraft.heavy_core", "hardness": 10.0, + "blast_resistance": 1200.0, "item_id": 87, "loot_table": { "type": "minecraft:block", @@ -460416,6 +461504,7 @@ "name": "pale_moss_block", "translation_key": "block.minecraft.pale_moss_block", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 259, "loot_table": { "type": "minecraft:block", @@ -460462,6 +461551,7 @@ "name": "pale_moss_carpet", "translation_key": "block.minecraft.pale_moss_carpet", "hardness": 0.1, + "blast_resistance": 0.1, "item_id": 257, "loot_table": { "type": "minecraft:block", @@ -462649,6 +463739,7 @@ "name": "pale_hanging_moss", "translation_key": "block.minecraft.pale_hanging_moss", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 258, "loot_table": { "type": "minecraft:block", @@ -462734,6 +463825,7 @@ "name": "open_eyeblossom", "translation_key": "block.minecraft.open_eyeblossom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 226, "loot_table": { "type": "minecraft:block", @@ -462777,6 +463869,7 @@ "name": "closed_eyeblossom", "translation_key": "block.minecraft.closed_eyeblossom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 227, "loot_table": { "type": "minecraft:block", @@ -462820,6 +463913,7 @@ "name": "potted_open_eyeblossom", "translation_key": "block.minecraft.potted_open_eyeblossom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", @@ -462880,6 +463974,7 @@ "name": "potted_closed_eyeblossom", "translation_key": "block.minecraft.potted_closed_eyeblossom", "hardness": 0.0, + "blast_resistance": 0.0, "item_id": 0, "loot_table": { "type": "minecraft:block", diff --git a/assets/entity_statuses.json b/assets/entity_statuses.json new file mode 100644 index 000000000..1609b8328 --- /dev/null +++ b/assets/entity_statuses.json @@ -0,0 +1,60 @@ +{ + "ADD_SPRINTING_PARTICLES_OR_RESET_SPAWNER_MINECART_SPAWN_DELAY": 1, + "PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES": 3, + "PLAY_ATTACK_SOUND": 4, + "ADD_NEGATIVE_PLAYER_REACTION_PARTICLES": 6, + "ADD_POSITIVE_PLAYER_REACTION_PARTICLES": 7, + "SHAKE_OFF_WATER": 8, + "CONSUME_ITEM": 9, + "SET_SHEEP_EAT_GRASS_TIMER_OR_PRIME_TNT_MINECART": 10, + "LOOK_AT_VILLAGER": 11, + "ADD_VILLAGER_HEART_PARTICLES": 12, + "ADD_VILLAGER_ANGRY_PARTICLES": 13, + "ADD_VILLAGER_HAPPY_PARTICLES": 14, + "ADD_WITCH_PARTICLES": 15, + "PLAY_CURE_ZOMBIE_VILLAGER_SOUND": 16, + "EXPLODE_FIREWORK_CLIENT": 17, + "ADD_BREEDING_PARTICLES": 18, + "RESET_SQUID_THRUST_TIMER": 19, + "PLAY_SPAWN_EFFECTS": 20, + "PLAY_GUARDIAN_ATTACK_SOUND": 21, + "USE_REDUCED_DEBUG_INFO": 22, + "USE_FULL_DEBUG_INFO": 23, + "SET_OP_LEVEL_0": 24, + "SET_OP_LEVEL_1": 25, + "SET_OP_LEVEL_2": 26, + "SET_OP_LEVEL_3": 27, + "SET_OP_LEVEL_4": 28, + "BLOCK_WITH_SHIELD": 29, + "BREAK_SHIELD": 30, + "PULL_HOOKED_ENTITY": 31, + "HIT_ARMOR_STAND": 32, + "STOP_LOOKING_AT_VILLAGER": 34, + "USE_TOTEM_OF_UNDYING": 35, + "ADD_DOLPHIN_HAPPY_VILLAGER_PARTICLES": 38, + "STUN_RAVAGER": 39, + "TAME_OCELOT_FAILED": 40, + "TAME_OCELOT_SUCCESS": 41, + "ADD_SPLASH_PARTICLES": 42, + "CREATE_EATING_PARTICLES": 45, + "ADD_PORTAL_PARTICLES": 46, + "BREAK_MAINHAND": 47, + "BREAK_OFFHAND": 48, + "BREAK_HEAD": 49, + "BREAK_CHEST": 50, + "BREAK_LEGS": 51, + "BREAK_FEET": 52, + "DRIP_HONEY": 53, + "DRIP_RICH_HONEY": 54, + "SWAP_HANDS": 55, + "RESET_WOLF_SHAKE": 56, + "PREPARE_RAM": 58, + "FINISH_RAM": 59, + "ADD_DEATH_PARTICLES": 60, + "EARS_TWITCH": 61, + "SONIC_BOOM": 62, + "START_DIGGING": 63, + "PEEKING": 64, + "BREAK_BODY": 65, + "INVULNERABLE_CREAKING_HIT": 66 +} \ No newline at end of file diff --git a/assets/status_effects.json b/assets/status_effects.json new file mode 100644 index 000000000..d8f4755cc --- /dev/null +++ b/assets/status_effects.json @@ -0,0 +1,41 @@ +[ + "speed", + "slowness", + "haste", + "mining_fatigue", + "strength", + "instant_health", + "instant_damage", + "jump_boost", + "nausea", + "regeneration", + "resistance", + "fire_resistance", + "water_breathing", + "invisibility", + "blindness", + "night_vision", + "hunger", + "weakness", + "poison", + "wither", + "health_boost", + "absorption", + "saturation", + "glowing", + "levitation", + "luck", + "unluck", + "slow_falling", + "conduit_power", + "dolphins_grace", + "bad_omen", + "hero_of_the_village", + "darkness", + "trial_omen", + "raid_omen", + "wind_charged", + "weaving", + "oozing", + "infested" +] \ No newline at end of file diff --git a/assets/world_event.json b/assets/world_event.json index 9e43ac24b..d4f4df763 100644 --- a/assets/world_event.json +++ b/assets/world_event.json @@ -40,7 +40,6 @@ "SKELETON_CONVERTS_TO_STRAY": 1048, "CRAFTER_CRAFTS": 1049, "CRAFTER_FAILS": 1050, - "field_51787": 1051, "COMPOSTER_USED": 1500, "LAVA_EXTINGUISHED": 1501, "REDSTONE_TORCH_BURNS_OUT": 1502, diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 5379b3616..44befdd44 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -2,7 +2,7 @@ name = "pumpkin-fuzz" version = "0.0.0" publish = false -edition = "2021" +edition = "2024" [package.metadata] cargo-fuzz = true diff --git a/pumpkin-api-macros/src/lib.rs b/pumpkin-api-macros/src/lib.rs index dbbd4d4fb..cc7e33dc1 100644 --- a/pumpkin-api-macros/src/lib.rs +++ b/pumpkin-api-macros/src/lib.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; use quote::quote; use std::sync::LazyLock; use std::sync::Mutex; -use syn::{parse_macro_input, parse_quote, ImplItem, ItemFn, ItemImpl, ItemStruct}; +use syn::{ImplItem, ItemFn, ItemImpl, ItemStruct, parse_macro_input, parse_quote}; static PLUGIN_METHODS: LazyLock>> = LazyLock::new(|| Mutex::new(Vec::new())); diff --git a/pumpkin-config/src/lib.rs b/pumpkin-config/src/lib.rs index 7dd87e161..65255e993 100644 --- a/pumpkin-config/src/lib.rs +++ b/pumpkin-config/src/lib.rs @@ -2,7 +2,7 @@ use chunk::ChunkConfig; use log::warn; use logging::LoggingConfig; use pumpkin_util::{Difficulty, GameMode, PermissionLvl}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; use std::{ env, fs, @@ -184,14 +184,15 @@ impl LoadConfiguration for BasicConfiguration { } fn validate(&self) { + let min = unsafe { NonZeroU8::new_unchecked(2) }; + let max = unsafe { NonZeroU8::new_unchecked(32) }; + assert!( - self.view_distance - .ge(unsafe { &NonZeroU8::new_unchecked(2) }), + self.view_distance.ge(&min), "View distance must be at least 2" ); assert!( - self.view_distance - .le(unsafe { &NonZeroU8::new_unchecked(32) }), + self.view_distance.le(&max), "View distance must be less than 32" ); if self.online_mode { diff --git a/pumpkin-config/src/resource_pack.rs b/pumpkin-config/src/resource_pack.rs index 1f011de70..0bc350636 100644 --- a/pumpkin-config/src/resource_pack.rs +++ b/pumpkin-config/src/resource_pack.rs @@ -9,21 +9,28 @@ pub struct ResourcePackConfig { /// The SHA1 hash (40) of the resource pack. pub sha1: String, /// Custom prompt Text component, Leave blank for none - pub message: String, + pub prompt_message: String, /// Will force the Player to accept the resource pack pub force: bool, } impl ResourcePackConfig { pub fn validate(&self) { + if !self.enabled { + return; + } + assert_eq!( !self.url.is_empty(), !self.sha1.is_empty(), "Resource Pack path or Sha1 hash is missing" ); + + let hash_len = self.sha1.len(); assert!( - self.sha1.len() <= 40, - "Resource pack sha1 hash is too long (max. 40)" + hash_len == 40, + "Resource pack sha1 hash is the wrong length (should be 40, is {})", + hash_len ) } } diff --git a/pumpkin-data/build/build.rs b/pumpkin-data/build/build.rs index 922e9b281..c1420d04d 100644 --- a/pumpkin-data/build/build.rs +++ b/pumpkin-data/build/build.rs @@ -8,6 +8,7 @@ mod biome; mod chunk_status; mod damage_type; mod entity_pose; +mod entity_status; mod entity_type; mod fluid; mod game_event; @@ -21,6 +22,7 @@ mod screen; mod sound; mod sound_category; mod spawn_egg; +mod status_effect; mod world_event; pub fn main() { @@ -42,6 +44,8 @@ pub fn main() { write_generated_file(spawn_egg::build(), "spawn_egg.rs"); write_generated_file(item::build(), "item.rs"); write_generated_file(fluid::build(), "fluid.rs"); + write_generated_file(status_effect::build(), "status_effect.rs"); + write_generated_file(entity_status::build(), "entity_status.rs"); } pub fn array_to_tokenstream(array: &[String]) -> TokenStream { diff --git a/pumpkin-data/build/entity_status.rs b/pumpkin-data/build/entity_status.rs new file mode 100644 index 000000000..0b33797a9 --- /dev/null +++ b/pumpkin-data/build/entity_status.rs @@ -0,0 +1,27 @@ +use std::collections::HashMap; + +use heck::ToPascalCase; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +pub(crate) fn build() -> TokenStream { + println!("cargo:rerun-if-changed=../assets/entity_statuses.json"); + + let events: HashMap = + serde_json::from_str(include_str!("../../assets/entity_statuses.json")) + .expect("Failed to parse entity_statuses.json"); + let mut variants = TokenStream::new(); + + for (event, id) in events.iter() { + let name = format_ident!("{}", event.to_pascal_case()); + variants.extend([quote! { + #name = #id, + }]); + } + quote! { + #[repr(u8)] + pub enum EntityStatus { + #variants + } + } +} diff --git a/pumpkin-data/build/entity_type.rs b/pumpkin-data/build/entity_type.rs index 8ee8dc683..8a1b4800a 100644 --- a/pumpkin-data/build/entity_type.rs +++ b/pumpkin-data/build/entity_type.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use proc_macro2::TokenStream; -use quote::{format_ident, quote, ToTokens}; +use quote::{ToTokens, format_ident, quote}; use serde::Deserialize; use syn::LitInt; diff --git a/pumpkin-data/build/item.rs b/pumpkin-data/build/item.rs index 2d0197cab..e22a3c946 100644 --- a/pumpkin-data/build/item.rs +++ b/pumpkin-data/build/item.rs @@ -1,6 +1,6 @@ use heck::ToShoutySnakeCase; use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote, ToTokens}; +use quote::{ToTokens, format_ident, quote}; use syn::{Ident, LitBool, LitFloat, LitInt, LitStr}; include!("../src/tag.rs"); @@ -225,6 +225,7 @@ pub(crate) fn build() -> TokenStream { constants.extend(quote! { pub const #const_ident: Item = Item { id: #id_lit, + registry_key: #name, components: #components_tokens }; }); @@ -240,13 +241,21 @@ pub(crate) fn build() -> TokenStream { quote! { use pumpkin_util::text::TextComponent; + use crate::tag::{Tagable, RegistryKey}; - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Debug)] pub struct Item { pub id: u16, + pub registry_key: &'static str, pub components: ItemComponents, } + impl PartialEq for Item { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } + } + #[derive(Clone, Copy, Debug)] pub struct ItemComponents { pub item_name: Option<&'static str>, @@ -307,7 +316,7 @@ pub(crate) fn build() -> TokenStream { } #[doc = r" Try to parse a Item from a resource location string"] - pub fn from_name(name: &str) -> Option { + pub fn from_registry_key(name: &str) -> Option { match name { #type_from_name _ => None @@ -320,7 +329,18 @@ pub(crate) fn build() -> TokenStream { _ => None } } + } + + impl Tagable for Item { + #[inline] + fn tag_key() -> RegistryKey { + RegistryKey::Item + } + #[inline] + fn registry_key(&self) -> &str { + self.registry_key + } } } } diff --git a/pumpkin-data/build/status_effect.rs b/pumpkin-data/build/status_effect.rs new file mode 100644 index 000000000..cfb825978 --- /dev/null +++ b/pumpkin-data/build/status_effect.rs @@ -0,0 +1,51 @@ +use heck::ToPascalCase; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +pub(crate) fn build() -> TokenStream { + println!("cargo:rerun-if-changed=../assets/status_effects.json"); + + let chunk_status: Vec = + serde_json::from_str(include_str!("../../assets/status_effects.json")) + .expect("Failed to parse status_effects.json"); + let mut variants = TokenStream::new(); + let mut type_from_name = TokenStream::new(); + let mut type_to_name = TokenStream::new(); + + for status in chunk_status.iter() { + let const_ident = format_ident!("{}", status.to_pascal_case()); + let resource_name = status.to_lowercase(); + + variants.extend([quote! { + #const_ident, + }]); + type_from_name.extend(quote! { + #resource_name => Some(Self::#const_ident), + }); + type_to_name.extend(quote! { + Self::#const_ident => #resource_name, + }); + } + quote! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub enum EffectType { + #variants + } + + impl EffectType { + #[doc = r" Try to parse a Effect Type from a resource location string"] + pub fn from_name(name: &str) -> Option { + match name { + #type_from_name + _ => None + } + } + + pub const fn to_name(&self) -> &'static str { + match self { + #type_to_name + } + } + } + } +} diff --git a/pumpkin-data/src/lib.rs b/pumpkin-data/src/lib.rs index b829ac085..a14580a1d 100644 --- a/pumpkin-data/src/lib.rs +++ b/pumpkin-data/src/lib.rs @@ -32,6 +32,8 @@ pub mod game_event { } pub mod entity { + include!(concat!(env!("OUT_DIR"), "/entity_status.rs")); + include!(concat!(env!("OUT_DIR"), "/status_effect.rs")); include!(concat!(env!("OUT_DIR"), "/spawn_egg.rs")); include!(concat!(env!("OUT_DIR"), "/entity_type.rs")); include!(concat!(env!("OUT_DIR"), "/entity_pose.rs")); diff --git a/pumpkin-data/src/tag.rs b/pumpkin-data/src/tag.rs index 0cd26b5d6..9ac94551e 100644 --- a/pumpkin-data/src/tag.rs +++ b/pumpkin-data/src/tag.rs @@ -39,14 +39,25 @@ impl RegistryKey { } } +#[allow(dead_code)] +pub trait Tagable { + fn tag_key() -> RegistryKey; + fn registry_key(&self) -> &str; + + /// Returns none if tag does not exist + fn is_tagged_with(&self, tag: &str) -> Option { + let tag = tag.strip_prefix("#").unwrap_or(tag); + let items = get_tag_values(Self::tag_key(), tag)?; + Some(items.iter().any(|elem| elem == self.registry_key())) + } +} + const TAG_JSON: &str = include_str!("../../assets/tags.json"); -#[expect(clippy::type_complexity)] -pub static TAGS: LazyLock>>>> = +pub static TAGS: LazyLock>>> = LazyLock::new(|| serde_json::from_str(TAG_JSON).expect("Valid tag collections")); -#[allow(dead_code)] -pub fn get_tag_values(tag_category: RegistryKey, tag: &str) -> Option<&Vec>> { +pub fn get_tag_values(tag_category: RegistryKey, tag: &str) -> Option<&Vec> { TAGS.get(&tag_category) .expect("Should deserialize all tag categories") .get(tag) diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index d93ba3d3c..2bb7568f4 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -1,12 +1,20 @@ -use crate::InventoryError; +use crate::{InventoryError, player::SLOT_INDEX_OUTSIDE}; use pumpkin_protocol::server::play::SlotActionType; use pumpkin_world::item::ItemStack; +#[derive(Debug)] pub struct Click { pub slot: Slot, pub click_type: ClickType, } +const BUTTON_CLICK_LEFT: i8 = 0; +const BUTTON_CLICK_RIGHT: i8 = 1; + +const KEY_CLICK_OFFHAND: i8 = 40; +const KEY_CLICK_HOTBAR_START: i8 = 0; +const KEY_CLICK_HOTBAR_END: i8 = 9; + impl Click { pub fn new(mode: SlotActionType, button: i8, slot: i16) -> Result { match mode { @@ -18,7 +26,7 @@ impl Click { click_type: ClickType::CreativePickItem, slot: Slot::Normal(slot.try_into().or(Err(InventoryError::InvalidSlot))?), }), - SlotActionType::Throw => Self::new_drop_item(button), + SlotActionType::Throw => Self::new_drop_item(button, slot), SlotActionType::QuickCraft => Self::new_drag_item(button, slot), SlotActionType::PickupAll => Ok(Self { click_type: ClickType::DoubleClick, @@ -29,15 +37,15 @@ impl Click { fn new_normal_click(button: i8, slot: i16) -> Result { let slot = match slot { - -999 => Slot::OutsideInventory, + SLOT_INDEX_OUTSIDE => Slot::OutsideInventory, _ => { let slot = slot.try_into().unwrap_or(0); Slot::Normal(slot) } }; let button = match button { - 0 => MouseClick::Left, - 1 => MouseClick::Right, + BUTTON_CLICK_LEFT => MouseClick::Left, + BUTTON_CLICK_RIGHT => MouseClick::Right, _ => Err(InventoryError::InvalidPacket)?, }; Ok(Self { @@ -55,8 +63,10 @@ impl Click { fn new_key_click(button: i8, slot: i16) -> Result { let key = match button { - 0..9 => KeyClick::Slot(button.try_into().or(Err(InventoryError::InvalidSlot))?), - 40 => KeyClick::Offhand, + KEY_CLICK_HOTBAR_START..KEY_CLICK_HOTBAR_END => { + KeyClick::Slot(button.try_into().or(Err(InventoryError::InvalidSlot))?) + } + KEY_CLICK_OFFHAND => KeyClick::Offhand, _ => Err(InventoryError::InvalidSlot)?, }; @@ -66,15 +76,18 @@ impl Click { }) } - fn new_drop_item(button: i8) -> Result { - let drop_type = match button { - 0 => DropType::SingleItem, - 1 => DropType::FullStack, - _ => Err(InventoryError::InvalidPacket)?, + fn new_drop_item(button: i8, slot: i16) -> Result { + let drop_type = DropType::from_i8(button)?; + let slot = match slot { + SLOT_INDEX_OUTSIDE => Slot::OutsideInventory, + _ => { + let slot = slot.try_into().unwrap_or(0); + Slot::Normal(slot) + } }; Ok(Self { click_type: ClickType::DropType(drop_type), - slot: Slot::OutsideInventory, + slot, }) } @@ -99,6 +112,7 @@ impl Click { } } +#[derive(Debug)] pub enum ClickType { MouseClick(MouseClick), ShiftClick, @@ -114,27 +128,40 @@ pub enum MouseClick { Right, } +#[derive(Debug)] pub enum KeyClick { Slot(u8), Offhand, } -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub enum Slot { Normal(usize), OutsideInventory, } +#[derive(Debug)] pub enum DropType { SingleItem, FullStack, } + +impl DropType { + fn from_i8(value: i8) -> Result { + Ok(match value { + 0 => Self::SingleItem, + 1 => Self::FullStack, + _ => return Err(InventoryError::InvalidPacket), + }) + } +} + #[derive(Debug, PartialEq)] pub enum MouseDragType { Left, Right, Middle, } -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum MouseDragState { Start(MouseDragType), AddSlot(usize), diff --git a/pumpkin-inventory/src/crafting.rs b/pumpkin-inventory/src/crafting.rs index 0ab0dda0e..91c5664cf 100644 --- a/pumpkin-inventory/src/crafting.rs +++ b/pumpkin-inventory/src/crafting.rs @@ -1,13 +1,13 @@ use pumpkin_data::{ item::Item, - tag::{get_tag_values, RegistryEntryList, RegistryKey, TagType}, + tag::{RegistryEntryList, RegistryKey, TagType, get_tag_values}, }; -use pumpkin_registry::{flatten_3x3, RecipeResult, RECIPES}; +use pumpkin_registry::{RECIPES, RecipeResult, flatten_3x3}; use pumpkin_world::item::ItemStack; use rayon::prelude::*; #[inline(always)] -fn check_ingredient_type(ingredient_type: &TagType, input: ItemStack) -> bool { +fn check_ingredient_type(ingredient_type: &TagType, input: &ItemStack) -> bool { match ingredient_type { TagType::Tag(tag) => { let _items = match get_tag_values(RegistryKey::Item, tag) { @@ -18,11 +18,13 @@ fn check_ingredient_type(ingredient_type: &TagType, input: ItemStack) -> bool { false // items.iter().any(|tag| check_ingredient_type(&tag, input)) } - TagType::Item(item) => Item::from_name(item).is_some_and(|item| item.id == input.item.id), + TagType::Item(item) => { + Item::from_registry_key(item).is_some_and(|item| item.id == input.item.id) + } } } -pub fn check_if_matches_crafting(input: [[Option; 3]; 3]) -> Option { +pub fn check_if_matches_crafting(input: [[Option<&ItemStack>; 3]; 3]) -> Option { let input = flatten_3x3(input); RECIPES .par_iter() @@ -53,18 +55,18 @@ pub fn check_if_matches_crafting(input: [[Option; 3]; 3]) -> Option Some(ItemStack { - item: Item::from_name(id).unwrap(), + item: Item::from_registry_key(id).unwrap(), item_count: 1, }), RecipeResult::Many { id, count, .. } => Some(ItemStack { - item: Item::from_name(id).unwrap(), + item: Item::from_registry_key(id).unwrap(), item_count: *count, }), RecipeResult::Special => None, })? } -fn ingredient_slot_check(recipe_item: &RegistryEntryList, input: ItemStack) -> bool { +fn ingredient_slot_check(recipe_item: &RegistryEntryList, input: &ItemStack) -> bool { match recipe_item { RegistryEntryList::Single(ingredient) => check_ingredient_type(ingredient, input), RegistryEntryList::Many(ingredients) => ingredients @@ -73,7 +75,7 @@ fn ingredient_slot_check(recipe_item: &RegistryEntryList, input: ItemStack) -> b } } fn shapeless_crafting_match( - input: [[Option; 3]; 3], + input: [[Option<&ItemStack>; 3]; 3], pattern: &[[[Option; 3]; 3]], ) -> bool { let mut pattern: Vec = pattern diff --git a/pumpkin-inventory/src/drag_handler.rs b/pumpkin-inventory/src/drag_handler.rs index aa403772b..f3a3b4885 100644 --- a/pumpkin-inventory/src/drag_handler.rs +++ b/pumpkin-inventory/src/drag_handler.rs @@ -71,10 +71,6 @@ impl DragHandler { Err(InventoryError::MultiplePlayersDragging)? } let mut slots = container.all_slots(); - let slots_cloned: Vec> = slots - .iter() - .map(|stack| stack.map(|item| item.to_owned())) - .collect(); let Some(carried_item) = maybe_carried_item else { return Ok(()); }; @@ -83,27 +79,27 @@ impl DragHandler { // Checked in any function that uses this function. MouseDragType::Middle => { for slot in &drag.slots { - *slots[*slot] = *maybe_carried_item; + *slots[*slot] = maybe_carried_item.clone(); } } MouseDragType::Right => { - let mut single_item = *carried_item; - single_item.item_count = 1; - let changing_slots = - drag.possibly_changing_slots(&slots_cloned, carried_item.item.id); - changing_slots.for_each(|slot| { + drag.possibly_changing_slots(slots.as_ref(), carried_item.item.id); + changing_slots.into_iter().for_each(|slot| { if carried_item.item_count != 0 { carried_item.item_count -= 1; if let Some(stack) = &mut slots[slot] { // TODO: Check for stack max here - if stack.item_count + 1 < 64 { + if stack.item_count + 1 < stack.item.components.max_stack_size { stack.item_count += 1; } else { carried_item.item_count += 1; } } else { - *slots[slot] = Some(single_item) + *slots[slot] = Some(ItemStack { + item: carried_item.item.clone(), + item_count: 1, + }) } } }); @@ -116,9 +112,8 @@ impl DragHandler { // TODO: Handle dragging a stack with greater amount than item allows as max unstackable // In that specific case, follow MouseDragType::Right behaviours instead! - let changing_slots = - drag.possibly_changing_slots(&slots_cloned, carried_item.item.id); - let amount_of_slots = changing_slots.clone().count(); + let changing_slots = drag.possibly_changing_slots(&slots, carried_item.item.id); + let amount_of_slots = changing_slots.len(); let (amount_per_slot, remainder) = if amount_of_slots == 0 { // TODO: please work lol (1, 0) @@ -128,9 +123,13 @@ impl DragHandler { carried_item.item_count.rem_euclid(amount_of_slots as u8), ) }; - let mut item_in_each_slot = *carried_item; - item_in_each_slot.item_count = amount_per_slot; - changing_slots.for_each(|slot| *slots[slot] = Some(item_in_each_slot)); + changing_slots.into_iter().for_each(|slot| { + if let Some(stack) = slots[slot].as_mut() { + debug_assert!(stack.item.id == carried_item.item.id); + // TODO: Handle max stack size + stack.item_count += amount_per_slot; + } + }); if remainder > 0 { carried_item.item_count = remainder; @@ -150,24 +149,27 @@ struct Drag { } impl Drag { - fn possibly_changing_slots<'a>( - &'a self, - slots: &'a [Option], + fn possibly_changing_slots( + &self, + slots: &[&mut Option], carried_item_id: u16, - ) -> impl Iterator + 'a + Clone { - self.slots.iter().filter_map(move |slot_index| { - let slot = &slots[*slot_index]; + ) -> Box<[usize]> { + self.slots + .iter() + .filter_map(move |slot_index| { + let slot = &slots[*slot_index]; - match slot { - Some(item_slot) => { - if item_slot.item.id == carried_item_id { - Some(*slot_index) - } else { - None + match slot { + Some(item_slot) => { + if item_slot.item.id == carried_item_id { + Some(*slot_index) + } else { + None + } } + None => Some(*slot_index), } - None => Some(*slot_index), - } - }) + }) + .collect() } } diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index ef2b652e9..6fc2780d4 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -29,7 +29,7 @@ pub trait Container: Sync + Send { mouse_click: MouseClick, taking_crafted: bool, ) -> Result<(), InventoryError> { - let mut all_slots = self.all_slots(); + let all_slots = self.all_slots(); if slot > all_slots.len() { Err(InventoryError::InvalidSlot)? } @@ -50,9 +50,9 @@ pub trait Container: Sync + Send { Ok(()) } - fn all_slots(&mut self) -> Vec<&mut Option>; + fn all_slots(&mut self) -> Box<[&mut Option]>; - fn all_slots_ref(&self) -> Vec>; + fn all_slots_ref(&self) -> Box<[Option<&ItemStack>]>; fn clear_all_slots(&mut self) { let all_slots = self.all_slots(); @@ -61,11 +61,11 @@ pub trait Container: Sync + Send { } } - fn all_combinable_slots(&self) -> Vec> { + fn all_combinable_slots(&self) -> Box<[Option<&ItemStack>]> { self.all_slots_ref() } - fn all_combinable_slots_mut(&mut self) -> Vec<&mut Option> { + fn all_combinable_slots_mut(&mut self) -> Box<[&mut Option]> { self.all_slots() } @@ -85,10 +85,8 @@ pub trait Container: Sync + Send { false } - fn crafted_item_slot(&self) -> Option { - self.all_slots_ref() - .get(self.crafting_output_slot()?)? - .copied() + fn crafted_item_slot(&self) -> Option<&ItemStack> { + *self.all_slots_ref().get(self.crafting_output_slot()?)? } fn recipe_used(&mut self) {} @@ -109,13 +107,13 @@ impl Container for EmptyContainer { ); } - fn all_slots(&mut self) -> Vec<&mut Option> { + fn all_slots(&mut self) -> Box<[&mut Option]> { unreachable!( "you should never be able to get here because this type is always wrapped in an option" ); } - fn all_slots_ref(&self) -> Vec> { + fn all_slots_ref(&self) -> Box<[Option<&ItemStack>]> { unreachable!( "you should never be able to get here because this type is always wrapped in an option" ); @@ -127,19 +125,22 @@ pub fn handle_item_take( item_slot: &mut Option, mouse_click: MouseClick, ) { - let Some(item) = item_slot else { + let Some(item_stack) = item_slot else { return; }; - let mut new_item = *item; + let mut new_item = item_stack.clone(); match mouse_click { MouseClick::Left => { *item_slot = None; } MouseClick::Right => { - let half = item.item_count / 2; - item.item_count -= half; + let half = item_stack.item_count / 2; new_item.item_count = half; + item_stack.item_count -= half; + if item_stack.item_count == 0 { + *item_slot = None; + } } } *carried_item = Some(new_item); @@ -155,22 +156,24 @@ pub fn handle_item_change( if current.item.id == carried.item.id { combine_stacks(carried_slot, current, mouse_click); } else if mouse_click == MouseClick::Left { - let carried = *carried; - *carried_slot = Some(current.to_owned()); - *current_slot = Some(carried.to_owned()); + std::mem::swap(carried_slot, current_slot); } } // Put held stack into empty slot - (None, Some(carried)) => match mouse_click { + (None, Some(carried_item_stack)) => match mouse_click { MouseClick::Left => { - *current_slot = Some(carried.to_owned()); - *carried_slot = None; + std::mem::swap(carried_slot, current_slot); } MouseClick::Right => { - carried.item_count -= 1; - let mut new = *carried; - new.item_count = 1; - *current_slot = Some(new); + let new_stack = ItemStack { + item: carried_item_stack.item.clone(), + item_count: 1, + }; + *current_slot = Some(new_stack); + carried_item_stack.item_count -= 1; + if carried_item_stack.item_count == 0 { + *carried_slot = None; + } } }, // Take stack into carried @@ -188,21 +191,24 @@ pub fn combine_stacks( return; }; + debug_assert!(carried_item.item.id == slot.item.id); + let max_size = carried_item.item.components.max_stack_size; + let carried_change = match mouse_click { MouseClick::Left => carried_item.item_count, MouseClick::Right => 1, }; // TODO: Check for item stack max size here - if slot.item_count + carried_change <= 64 { + if slot.item_count + carried_change <= max_size { slot.item_count += carried_change; carried_item.item_count -= carried_change; if carried_item.item_count == 0 { *carried_slot = None; } } else { - let left_over = slot.item_count + carried_change - 64; - slot.item_count = 64; + let left_over = slot.item_count + carried_change - max_size; + slot.item_count = max_size; carried_item.item_count = left_over; } } @@ -243,24 +249,24 @@ impl<'a> Container for OptionallyCombinedContainer<'a, 'a> { .unwrap_or(self.inventory.window_name()) } - fn all_slots(&mut self) -> Vec<&mut Option> { + fn all_slots(&mut self) -> Box<[&mut Option]> { let slots = match &mut self.container { Some(container) => { - let mut slots = container.all_slots(); + let mut slots = container.all_slots().into_vec(); slots.extend(self.inventory.all_combinable_slots_mut()); - slots + slots.into_boxed_slice() } None => self.inventory.all_slots(), }; slots } - fn all_slots_ref(&self) -> Vec> { + fn all_slots_ref(&self) -> Box<[Option<&ItemStack>]> { match &self.container { Some(container) => { - let mut slots = container.all_slots_ref(); + let mut slots = container.all_slots_ref().into_vec(); slots.extend(self.inventory.all_combinable_slots()); - slots + slots.into_boxed_slice() } None => self.inventory.all_slots_ref(), } diff --git a/pumpkin-inventory/src/open_container.rs b/pumpkin-inventory/src/open_container.rs index a64fb76d3..9089b369c 100644 --- a/pumpkin-inventory/src/open_container.rs +++ b/pumpkin-inventory/src/open_container.rs @@ -1,5 +1,5 @@ -use crate::crafting::check_if_matches_crafting; use crate::Container; +use crate::crafting::check_if_matches_crafting; use pumpkin_data::screen::WindowType; use pumpkin_util::math::position::BlockPos; use pumpkin_world::block::registry::Block; @@ -34,11 +34,7 @@ impl OpenContainer { pub fn remove_player(&mut self, player_id: i32) { if let Some(index) = self.players.iter().enumerate().find_map(|(index, id)| { - if *id == player_id { - Some(index) - } else { - None - } + if *id == player_id { Some(index) } else { None } }) { self.players.remove(index); } @@ -98,7 +94,7 @@ pub struct Chest([Option; 27]); impl Chest { pub fn new() -> Self { - Self([None; 27]) + Self([const { None }; 27]) } } impl Container for Chest { @@ -109,11 +105,11 @@ impl Container for Chest { fn window_name(&self) -> &'static str { "Chest" } - fn all_slots(&mut self) -> Vec<&mut Option> { + fn all_slots(&mut self) -> Box<[&mut Option]> { self.0.iter_mut().collect() } - fn all_slots_ref(&self) -> Vec> { + fn all_slots_ref(&self) -> Box<[Option<&ItemStack>]> { self.0.iter().map(|slot| slot.as_ref()).collect() } } @@ -124,6 +120,12 @@ pub struct CraftingTable { output: Option, } +impl CraftingTable { + const SLOT_OUTPUT: usize = 0; + const SLOT_INPUT_START: usize = 1; + const SLOT_INPUT_END: usize = 9; +} + impl Container for CraftingTable { fn window_type(&self) -> &'static WindowType { &WindowType::Crafting @@ -132,7 +134,7 @@ impl Container for CraftingTable { fn window_name(&self) -> &'static str { "Crafting Table" } - fn all_slots(&mut self) -> Vec<&mut Option> { + fn all_slots(&mut self) -> Box<[&mut Option]> { let slots = vec![&mut self.output]; let slots = slots .into_iter() @@ -141,7 +143,7 @@ impl Container for CraftingTable { slots } - fn all_slots_ref(&self) -> Vec> { + fn all_slots_ref(&self) -> Box<[Option<&ItemStack>]> { let slots = vec![self.output.as_ref()]; let slots = slots .into_iter() @@ -150,28 +152,49 @@ impl Container for CraftingTable { slots } - fn all_combinable_slots(&self) -> Vec> { + fn all_combinable_slots(&self) -> Box<[Option<&ItemStack>]> { self.input.iter().flatten().map(|s| s.as_ref()).collect() } - fn all_combinable_slots_mut(&mut self) -> Vec<&mut Option> { + fn all_combinable_slots_mut(&mut self) -> Box<[&mut Option]> { self.input.iter_mut().flatten().collect() } fn craft(&mut self) -> bool { - let old_output = self.output; - self.output = check_if_matches_crafting(self.input); - old_output != self.output + // TODO: Is there a better way to do this? + let check = [ + [ + self.input[0][0].as_ref(), + self.input[0][1].as_ref(), + self.input[0][2].as_ref(), + ], + [ + self.input[1][0].as_ref(), + self.input[1][1].as_ref(), + self.input[1][2].as_ref(), + ], + [ + self.input[2][0].as_ref(), + self.input[2][1].as_ref(), + self.input[2][2].as_ref(), + ], + ]; + + let new_output = check_if_matches_crafting(check); + let result = new_output != self.output || self.input.iter().flatten().any(|s| s.is_some()) - || self.output.is_some() + || new_output.is_some(); + + self.output = new_output; + result } fn crafting_output_slot(&self) -> Option { - Some(0) + Some(Self::SLOT_OUTPUT) } fn slot_in_crafting_input_slots(&self, slot: &usize) -> bool { - (1..10).contains(slot) + (Self::SLOT_INPUT_START..=Self::SLOT_INPUT_END).contains(slot) } fn recipe_used(&mut self) { self.input.iter_mut().flatten().for_each(|slot| { @@ -201,17 +224,11 @@ impl Container for Furnace { fn window_name(&self) -> &'static str { "Furnace" } - fn all_slots(&mut self) -> Vec<&mut Option> { - let mut slots = vec![&mut self.cook]; - slots.push(&mut self.fuel); - slots.push(&mut self.output); - slots + fn all_slots(&mut self) -> Box<[&mut Option]> { + Box::new([&mut self.cook, &mut self.fuel, &mut self.output]) } - fn all_slots_ref(&self) -> Vec> { - let mut slots = vec![self.cook.as_ref()]; - slots.push(self.fuel.as_ref()); - slots.push(self.output.as_ref()); - slots + fn all_slots_ref(&self) -> Box<[Option<&ItemStack>]> { + Box::new([self.cook.as_ref(), self.fuel.as_ref(), self.output.as_ref()]) } } diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index 5d52bcfb3..d821ee8ea 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -1,10 +1,39 @@ use crate::container_click::MouseClick; use crate::crafting::check_if_matches_crafting; -use crate::{handle_item_change, Container, InventoryError, WindowType}; +use crate::{Container, InventoryError, WindowType, handle_item_change}; +use pumpkin_data::item::Item; use pumpkin_world::item::ItemStack; use std::iter::Chain; use std::slice::IterMut; +/* + Inventory Layout: + - 0: Crafting Output + - 1-4: Crafting Input + - 5-8: Armor + - 9-35: Main Inventory + - 36-44: Hotbar + - 45: Offhand + +*/ + +pub const SLOT_CRAFT_OUTPUT: usize = 0; +pub const SLOT_CRAFT_INPUT_START: usize = 1; +pub const SLOT_CRAFT_INPUT_END: usize = 4; +pub const SLOT_HELM: usize = 5; +pub const SLOT_CHEST: usize = 6; +pub const SLOT_LEG: usize = 7; +pub const SLOT_BOOT: usize = 8; +pub const SLOT_INV_START: usize = 9; +pub const SLOT_INV_END: usize = 35; +pub const SLOT_HOTBAR_START: usize = 36; +pub const SLOT_HOTBAR_END: usize = 44; +pub const SLOT_OFFHAND: usize = 45; + +pub const SLOT_HOTBAR_INDEX: usize = SLOT_HOTBAR_END - SLOT_HOTBAR_START; +pub const SLOT_MAX: usize = SLOT_OFFHAND; +pub const SLOT_INDEX_OUTSIDE: i16 = -999; + pub struct PlayerInventory { // Main Inventory + Hotbar crafting: [Option; 4], @@ -13,7 +42,7 @@ pub struct PlayerInventory { armor: [Option; 4], offhand: Option, // current selected slot in hotbar - pub selected: u32, + pub selected: usize, pub state_id: u32, // Notchian server wraps this value at 100, we can just keep it as a u8 that automatically wraps pub total_opened_containers: i32, @@ -30,10 +59,10 @@ impl PlayerInventory { pub fn new() -> Self { Self { - crafting: [None; 4], + crafting: [const { None }; 4], crafting_output: None, - items: [None; 36], - armor: [None; 4], + items: [const { None }; 36], + armor: [const { None }; 4], offhand: None, // TODO: What when player spawns in with an different index ? selected: 0, @@ -56,7 +85,7 @@ impl PlayerInventory { item_allowed_override: bool, ) -> Result<(), InventoryError> { if item_allowed_override { - if !(0..=45).contains(&slot) { + if !(0..=SLOT_MAX).contains(&slot) { Err(InventoryError::InvalidSlot)? } *self.all_slots()[slot] = item; @@ -75,44 +104,45 @@ impl PlayerInventory { &self, slot: usize, ) -> Result bool>, InventoryError> { - if !(0..=45).contains(&slot) { + if !(0..=SLOT_MAX).contains(&slot) { return Err(InventoryError::InvalidSlot); } Ok(Box::new(match slot { - 0..=4 | 9..=45 => |_| true, - 5 => |item: &ItemStack| item.is_helmet(), - 6 => |item: &ItemStack| item.is_chestplate(), - 7 => |item: &ItemStack| item.is_leggings(), - 8 => |item: &ItemStack| item.is_boots(), + SLOT_CRAFT_OUTPUT..=SLOT_CRAFT_INPUT_END | SLOT_INV_START..=SLOT_OFFHAND => |_| true, + SLOT_HELM => |item: &ItemStack| item.is_helmet(), + SLOT_CHEST => |item: &ItemStack| item.is_chestplate(), + SLOT_LEG => |item: &ItemStack| item.is_leggings(), + SLOT_BOOT => |item: &ItemStack| item.is_boots(), _ => unreachable!(), })) } pub fn get_slot(&mut self, slot: usize) -> Result<&mut Option, InventoryError> { match slot { - 0 => { + SLOT_CRAFT_OUTPUT => { // TODO: Add crafting check here Ok(&mut self.crafting_output) } - 1..=4 => Ok(&mut self.crafting[slot - 1]), - 5..=8 => Ok(&mut self.armor[slot - 5]), - 9..=44 => Ok(&mut self.items[slot - 9]), - 45 => Ok(&mut self.offhand), + SLOT_CRAFT_INPUT_START..=SLOT_CRAFT_INPUT_END => { + Ok(&mut self.crafting[slot - SLOT_CRAFT_INPUT_START]) + } + SLOT_HELM..=SLOT_BOOT => Ok(&mut self.armor[slot - SLOT_HELM]), + SLOT_INV_START..=SLOT_HOTBAR_END => Ok(&mut self.items[slot - SLOT_INV_START]), + SLOT_OFFHAND => Ok(&mut self.offhand), _ => Err(InventoryError::InvalidSlot), } } - pub fn set_selected(&mut self, slot: u32) { - assert!((0..9).contains(&slot)); + pub fn set_selected(&mut self, slot: usize) { + debug_assert!((0..=SLOT_HOTBAR_INDEX).contains(&slot)); self.selected = slot; } - pub fn get_selected(&self) -> u32 { - self.selected + 36 + pub fn get_selected_slot(&self) -> usize { + self.selected + SLOT_HOTBAR_START } - pub fn held_item(&self) -> Option<&ItemStack> { - debug_assert!((0..9).contains(&self.selected)); - self.items[self.selected as usize + 36 - 9].as_ref() + pub fn increment_state_id(&mut self) { + self.state_id = self.state_id % 100 + 1; } pub async fn get_mining_speed(&self, block_name: &str) -> f32 { @@ -120,9 +150,16 @@ impl PlayerInventory { .map_or_else(|| 1.0, |e| e.get_speed(block_name)) } + //NOTE: We actually want &mut Option instead of Option<&mut> pub fn held_item_mut(&mut self) -> &mut Option { - debug_assert!((0..9).contains(&self.selected)); - &mut self.items[self.selected as usize + 36 - 9] + debug_assert!((0..=SLOT_HOTBAR_INDEX).contains(&self.selected)); + &mut self.items[self.get_selected_slot() - SLOT_INV_START] + } + + #[inline] + pub fn held_item(&self) -> Option<&ItemStack> { + debug_assert!((0..=SLOT_HOTBAR_INDEX).contains(&self.selected)); + self.items[self.get_selected_slot() - SLOT_INV_START].as_ref() } pub fn decrease_current_stack(&mut self, amount: u8) -> bool { @@ -137,69 +174,105 @@ impl PlayerInventory { false } - pub fn get_slot_with_item(&self, item_id: u16, max_stack: u8) -> Option { - for slot in 9..=44 { - match &self.items[slot - 9] { - Some(item) if item.item.id == item_id && item.item_count <= max_stack => { - return Some(slot) - } - _ => continue, + pub fn get_empty_hotbar_slot(&self) -> usize { + if self.held_item().is_none() { + return self.selected; + } + + for slot in SLOT_HOTBAR_START..=SLOT_HOTBAR_END { + if self.items[slot - SLOT_INV_START].is_none() { + return slot - SLOT_HOTBAR_START; } } - None + self.selected } - /// Checks if we can merge an existing item into an Stack or if a any new Slot is empty - pub fn collect_item_slot(&self, item_id: u16) -> Option { - // Lets try to merge first - // TODO: Max stack size - if let Some(stack) = self.get_slot_with_item(item_id, 64) { - return Some(stack); + pub fn get_slot_filtered(&self, filter: &F) -> Option + where + F: Fn(Option<&ItemStack>) -> bool, + { + // Check selected slot + if filter(self.items[self.get_selected_slot() - SLOT_INV_START].as_ref()) { + Some(self.get_selected_slot()) + } + // Check hotbar slots (27-35) first + else if let Some(index) = self.items + [SLOT_HOTBAR_START - SLOT_INV_START..=SLOT_HOTBAR_END - SLOT_INV_START] + .iter() + .enumerate() + .position(|(index, item_stack)| index != self.selected && filter(item_stack.as_ref())) + { + Some(index + SLOT_HOTBAR_START) } - if let Some(empty) = self.get_empty_slot() { - return Some(empty); + // Then check main inventory slots (0-26) + else if let Some(index) = self.items[0..=SLOT_INV_END - SLOT_INV_START] + .iter() + .position(|item_stack| filter(item_stack.as_ref())) + { + Some(index + SLOT_INV_START) + } + // Check offhand + else if filter(self.offhand.as_ref()) { + Some(SLOT_OFFHAND) + } else { + None } - None } - pub fn get_empty_hotbar_slot(&self) -> u32 { - if self.items[self.selected as usize + 36 - 9].is_none() { - return self.selected; - } + pub fn get_nonfull_slot_with_item(&self, item_id: u16) -> Option { + let max_stack = Item::from_id(item_id) + .expect("We passed an invalid item id") + .components + .max_stack_size; + + self.get_slot_filtered(&|item_stack| { + item_stack.is_some_and(|item_stack| { + item_stack.item.id == item_id && item_stack.item_count < max_stack + }) + }) + } - for slot in 0..9 { - if self.items[slot + 36 - 9].is_none() { - return slot as u32; - } - } + /// Returns a slot that has an item with less than the max stack size, if none, returns an empty + /// slot, if none, returns None + pub fn get_pickup_item_slot(&self, item_id: u16) -> Option { + self.get_nonfull_slot_with_item(item_id) + .or_else(|| self.get_empty_slot()) + } - self.selected + pub fn get_slot_with_item(&self, item_id: u16) -> Option { + self.get_slot_filtered(&|item_stack| { + item_stack.is_some_and(|item_stack| item_stack.item.id == item_id) + }) } pub fn get_empty_slot(&self) -> Option { + self.get_slot_filtered(&|item_stack| item_stack.is_none()) + } + + pub fn get_empty_slot_no_order(&self) -> Option { self.items .iter() .position(|slot| slot.is_none()) - .map(|index| index + 9) + .map(|index| index + SLOT_INV_START) } - pub fn slots(&self) -> Vec> { + pub fn slots(&self) -> Box<[Option<&ItemStack>]> { let mut slots = vec![self.crafting_output.as_ref()]; slots.extend(self.crafting.iter().map(|c| c.as_ref())); slots.extend(self.armor.iter().map(|c| c.as_ref())); slots.extend(self.items.iter().map(|c| c.as_ref())); slots.push(self.offhand.as_ref()); - slots + slots.into_boxed_slice() } - pub fn slots_mut(&mut self) -> Vec<&mut Option> { + pub fn slots_mut(&mut self) -> Box<[&mut Option]> { let mut slots = vec![&mut self.crafting_output]; slots.extend(self.crafting.iter_mut()); slots.extend(self.armor.iter_mut()); slots.extend(self.items.iter_mut()); slots.push(&mut self.offhand); - slots + slots.into_boxed_slice() } pub fn iter_items_mut(&mut self) -> IterMut> { @@ -209,7 +282,7 @@ impl PlayerInventory { pub fn slots_with_hotbar_first( &mut self, ) -> Chain>, IterMut>> { - let (items, hotbar) = self.items.split_at_mut(27); + let (items, hotbar) = self.items.split_at_mut(SLOT_HOTBAR_START - SLOT_INV_START); hotbar.iter_mut().chain(items) } } @@ -234,43 +307,47 @@ impl Container for PlayerInventory { let slot_condition = self.slot_condition(slot)?; let item_slot = self.get_slot(slot)?; if let Some(item) = carried_slot { + debug_assert!( + item.item_count > 0, + "We aren't setting the stack to None somewhere" + ); if slot_condition(item) { if invert { handle_item_change(item_slot, carried_slot, mouse_click); - return Ok(()); + } else { + handle_item_change(carried_slot, item_slot, mouse_click); } - handle_item_change(carried_slot, item_slot, mouse_click); + } else { + return Err(InventoryError::InvalidSlot); } + } else if invert { + handle_item_change(item_slot, carried_slot, mouse_click); } else { - if invert { - handle_item_change(item_slot, carried_slot, mouse_click); - return Ok(()); - } handle_item_change(carried_slot, item_slot, mouse_click) } Ok(()) } - fn all_slots(&mut self) -> Vec<&mut Option> { + fn all_slots(&mut self) -> Box<[&mut Option]> { self.slots_mut() } - fn all_slots_ref(&self) -> Vec> { + fn all_slots_ref(&self) -> Box<[Option<&ItemStack>]> { self.slots() } - fn all_combinable_slots(&self) -> Vec> { + fn all_combinable_slots(&self) -> Box<[Option<&ItemStack>]> { self.items.iter().map(|item| item.as_ref()).collect() } - fn all_combinable_slots_mut(&mut self) -> Vec<&mut Option> { + fn all_combinable_slots_mut(&mut self) -> Box<[&mut Option]> { self.items.iter_mut().collect() } fn craft(&mut self) -> bool { - let v1 = [self.crafting[0], self.crafting[1], None]; - let v2 = [self.crafting[2], self.crafting[3], None]; - let v3 = [None; 3]; + let v1 = [self.crafting[0].as_ref(), self.crafting[1].as_ref(), None]; + let v2 = [self.crafting[2].as_ref(), self.crafting[3].as_ref(), None]; + let v3 = [const { None }; 3]; let together = [v1, v2, v3]; self.crafting_output = check_if_matches_crafting(together); @@ -278,10 +355,10 @@ impl Container for PlayerInventory { } fn crafting_output_slot(&self) -> Option { - Some(0) + Some(SLOT_CRAFT_OUTPUT) } fn slot_in_crafting_input_slots(&self, slot: &usize) -> bool { - (1..=4).contains(slot) + (SLOT_CRAFT_INPUT_START..=SLOT_CRAFT_INPUT_END).contains(slot) } } diff --git a/pumpkin-inventory/src/window_property.rs b/pumpkin-inventory/src/window_property.rs index 9c7a1cc24..8d075255c 100644 --- a/pumpkin-inventory/src/window_property.rs +++ b/pumpkin-inventory/src/window_property.rs @@ -33,6 +33,7 @@ pub enum EnchantmentTable { EnchantmentLevel { slot: u8 }, } +// TODO: No more magic numbers impl WindowPropertyTrait for EnchantmentTable { fn to_id(self) -> i16 { use EnchantmentTable::*; diff --git a/pumpkin-macros/src/lib.rs b/pumpkin-macros/src/lib.rs index 57adb0b66..15983195d 100644 --- a/pumpkin-macros/src/lib.rs +++ b/pumpkin-macros/src/lib.rs @@ -3,8 +3,9 @@ use proc_macro::TokenStream; use pumpkin_data::item::Item; use quote::quote; use syn::{ + Block, Expr, Field, Fields, ItemStruct, Stmt, parse::{Nothing, Parser}, - parse_macro_input, Block, Expr, Field, Fields, ItemStruct, Stmt, + parse_macro_input, }; extern crate proc_macro; @@ -153,7 +154,7 @@ pub fn send_cancellable(input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn client_packet(input: TokenStream, item: TokenStream) -> TokenStream { +pub fn packet(input: TokenStream, item: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap(); let name = &ast.ident; let (impl_generics, ty_generics, _) = ast.generics.split_for_impl(); @@ -161,33 +162,14 @@ pub fn client_packet(input: TokenStream, item: TokenStream) -> TokenStream { let input: proc_macro2::TokenStream = input.into(); let item: proc_macro2::TokenStream = item.into(); - let gen = quote! { + let code = quote! { #item impl #impl_generics crate::bytebuf::packet::Packet for #name #ty_generics { const PACKET_ID: i32 = #input; } }; - gen.into() -} - -#[proc_macro_attribute] -pub fn server_packet(input: TokenStream, item: TokenStream) -> TokenStream { - let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap(); - let name = &ast.ident; - let (impl_generics, ty_generics, _) = ast.generics.split_for_impl(); - - let input: proc_macro2::TokenStream = input.into(); - let item: proc_macro2::TokenStream = item.into(); - - let gen = quote! { - #item - impl #impl_generics crate::bytebuf::packet::Packet for #name #ty_generics { - const PACKET_ID: i32 = #input; - } - }; - - gen.into() + code.into() } #[proc_macro_attribute] @@ -205,7 +187,7 @@ pub fn pumpkin_block(input: TokenStream, item: TokenStream) -> TokenStream { let item: proc_macro2::TokenStream = item.into(); - let gen = quote! { + let code = quote! { #item impl #impl_generics crate::block::pumpkin_block::BlockMetadata for #name #ty_generics { const NAMESPACE: &'static str = #namespace; @@ -213,7 +195,7 @@ pub fn pumpkin_block(input: TokenStream, item: TokenStream) -> TokenStream { } }; - gen.into() + code.into() } #[proc_macro_attribute] @@ -224,19 +206,19 @@ pub fn pumpkin_item(input: TokenStream, item: TokenStream) -> TokenStream { let input_string = input.to_string(); let packet_name = input_string.trim_matches('"'); - let item_id = Item::from_name(packet_name).unwrap(); + let item_id = Item::from_registry_key(packet_name).unwrap(); let id = item_id.id; let item: proc_macro2::TokenStream = item.into(); - let gen = quote! { + let code = quote! { #item impl #impl_generics crate::item::pumpkin_item::ItemMetadata for #name #ty_generics { const ID: u16 = #id; } }; - gen.into() + code.into() } #[proc_macro_attribute] @@ -351,7 +333,7 @@ pub fn block_property(input: TokenStream, item: TokenStream) -> TokenStream { } }; - let gen = quote! { + let code = quote! { #item impl #impl_generics crate::block::properties::BlockPropertyMetadata for #name #ty_generics { fn name(&self) -> &'static str { @@ -372,7 +354,7 @@ pub fn block_property(input: TokenStream, item: TokenStream) -> TokenStream { #extra }; - gen.into() + code.into() } mod block_state; diff --git a/pumpkin-nbt/src/compound.rs b/pumpkin-nbt/src/compound.rs index 0d0cbe4d4..ef6cd40ad 100644 --- a/pumpkin-nbt/src/compound.rs +++ b/pumpkin-nbt/src/compound.rs @@ -1,7 +1,7 @@ use crate::deserializer::ReadAdaptor; use crate::serializer::WriteAdaptor; use crate::tag::NbtTag; -use crate::{get_nbt_string, Error, Nbt, END_ID}; +use crate::{END_ID, Error, Nbt, get_nbt_string}; use std::io::{ErrorKind, Read, Write}; use std::vec::IntoIter; diff --git a/pumpkin-nbt/src/deserializer.rs b/pumpkin-nbt/src/deserializer.rs index 6331755cc..3d235762d 100644 --- a/pumpkin-nbt/src/deserializer.rs +++ b/pumpkin-nbt/src/deserializer.rs @@ -1,7 +1,7 @@ use crate::*; use io::Read; use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor}; -use serde::{forward_to_deserialize_any, Deserialize}; +use serde::{Deserialize, forward_to_deserialize_any}; pub type Result = std::result::Result; diff --git a/pumpkin-nbt/src/lib.rs b/pumpkin-nbt/src/lib.rs index bd6edbe57..1d935282a 100644 --- a/pumpkin-nbt/src/lib.rs +++ b/pumpkin-nbt/src/lib.rs @@ -210,13 +210,13 @@ impl_array!(nbt_byte_array, NBT_BYTE_ARRAY_TAG); #[cfg(test)] mod test { + use crate::Error; use crate::deserializer::from_bytes; use crate::nbt_byte_array; use crate::nbt_int_array; use crate::nbt_long_array; use crate::serializer::to_bytes; use crate::serializer::to_bytes_named; - use crate::Error; use crate::{deserializer::from_bytes_unnamed, serializer::to_bytes_unnamed}; use serde::{Deserialize, Serialize}; diff --git a/pumpkin-nbt/src/serializer.rs b/pumpkin-nbt/src/serializer.rs index fdc6f9c20..65252799c 100644 --- a/pumpkin-nbt/src/serializer.rs +++ b/pumpkin-nbt/src/serializer.rs @@ -1,10 +1,10 @@ use serde::ser::Impossible; -use serde::{ser, Serialize}; +use serde::{Serialize, ser}; use std::io::Write; use crate::tag::NbtTag; use crate::{ - Error, BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, FLOAT_ID, INT_ARRAY_ID, INT_ID, + BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, Error, FLOAT_ID, INT_ARRAY_ID, INT_ID, LIST_ID, LONG_ARRAY_ID, LONG_ID, NBT_ARRAY_TAG, NBT_BYTE_ARRAY_TAG, NBT_INT_ARRAY_TAG, NBT_LONG_ARRAY_TAG, SHORT_ID, STRING_ID, }; @@ -393,7 +393,7 @@ impl ser::Serializer for &mut Serializer { _ => { return Err(Error::SerdeError( "Array supports only byte, int, long".to_string(), - )) + )); } }; diff --git a/pumpkin-protocol/src/bytebuf/mod.rs b/pumpkin-protocol/src/bytebuf/mod.rs index 54836a706..585a57235 100644 --- a/pumpkin-protocol/src/bytebuf/mod.rs +++ b/pumpkin-protocol/src/bytebuf/mod.rs @@ -1,11 +1,11 @@ use core::str; use crate::{ + FixedBitSet, codec::{ - bit_set::BitSet, identifier::Identifier, var_int::VarInt, var_long::VarLong, Codec, - DecodeError, + Codec, DecodeError, bit_set::BitSet, identifier::Identifier, var_int::VarInt, + var_long::VarLong, }, - FixedBitSet, }; use bytes::{Buf, BufMut}; @@ -279,8 +279,8 @@ mod test { use serde::{Deserialize, Serialize}; use crate::{ - bytebuf::{deserializer, serializer}, VarInt, + bytebuf::{deserializer, serializer}, }; #[test] diff --git a/pumpkin-protocol/src/bytebuf/packet.rs b/pumpkin-protocol/src/bytebuf/packet.rs index 6534033eb..fef08c480 100644 --- a/pumpkin-protocol/src/bytebuf/packet.rs +++ b/pumpkin-protocol/src/bytebuf/packet.rs @@ -1,9 +1,9 @@ use bytes::{Buf, BufMut}; -use serde::{de::DeserializeOwned, Serialize}; +use serde::{Serialize, de::DeserializeOwned}; -use crate::{codec::var_int::VarIntType, ClientPacket, ServerPacket}; +use crate::{ClientPacket, ServerPacket, codec::var_int::VarIntType}; -use super::{deserializer, serializer, ReadingError}; +use super::{ReadingError, deserializer, serializer}; pub trait Packet { const PACKET_ID: VarIntType; diff --git a/pumpkin-protocol/src/bytebuf/serializer.rs b/pumpkin-protocol/src/bytebuf/serializer.rs index 3d3afb55a..45f635945 100644 --- a/pumpkin-protocol/src/bytebuf/serializer.rs +++ b/pumpkin-protocol/src/bytebuf/serializer.rs @@ -2,8 +2,8 @@ use std::fmt::Display; use bytes::BufMut; use serde::{ - ser::{self}, Serialize, + ser::{self}, }; use thiserror::Error; @@ -207,7 +207,7 @@ impl ser::Serializer for &mut Serializer { unimplemented!() } fn serialize_unit_struct(self, _name: &'static str) -> Result { - todo!() + Ok(()) } fn serialize_unit_variant( self, @@ -219,6 +219,9 @@ impl ser::Serializer for &mut Serializer { self.output.put_var_int(&variant_index.into()); Ok(()) } + fn is_human_readable(&self) -> bool { + false + } } impl ser::SerializeSeq for &mut Serializer { diff --git a/pumpkin-protocol/src/client/config/add_resource_pack.rs b/pumpkin-protocol/src/client/config/add_resource_pack.rs index d9b934ed9..ec5972cee 100644 --- a/pumpkin-protocol/src/client/config/add_resource_pack.rs +++ b/pumpkin-protocol/src/client/config/add_resource_pack.rs @@ -1,14 +1,15 @@ use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use pumpkin_data::packet::clientbound::CONFIG_RESOURCE_PACK_PUSH; #[derive(Serialize)] -#[client_packet(CONFIG_RESOURCE_PACK_PUSH)] +#[packet(CONFIG_RESOURCE_PACK_PUSH)] pub struct CConfigAddResourcePack<'a> { - uuid: uuid::Uuid, + #[serde(with = "uuid::serde::compact")] + uuid: &'a uuid::Uuid, url: &'a str, hash: &'a str, // max 40 forced: bool, @@ -17,7 +18,7 @@ pub struct CConfigAddResourcePack<'a> { impl<'a> CConfigAddResourcePack<'a> { pub fn new( - uuid: uuid::Uuid, + uuid: &'a uuid::Uuid, url: &'a str, hash: &'a str, forced: bool, diff --git a/pumpkin-protocol/src/client/config/config_disconnect.rs b/pumpkin-protocol/src/client/config/config_disconnect.rs index 65e86a191..5b07b6ea8 100644 --- a/pumpkin-protocol/src/client/config/config_disconnect.rs +++ b/pumpkin-protocol/src/client/config/config_disconnect.rs @@ -1,11 +1,11 @@ -use pumpkin_macros::client_packet; - use pumpkin_data::packet::clientbound::CONFIG_DISCONNECT; +use pumpkin_macros::packet; +use serde::Deserialize; -#[derive(serde::Serialize)] -#[client_packet(CONFIG_DISCONNECT)] +#[derive(serde::Serialize, Deserialize)] +#[packet(CONFIG_DISCONNECT)] pub struct CConfigDisconnect<'a> { - reason: &'a str, + pub reason: &'a str, } impl<'a> CConfigDisconnect<'a> { diff --git a/pumpkin-protocol/src/client/config/cookie_request.rs b/pumpkin-protocol/src/client/config/cookie_request.rs index f32011fdc..39b15587c 100644 --- a/pumpkin-protocol/src/client/config/cookie_request.rs +++ b/pumpkin-protocol/src/client/config/cookie_request.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::CONFIG_COOKIE_REQUEST; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use crate::codec::identifier::Identifier; #[derive(serde::Serialize)] -#[client_packet(CONFIG_COOKIE_REQUEST)] +#[packet(CONFIG_COOKIE_REQUEST)] /// Requests a cookie that was previously stored. pub struct CCookieRequest<'a> { - key: &'a Identifier, + pub key: &'a Identifier, } impl<'a> CCookieRequest<'a> { diff --git a/pumpkin-protocol/src/client/config/finish_config.rs b/pumpkin-protocol/src/client/config/finish_config.rs index 7dc0d978d..74e0d7085 100644 --- a/pumpkin-protocol/src/client/config/finish_config.rs +++ b/pumpkin-protocol/src/client/config/finish_config.rs @@ -1,18 +1,7 @@ use pumpkin_data::packet::clientbound::CONFIG_FINISH_CONFIGURATION; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; +use serde::Serialize; -#[derive(serde::Serialize)] -#[client_packet(CONFIG_FINISH_CONFIGURATION)] -pub struct CFinishConfig {} - -impl Default for CFinishConfig { - fn default() -> Self { - Self::new() - } -} - -impl CFinishConfig { - pub fn new() -> Self { - Self {} - } -} +#[derive(Serialize)] +#[packet(CONFIG_FINISH_CONFIGURATION)] +pub struct CFinishConfig; diff --git a/pumpkin-protocol/src/client/config/known_packs.rs b/pumpkin-protocol/src/client/config/known_packs.rs index 344750255..ce3714781 100644 --- a/pumpkin-protocol/src/client/config/known_packs.rs +++ b/pumpkin-protocol/src/client/config/known_packs.rs @@ -1,12 +1,12 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::CONFIG_SELECT_KNOWN_PACKS; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; -use crate::{bytebuf::ByteBufMut, ClientPacket, KnownPack}; +use crate::{ClientPacket, KnownPack, bytebuf::ByteBufMut}; -#[client_packet(CONFIG_SELECT_KNOWN_PACKS)] +#[packet(CONFIG_SELECT_KNOWN_PACKS)] pub struct CKnownPacks<'a> { - known_packs: &'a [KnownPack<'a>], + pub known_packs: &'a [KnownPack<'a>], } impl<'a> CKnownPacks<'a> { diff --git a/pumpkin-protocol/src/client/config/plugin_message.rs b/pumpkin-protocol/src/client/config/plugin_message.rs index 95464bc70..cb7b986ab 100644 --- a/pumpkin-protocol/src/client/config/plugin_message.rs +++ b/pumpkin-protocol/src/client/config/plugin_message.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::CONFIG_CUSTOM_PAYLOAD; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(CONFIG_CUSTOM_PAYLOAD)] +#[packet(CONFIG_CUSTOM_PAYLOAD)] pub struct CPluginMessage<'a> { - channel: &'a str, - data: &'a [u8], + pub channel: &'a str, + pub data: &'a [u8], } impl<'a> CPluginMessage<'a> { diff --git a/pumpkin-protocol/src/client/config/registry_data.rs b/pumpkin-protocol/src/client/config/registry_data.rs index 0733097bd..fa4164263 100644 --- a/pumpkin-protocol/src/client/config/registry_data.rs +++ b/pumpkin-protocol/src/client/config/registry_data.rs @@ -1,14 +1,14 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::CONFIG_REGISTRY_DATA; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; -use crate::{bytebuf::ByteBufMut, codec::identifier::Identifier, ClientPacket}; +use crate::{ClientPacket, bytebuf::ByteBufMut, codec::identifier::Identifier}; -#[client_packet(CONFIG_REGISTRY_DATA)] +#[packet(CONFIG_REGISTRY_DATA)] pub struct CRegistryData<'a> { - registry_id: &'a Identifier, - entries: &'a [RegistryEntry], + pub registry_id: &'a Identifier, + pub entries: &'a [RegistryEntry], } impl<'a> CRegistryData<'a> { diff --git a/pumpkin-protocol/src/client/config/server_links.rs b/pumpkin-protocol/src/client/config/server_links.rs index 32bf22cdf..923493ff2 100644 --- a/pumpkin-protocol/src/client/config/server_links.rs +++ b/pumpkin-protocol/src/client/config/server_links.rs @@ -1,10 +1,10 @@ use crate::{Link, VarInt}; use pumpkin_data::packet::clientbound::CONFIG_SERVER_LINKS; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(CONFIG_SERVER_LINKS)] +#[packet(CONFIG_SERVER_LINKS)] pub struct CConfigServerLinks<'a> { links_count: &'a VarInt, links: &'a [Link<'a>], diff --git a/pumpkin-protocol/src/client/config/store_cookie.rs b/pumpkin-protocol/src/client/config/store_cookie.rs index e6b283316..38788d42e 100644 --- a/pumpkin-protocol/src/client/config/store_cookie.rs +++ b/pumpkin-protocol/src/client/config/store_cookie.rs @@ -1,9 +1,9 @@ -use crate::{codec::identifier::Identifier, VarInt}; +use crate::{VarInt, codec::identifier::Identifier}; use pumpkin_data::packet::clientbound::CONFIG_STORE_COOKIE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; #[derive(serde::Serialize)] -#[client_packet(CONFIG_STORE_COOKIE)] +#[packet(CONFIG_STORE_COOKIE)] /// Stores some arbitrary data on the client, which persists between server transfers. /// The Notchian (vanilla) client only accepts cookies of up to 5 kiB in size. pub struct CStoreCookie<'a> { diff --git a/pumpkin-protocol/src/client/config/transfer.rs b/pumpkin-protocol/src/client/config/transfer.rs index c7aa76fcf..d580124ac 100644 --- a/pumpkin-protocol/src/client/config/transfer.rs +++ b/pumpkin-protocol/src/client/config/transfer.rs @@ -1,13 +1,13 @@ use crate::VarInt; use pumpkin_data::packet::clientbound::CONFIG_TRANSFER; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(CONFIG_TRANSFER)] +#[packet(CONFIG_TRANSFER)] pub struct CTransfer<'a> { - host: &'a str, - port: &'a VarInt, + pub host: &'a str, + pub port: &'a VarInt, } impl<'a> CTransfer<'a> { diff --git a/pumpkin-protocol/src/client/config/update_tags.rs b/pumpkin-protocol/src/client/config/update_tags.rs index d2c17956d..9f7fe8bbb 100644 --- a/pumpkin-protocol/src/client/config/update_tags.rs +++ b/pumpkin-protocol/src/client/config/update_tags.rs @@ -4,16 +4,16 @@ use pumpkin_data::{ packet::clientbound::CONFIG_UPDATE_TAGS, tag::{RegistryKey, TAGS}, }; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_world::block::registry; use crate::{ + ClientPacket, bytebuf::ByteBufMut, codec::{identifier::Identifier, var_int::VarInt}, - ClientPacket, }; -#[client_packet(CONFIG_UPDATE_TAGS)] +#[packet(CONFIG_UPDATE_TAGS)] pub struct CUpdateTags<'a> { tags: &'a [pumpkin_data::tag::RegistryKey], } @@ -34,18 +34,14 @@ impl ClientPacket for CUpdateTags<'_> { for (key, values) in values.iter() { // This is technically a Identifier but same thing p.put_string_len(key, u16::MAX as usize); - p.put_list(values, |p, v| { - if let Some(string_id) = v { - let id = match registry_key { - RegistryKey::Block => registry::get_block(string_id).unwrap().id as i32, - RegistryKey::Fluid => { - Fluid::ident_to_fluid_id(string_id).unwrap() as i32 - } - _ => unimplemented!(), - }; + p.put_list(values, |p, string_id| { + let id = match registry_key { + RegistryKey::Block => registry::get_block(string_id).unwrap().id as i32, + RegistryKey::Fluid => Fluid::ident_to_fluid_id(string_id).unwrap() as i32, + _ => unimplemented!(), + }; - p.put_var_int(&VarInt::from(id)); - } + p.put_var_int(&VarInt::from(id)); }); } }); diff --git a/pumpkin-protocol/src/client/login/cookie_request.rs b/pumpkin-protocol/src/client/login/cookie_request.rs index 0d8564a4c..e08844892 100644 --- a/pumpkin-protocol/src/client/login/cookie_request.rs +++ b/pumpkin-protocol/src/client/login/cookie_request.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::LOGIN_COOKIE_REQUEST; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::codec::identifier::Identifier; #[derive(Serialize)] -#[client_packet(LOGIN_COOKIE_REQUEST)] +#[packet(LOGIN_COOKIE_REQUEST)] /// Requests a cookie that was previously stored. pub struct CLoginCookieRequest<'a> { key: &'a Identifier, diff --git a/pumpkin-protocol/src/client/login/encryption_request.rs b/pumpkin-protocol/src/client/login/encryption_request.rs index 91ac9cc00..b67fdccbf 100644 --- a/pumpkin-protocol/src/client/login/encryption_request.rs +++ b/pumpkin-protocol/src/client/login/encryption_request.rs @@ -1,18 +1,18 @@ use pumpkin_data::packet::clientbound::LOGIN_HELLO; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; use crate::VarInt; -#[derive(Serialize)] -#[client_packet(LOGIN_HELLO)] +#[derive(Serialize, Deserialize)] +#[packet(LOGIN_HELLO)] pub struct CEncryptionRequest<'a> { - server_id: &'a str, // 20 - public_key_length: VarInt, - public_key: &'a [u8], - verify_token_length: VarInt, - verify_token: &'a [u8], - should_authenticate: bool, + pub server_id: &'a str, // 20 + pub public_key_length: VarInt, + pub public_key: &'a [u8], + pub verify_token_length: VarInt, + pub verify_token: &'a [u8], + pub should_authenticate: bool, } impl<'a> CEncryptionRequest<'a> { diff --git a/pumpkin-protocol/src/client/login/login_disconnect.rs b/pumpkin-protocol/src/client/login/login_disconnect.rs index b2499f776..baed47c6e 100644 --- a/pumpkin-protocol/src/client/login/login_disconnect.rs +++ b/pumpkin-protocol/src/client/login/login_disconnect.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::LOGIN_LOGIN_DISCONNECT; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(LOGIN_LOGIN_DISCONNECT)] +#[derive(Serialize, Deserialize)] +#[packet(LOGIN_LOGIN_DISCONNECT)] pub struct CLoginDisconnect<'a> { - json_reason: &'a str, + pub json_reason: &'a str, } impl<'a> CLoginDisconnect<'a> { diff --git a/pumpkin-protocol/src/client/login/login_success.rs b/pumpkin-protocol/src/client/login/login_success.rs index a581128c4..50f1cc3e6 100644 --- a/pumpkin-protocol/src/client/login/login_success.rs +++ b/pumpkin-protocol/src/client/login/login_success.rs @@ -1,10 +1,10 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::LOGIN_LOGIN_FINISHED; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; -use crate::{bytebuf::ByteBufMut, ClientPacket, Property}; +use crate::{ClientPacket, Property, bytebuf::ByteBufMut}; -#[client_packet(LOGIN_LOGIN_FINISHED)] +#[packet(LOGIN_LOGIN_FINISHED)] pub struct CLoginSuccess<'a> { pub uuid: &'a uuid::Uuid, pub username: &'a str, // 16 diff --git a/pumpkin-protocol/src/client/login/plugin_request.rs b/pumpkin-protocol/src/client/login/plugin_request.rs index 97fea6330..0c7ae9013 100644 --- a/pumpkin-protocol/src/client/login/plugin_request.rs +++ b/pumpkin-protocol/src/client/login/plugin_request.rs @@ -1,15 +1,15 @@ use pumpkin_data::packet::clientbound::LOGIN_CUSTOM_QUERY; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(LOGIN_CUSTOM_QUERY)] +#[packet(LOGIN_CUSTOM_QUERY)] pub struct CLoginPluginRequest<'a> { - message_id: VarInt, - channel: &'a str, - data: &'a [u8], + pub message_id: VarInt, + pub channel: &'a str, + pub data: &'a [u8], } impl<'a> CLoginPluginRequest<'a> { diff --git a/pumpkin-protocol/src/client/login/set_compression.rs b/pumpkin-protocol/src/client/login/set_compression.rs index 3b572f000..2dbb858d1 100644 --- a/pumpkin-protocol/src/client/login/set_compression.rs +++ b/pumpkin-protocol/src/client/login/set_compression.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::LOGIN_LOGIN_COMPRESSION; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; use crate::VarInt; -#[derive(Serialize)] -#[client_packet(LOGIN_LOGIN_COMPRESSION)] +#[derive(Serialize, Deserialize)] +#[packet(LOGIN_LOGIN_COMPRESSION)] pub struct CSetCompression { - threshold: VarInt, + pub threshold: VarInt, } impl CSetCompression { diff --git a/pumpkin-protocol/src/client/play/acknowledge_block.rs b/pumpkin-protocol/src/client/play/acknowledge_block.rs index 2d86fe002..5ed08af71 100644 --- a/pumpkin-protocol/src/client/play/acknowledge_block.rs +++ b/pumpkin-protocol/src/client/play/acknowledge_block.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_BLOCK_CHANGED_ACK; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; use crate::VarInt; -#[derive(Serialize)] -#[client_packet(PLAY_BLOCK_CHANGED_ACK)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_BLOCK_CHANGED_ACK)] pub struct CAcknowledgeBlockChange { - sequence_id: VarInt, + pub sequence_id: VarInt, } impl CAcknowledgeBlockChange { diff --git a/pumpkin-protocol/src/client/play/actionbar.rs b/pumpkin-protocol/src/client/play/actionbar.rs index 6242f329b..b59a843fe 100644 --- a/pumpkin-protocol/src/client/play/actionbar.rs +++ b/pumpkin-protocol/src/client/play/actionbar.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_ACTION_BAR_TEXT; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SET_ACTION_BAR_TEXT)] +#[packet(PLAY_SET_ACTION_BAR_TEXT)] pub struct CActionBar<'a> { action_bar: &'a TextComponent, } diff --git a/pumpkin-protocol/src/client/play/block_destroy_stage.rs b/pumpkin-protocol/src/client/play/block_destroy_stage.rs index dcf5b71ba..232e0958c 100644 --- a/pumpkin-protocol/src/client/play/block_destroy_stage.rs +++ b/pumpkin-protocol/src/client/play/block_destroy_stage.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_BLOCK_DESTRUCTION; use pumpkin_util::math::position::BlockPos; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_BLOCK_DESTRUCTION)] +#[packet(PLAY_BLOCK_DESTRUCTION)] pub struct CSetBlockDestroyStage { entity_id: VarInt, location: BlockPos, diff --git a/pumpkin-protocol/src/client/play/block_entity_data.rs b/pumpkin-protocol/src/client/play/block_entity_data.rs index 5d843c4dd..1a031f4e8 100644 --- a/pumpkin-protocol/src/client/play/block_entity_data.rs +++ b/pumpkin-protocol/src/client/play/block_entity_data.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_BLOCK_ENTITY_DATA; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_BLOCK_ENTITY_DATA)] +#[packet(PLAY_BLOCK_ENTITY_DATA)] pub struct CBlockEntityData { location: BlockPos, r#type: VarInt, diff --git a/pumpkin-protocol/src/client/play/block_event.rs b/pumpkin-protocol/src/client/play/block_event.rs index 30e0f969f..3414231d8 100644 --- a/pumpkin-protocol/src/client/play/block_event.rs +++ b/pumpkin-protocol/src/client/play/block_event.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_BLOCK_EVENT; use pumpkin_util::math::position::BlockPos; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_BLOCK_EVENT)] +#[packet(PLAY_BLOCK_EVENT)] pub struct CBlockAction<'a> { location: &'a BlockPos, action_id: u8, diff --git a/pumpkin-protocol/src/client/play/block_update.rs b/pumpkin-protocol/src/client/play/block_update.rs index ddc067425..b0f09b800 100644 --- a/pumpkin-protocol/src/client/play/block_update.rs +++ b/pumpkin-protocol/src/client/play/block_update.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_BLOCK_UPDATE; use pumpkin_util::math::position::BlockPos; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_BLOCK_UPDATE)] +#[packet(PLAY_BLOCK_UPDATE)] pub struct CBlockUpdate<'a> { location: &'a BlockPos, block_id: VarInt, diff --git a/pumpkin-protocol/src/client/play/boss_event.rs b/pumpkin-protocol/src/client/play/boss_event.rs index f103f184a..bf6cfd72e 100644 --- a/pumpkin-protocol/src/client/play/boss_event.rs +++ b/pumpkin-protocol/src/client/play/boss_event.rs @@ -3,9 +3,9 @@ use crate::client::play::bossevent_action::BosseventAction; use crate::{ClientPacket, VarInt}; use bytes::BufMut; use pumpkin_data::packet::clientbound::PLAY_BOSS_EVENT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; -#[client_packet(PLAY_BOSS_EVENT)] +#[packet(PLAY_BOSS_EVENT)] pub struct CBossEvent<'a> { pub uuid: &'a uuid::Uuid, pub action: BosseventAction, diff --git a/pumpkin-protocol/src/client/play/center_chunk.rs b/pumpkin-protocol/src/client/play/center_chunk.rs index 02b447b4b..ee5eca3ac 100644 --- a/pumpkin-protocol/src/client/play/center_chunk.rs +++ b/pumpkin-protocol/src/client/play/center_chunk.rs @@ -1,10 +1,10 @@ use pumpkin_data::packet::clientbound::PLAY_SET_CHUNK_CACHE_CENTER; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use crate::VarInt; #[derive(serde::Serialize)] -#[client_packet(PLAY_SET_CHUNK_CACHE_CENTER)] +#[packet(PLAY_SET_CHUNK_CACHE_CENTER)] pub struct CCenterChunk { pub chunk_x: VarInt, pub chunk_z: VarInt, diff --git a/pumpkin-protocol/src/client/play/change_difficulty.rs b/pumpkin-protocol/src/client/play/change_difficulty.rs index 91498c195..5b6fce837 100644 --- a/pumpkin-protocol/src/client/play/change_difficulty.rs +++ b/pumpkin-protocol/src/client/play/change_difficulty.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_CHANGE_DIFFICULTY; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_CHANGE_DIFFICULTY)] +#[packet(PLAY_CHANGE_DIFFICULTY)] pub struct CChangeDifficulty { difficulty: u8, locked: bool, diff --git a/pumpkin-protocol/src/client/play/chunk_data.rs b/pumpkin-protocol/src/client/play/chunk_data.rs index dfe4af28e..27df4c0cb 100644 --- a/pumpkin-protocol/src/client/play/chunk_data.rs +++ b/pumpkin-protocol/src/client/play/chunk_data.rs @@ -1,14 +1,14 @@ -use crate::{bytebuf::ByteBufMut, codec::bit_set::BitSet, ClientPacket, VarInt}; +use crate::{ClientPacket, VarInt, bytebuf::ByteBufMut, codec::bit_set::BitSet}; use bytes::{BufMut, BytesMut}; use pumpkin_data::packet::clientbound::PLAY_LEVEL_CHUNK_WITH_LIGHT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_world::{ - chunk::{ChunkData, SUBCHUNKS_COUNT}, DIRECT_PALETTE_BITS, + chunk::{ChunkData, SUBCHUNKS_COUNT}, }; -#[client_packet(PLAY_LEVEL_CHUNK_WITH_LIGHT)] +#[packet(PLAY_LEVEL_CHUNK_WITH_LIGHT)] pub struct CChunkData<'a>(pub &'a ChunkData); impl ClientPacket for CChunkData<'_> { @@ -73,7 +73,7 @@ impl ClientPacket for CChunkData<'_> { .iter() .position(|b| b == block) .expect("Its just got added, ofc it should be there"); - out_long = out_long << block_size | (index as i64); + out_long = (out_long << block_size) | (index as i64); } data_buf.put_i64(out_long); } diff --git a/pumpkin-protocol/src/client/play/clear_title.rs b/pumpkin-protocol/src/client/play/clear_title.rs index 3716721e2..f36511c54 100644 --- a/pumpkin-protocol/src/client/play/clear_title.rs +++ b/pumpkin-protocol/src/client/play/clear_title.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_CLEAR_TITLES; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_CLEAR_TITLES)] +#[packet(PLAY_CLEAR_TITLES)] pub struct CClearTtitle { reset: bool, } diff --git a/pumpkin-protocol/src/client/play/close_container.rs b/pumpkin-protocol/src/client/play/close_container.rs index 284020212..a0c522043 100644 --- a/pumpkin-protocol/src/client/play/close_container.rs +++ b/pumpkin-protocol/src/client/play/close_container.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_CONTAINER_CLOSE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_CONTAINER_CLOSE)] +#[packet(PLAY_CONTAINER_CLOSE)] pub struct CCloseContainer { window_id: VarInt, } diff --git a/pumpkin-protocol/src/client/play/combat_death.rs b/pumpkin-protocol/src/client/play/combat_death.rs index a2b9522e4..ae56f8f55 100644 --- a/pumpkin-protocol/src/client/play/combat_death.rs +++ b/pumpkin-protocol/src/client/play/combat_death.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_PLAYER_COMBAT_KILL; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::text::TextComponent; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_PLAYER_COMBAT_KILL)] +#[packet(PLAY_PLAYER_COMBAT_KILL)] pub struct CCombatDeath<'a> { player_id: VarInt, message: &'a TextComponent, diff --git a/pumpkin-protocol/src/client/play/command_suggestions.rs b/pumpkin-protocol/src/client/play/command_suggestions.rs index f9a19cb82..063bd92d4 100644 --- a/pumpkin-protocol/src/client/play/command_suggestions.rs +++ b/pumpkin-protocol/src/client/play/command_suggestions.rs @@ -1,11 +1,11 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::PLAY_COMMAND_SUGGESTIONS; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::text::TextComponent; -use crate::{bytebuf::ByteBufMut, ClientPacket, VarInt}; +use crate::{ClientPacket, VarInt, bytebuf::ByteBufMut}; -#[client_packet(PLAY_COMMAND_SUGGESTIONS)] +#[packet(PLAY_COMMAND_SUGGESTIONS)] pub struct CCommandSuggestions { id: VarInt, start: VarInt, diff --git a/pumpkin-protocol/src/client/play/commands.rs b/pumpkin-protocol/src/client/play/commands.rs index 6f743996d..b8194a083 100644 --- a/pumpkin-protocol/src/client/play/commands.rs +++ b/pumpkin-protocol/src/client/play/commands.rs @@ -1,10 +1,10 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::PLAY_COMMANDS; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; -use crate::{bytebuf::ByteBufMut, ClientPacket, VarInt}; +use crate::{ClientPacket, VarInt, bytebuf::ByteBufMut}; -#[client_packet(PLAY_COMMANDS)] +#[packet(PLAY_COMMANDS)] pub struct CCommands<'a> { pub nodes: Vec>, pub root_node_index: VarInt, @@ -114,12 +114,19 @@ impl ProtoNode<'_> { if flags & Self::FLAG_HAS_SUGGESTION_TYPE != 0 { match &self.node_type { - ProtoNodeType::Argument { name: _, is_executable: _, parser: _, override_suggestion_type } => { + ProtoNodeType::Argument { + name: _, + is_executable: _, + parser: _, + override_suggestion_type, + } => { // suggestion type let suggestion_type = &override_suggestion_type.expect("ProtoNode::FLAG_HAS_SUGGESTION_TYPE should only be set if override_suggestion_type is not None."); bytebuf.put_string(suggestion_type.identifier()); - }, - _ => unimplemented!("ProtoNode::FLAG_HAS_SUGGESTION_TYPE is only implemented for ProtoNodeType::Argument"), + } + _ => unimplemented!( + "ProtoNode::FLAG_HAS_SUGGESTION_TYPE is only implemented for ProtoNodeType::Argument" + ), } } } diff --git a/pumpkin-protocol/src/client/play/cookie_request.rs b/pumpkin-protocol/src/client/play/cookie_request.rs index 1618accde..47eb6d9f3 100644 --- a/pumpkin-protocol/src/client/play/cookie_request.rs +++ b/pumpkin-protocol/src/client/play/cookie_request.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_COOKIE_REQUEST; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::codec::identifier::Identifier; #[derive(Serialize)] -#[client_packet(PLAY_COOKIE_REQUEST)] +#[packet(PLAY_COOKIE_REQUEST)] /// Requests a cookie that was previously stored. pub struct CPlayCookieRequest<'a> { key: &'a Identifier, diff --git a/pumpkin-protocol/src/client/play/damage_event.rs b/pumpkin-protocol/src/client/play/damage_event.rs index 976610946..32cf036af 100644 --- a/pumpkin-protocol/src/client/play/damage_event.rs +++ b/pumpkin-protocol/src/client/play/damage_event.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_DAMAGE_EVENT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_DAMAGE_EVENT)] +#[packet(PLAY_DAMAGE_EVENT)] pub struct CDamageEvent { entity_id: VarInt, source_type_id: VarInt, diff --git a/pumpkin-protocol/src/client/play/disconnect.rs b/pumpkin-protocol/src/client/play/disconnect.rs index 5bc3e6cf8..5ecf3dd44 100644 --- a/pumpkin-protocol/src/client/play/disconnect.rs +++ b/pumpkin-protocol/src/client/play/disconnect.rs @@ -1,17 +1,17 @@ use pumpkin_data::packet::clientbound::PLAY_DISCONNECT; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(PLAY_DISCONNECT)] -pub struct CPlayDisconnect<'a> { - reason: &'a TextComponent, +#[derive(Serialize, Deserialize)] +#[packet(PLAY_DISCONNECT)] +pub struct CPlayDisconnect { + pub reason: TextComponent, } -impl<'a> CPlayDisconnect<'a> { - pub fn new(reason: &'a TextComponent) -> Self { +impl CPlayDisconnect { + pub fn new(reason: TextComponent) -> Self { Self { reason } } } diff --git a/pumpkin-protocol/src/client/play/disguised_chat_message.rs b/pumpkin-protocol/src/client/play/disguised_chat_message.rs index 324dc537a..74cb13704 100644 --- a/pumpkin-protocol/src/client/play/disguised_chat_message.rs +++ b/pumpkin-protocol/src/client/play/disguised_chat_message.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_DISGUISED_CHAT; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_DISGUISED_CHAT)] +#[packet(PLAY_DISGUISED_CHAT)] pub struct CDisguisedChatMessage<'a> { message: &'a TextComponent, chat_type: VarInt, diff --git a/pumpkin-protocol/src/client/play/display_objective.rs b/pumpkin-protocol/src/client/play/display_objective.rs index 5a24a205c..233e73ce7 100644 --- a/pumpkin-protocol/src/client/play/display_objective.rs +++ b/pumpkin-protocol/src/client/play/display_objective.rs @@ -1,13 +1,13 @@ use pumpkin_data::{ packet::clientbound::PLAY_SET_DISPLAY_OBJECTIVE, scoreboard::ScoreboardDisplaySlot, }; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_SET_DISPLAY_OBJECTIVE)] +#[packet(PLAY_SET_DISPLAY_OBJECTIVE)] pub struct CDisplayObjective<'a> { position: VarInt, score_name: &'a str, diff --git a/pumpkin-protocol/src/client/play/entity_animation.rs b/pumpkin-protocol/src/client/play/entity_animation.rs index c4a163ee2..9f5d99ad1 100644 --- a/pumpkin-protocol/src/client/play/entity_animation.rs +++ b/pumpkin-protocol/src/client/play/entity_animation.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_ANIMATE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_ANIMATE)] +#[packet(PLAY_ANIMATE)] pub struct CEntityAnimation { entity_id: VarInt, /// See `Animation` diff --git a/pumpkin-protocol/src/client/play/entity_metadata.rs b/pumpkin-protocol/src/client/play/entity_metadata.rs index 1ce7bc5e8..aac619260 100644 --- a/pumpkin-protocol/src/client/play/entity_metadata.rs +++ b/pumpkin-protocol/src/client/play/entity_metadata.rs @@ -1,28 +1,26 @@ use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_DATA; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_SET_ENTITY_DATA)] -pub struct CSetEntityMetadata { +#[packet(PLAY_SET_ENTITY_DATA)] +pub struct CSetEntityMetadata { entity_id: VarInt, - metadata: Metadata, - end: u8, + metadata: Vec, } -impl CSetEntityMetadata { - pub fn new(entity_id: VarInt, metadata: Metadata) -> Self { +impl CSetEntityMetadata { + pub fn new(entity_id: VarInt, metadata: Vec) -> Self { Self { entity_id, metadata, - end: 255, } } } -#[derive(Serialize)] +#[derive(Serialize, Clone)] pub struct Metadata { index: u8, typ: VarInt, diff --git a/pumpkin-protocol/src/client/play/entity_sound_effect.rs b/pumpkin-protocol/src/client/play/entity_sound_effect.rs index 8be086015..1d3f8bc83 100644 --- a/pumpkin-protocol/src/client/play/entity_sound_effect.rs +++ b/pumpkin-protocol/src/client/play/entity_sound_effect.rs @@ -1,10 +1,10 @@ use bytes::BufMut; use pumpkin_data::{packet::clientbound::PLAY_SOUND_ENTITY, sound::SoundCategory}; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; -use crate::{bytebuf::ByteBufMut, ClientPacket, IDOrSoundEvent, SoundEvent, VarInt}; +use crate::{ClientPacket, IDOrSoundEvent, SoundEvent, VarInt, bytebuf::ByteBufMut}; -#[client_packet(PLAY_SOUND_ENTITY)] +#[packet(PLAY_SOUND_ENTITY)] pub struct CEntitySoundEffect { sound_event: IDOrSoundEvent, sound_category: VarInt, diff --git a/pumpkin-protocol/src/client/play/entity_status.rs b/pumpkin-protocol/src/client/play/entity_status.rs index a58a1dbae..183b33585 100644 --- a/pumpkin-protocol/src/client/play/entity_status.rs +++ b/pumpkin-protocol/src/client/play/entity_status.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_ENTITY_EVENT; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(PLAY_ENTITY_EVENT)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_ENTITY_EVENT)] pub struct CEntityStatus { entity_id: i32, entity_status: i8, diff --git a/pumpkin-protocol/src/client/play/entity_velocity.rs b/pumpkin-protocol/src/client/play/entity_velocity.rs index 617eeac0b..e5b70e967 100644 --- a/pumpkin-protocol/src/client/play/entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/entity_velocity.rs @@ -1,25 +1,25 @@ use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_MOTION; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_SET_ENTITY_MOTION)] -pub struct CEntityVelocity<'a> { - entity_id: &'a VarInt, +#[packet(PLAY_SET_ENTITY_MOTION)] +pub struct CEntityVelocity { + entity_id: VarInt, velocity: Vector3, } -impl<'a> CEntityVelocity<'a> { - pub fn new(entity_id: &'a VarInt, velocity_x: f64, velocity_y: f64, velocity_z: f64) -> Self { +impl CEntityVelocity { + pub fn new(entity_id: VarInt, velocity: Vector3) -> Self { Self { entity_id, velocity: Vector3::new( - (velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16, - (velocity_y.clamp(-3.9, 3.9) * 8000.0) as i16, - (velocity_z.clamp(-3.9, 3.9) * 8000.0) as i16, + (velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16, + (velocity.y.clamp(-3.9, 3.9) * 8000.0) as i16, + (velocity.z.clamp(-3.9, 3.9) * 8000.0) as i16, ), } } diff --git a/pumpkin-protocol/src/client/play/explode.rs b/pumpkin-protocol/src/client/play/explode.rs new file mode 100644 index 000000000..9535821c4 --- /dev/null +++ b/pumpkin-protocol/src/client/play/explode.rs @@ -0,0 +1,31 @@ +use pumpkin_data::packet::clientbound::PLAY_EXPLODE; +use pumpkin_macros::packet; +use pumpkin_util::math::vector3::Vector3; +use serde::Serialize; + +use crate::{IDOrSoundEvent, codec::var_int::VarInt}; + +#[derive(Serialize)] +#[packet(PLAY_EXPLODE)] +pub struct CExplosion { + center: Vector3, + knockback: Option>, + particle: VarInt, + sound: IDOrSoundEvent, +} + +impl CExplosion { + pub fn new( + center: Vector3, + knockback: Option>, + particle: VarInt, + sound: IDOrSoundEvent, + ) -> Self { + Self { + center, + knockback, + particle, + sound, + } + } +} diff --git a/pumpkin-protocol/src/client/play/game_event.rs b/pumpkin-protocol/src/client/play/game_event.rs index 375b8e1b9..9e2c69f41 100644 --- a/pumpkin-protocol/src/client/play/game_event.rs +++ b/pumpkin-protocol/src/client/play/game_event.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_GAME_EVENT; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(PLAY_GAME_EVENT)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_GAME_EVENT)] pub struct CGameEvent { event: u8, value: f32, diff --git a/pumpkin-protocol/src/client/play/head_rot.rs b/pumpkin-protocol/src/client/play/head_rot.rs index 3244d5e5f..541c89829 100644 --- a/pumpkin-protocol/src/client/play/head_rot.rs +++ b/pumpkin-protocol/src/client/play/head_rot.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_ROTATE_HEAD; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; use crate::VarInt; -#[derive(Serialize)] -#[client_packet(PLAY_ROTATE_HEAD)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_ROTATE_HEAD)] pub struct CHeadRot { entity_id: VarInt, head_yaw: u8, diff --git a/pumpkin-protocol/src/client/play/hurt_animation.rs b/pumpkin-protocol/src/client/play/hurt_animation.rs index 63c895f22..e6a7c830b 100644 --- a/pumpkin-protocol/src/client/play/hurt_animation.rs +++ b/pumpkin-protocol/src/client/play/hurt_animation.rs @@ -1,18 +1,18 @@ use pumpkin_data::packet::clientbound::PLAY_HURT_ANIMATION; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; use crate::VarInt; -#[derive(Serialize)] -#[client_packet(PLAY_HURT_ANIMATION)] -pub struct CHurtAnimation<'a> { - entity_id: &'a VarInt, +#[derive(Serialize, Deserialize)] +#[packet(PLAY_HURT_ANIMATION)] +pub struct CHurtAnimation { + entity_id: VarInt, yaw: f32, } -impl<'a> CHurtAnimation<'a> { - pub fn new(entity_id: &'a VarInt, yaw: f32) -> Self { +impl CHurtAnimation { + pub fn new(entity_id: VarInt, yaw: f32) -> Self { Self { entity_id, yaw } } } diff --git a/pumpkin-protocol/src/client/play/initialize_world_border.rs b/pumpkin-protocol/src/client/play/initialize_world_border.rs index 01eb9d568..47855a3c9 100644 --- a/pumpkin-protocol/src/client/play/initialize_world_border.rs +++ b/pumpkin-protocol/src/client/play/initialize_world_border.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_INITIALIZE_BORDER; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; -use crate::{codec::var_long::VarLong, VarInt}; +use crate::{VarInt, codec::var_long::VarLong}; #[derive(Serialize)] -#[client_packet(PLAY_INITIALIZE_BORDER)] +#[packet(PLAY_INITIALIZE_BORDER)] pub struct CInitializeWorldBorder { x: f64, z: f64, diff --git a/pumpkin-protocol/src/client/play/keep_alive.rs b/pumpkin-protocol/src/client/play/keep_alive.rs index 99727eddc..ed70231a3 100644 --- a/pumpkin-protocol/src/client/play/keep_alive.rs +++ b/pumpkin-protocol/src/client/play/keep_alive.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_KEEP_ALIVE; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(PLAY_KEEP_ALIVE)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_KEEP_ALIVE)] pub struct CKeepAlive { - keep_alive_id: i64, + pub keep_alive_id: i64, } impl CKeepAlive { diff --git a/pumpkin-protocol/src/client/play/level_event.rs b/pumpkin-protocol/src/client/play/level_event.rs index 9276dc8b7..d884ee12e 100644 --- a/pumpkin-protocol/src/client/play/level_event.rs +++ b/pumpkin-protocol/src/client/play/level_event.rs @@ -1,10 +1,10 @@ use pumpkin_data::packet::clientbound::PLAY_LEVEL_EVENT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; -use serde::Serialize; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(PLAY_LEVEL_EVENT)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_LEVEL_EVENT)] pub struct CLevelEvent { event: i32, location: BlockPos, diff --git a/pumpkin-protocol/src/client/play/login.rs b/pumpkin-protocol/src/client/play/login.rs index f32a06b8a..5528fe9a1 100644 --- a/pumpkin-protocol/src/client/play/login.rs +++ b/pumpkin-protocol/src/client/play/login.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_LOGIN; use pumpkin_util::math::position::BlockPos; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; -use crate::{codec::identifier::Identifier, VarInt}; +use crate::{VarInt, codec::identifier::Identifier}; #[derive(Serialize)] -#[client_packet(PLAY_LOGIN)] +#[packet(PLAY_LOGIN)] pub struct CLogin<'a> { entity_id: i32, is_hardcore: bool, diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index efe5ec623..55f5958fa 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -24,6 +24,7 @@ mod entity_metadata; mod entity_sound_effect; mod entity_status; mod entity_velocity; +mod explode; mod game_event; mod head_rot; mod hurt_animation; @@ -71,6 +72,7 @@ mod unload_chunk; mod update_entity_pos; mod update_entity_pos_rot; mod update_entity_rot; +mod update_mob_effect; mod update_objectives; mod update_score; mod worldevent; @@ -101,6 +103,7 @@ pub use entity_metadata::*; pub use entity_sound_effect::*; pub use entity_status::*; pub use entity_velocity::*; +pub use explode::*; pub use game_event::*; pub use head_rot::*; pub use hurt_animation::*; @@ -148,6 +151,7 @@ pub use unload_chunk::*; pub use update_entity_pos::*; pub use update_entity_pos_rot::*; pub use update_entity_rot::*; +pub use update_mob_effect::*; pub use update_objectives::*; pub use update_score::*; pub use worldevent::*; diff --git a/pumpkin-protocol/src/client/play/open_screen.rs b/pumpkin-protocol/src/client/play/open_screen.rs index 6e9ea18de..c50fe1710 100644 --- a/pumpkin-protocol/src/client/play/open_screen.rs +++ b/pumpkin-protocol/src/client/play/open_screen.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_OPEN_SCREEN; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_OPEN_SCREEN)] +#[packet(PLAY_OPEN_SCREEN)] pub struct COpenScreen<'a> { window_id: VarInt, window_type: VarInt, diff --git a/pumpkin-protocol/src/client/play/open_sign_editor.rs b/pumpkin-protocol/src/client/play/open_sign_editor.rs index 4827ccc68..f97faddc1 100644 --- a/pumpkin-protocol/src/client/play/open_sign_editor.rs +++ b/pumpkin-protocol/src/client/play/open_sign_editor.rs @@ -1,10 +1,10 @@ use pumpkin_data::packet::clientbound::PLAY_OPEN_SIGN_EDITOR; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_OPEN_SIGN_EDITOR)] +#[packet(PLAY_OPEN_SIGN_EDITOR)] pub struct COpenSignEditor { location: BlockPos, is_front_text: bool, diff --git a/pumpkin-protocol/src/client/play/particle.rs b/pumpkin-protocol/src/client/play/particle.rs index 0b35aca01..c5d8d1993 100644 --- a/pumpkin-protocol/src/client/play/particle.rs +++ b/pumpkin-protocol/src/client/play/particle.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_LEVEL_PARTICLES; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_LEVEL_PARTICLES)] +#[packet(PLAY_LEVEL_PARTICLES)] pub struct CParticle<'a> { force_spawn: bool, /// If true, particle distance increases from 256 to 65536. diff --git a/pumpkin-protocol/src/client/play/ping_response.rs b/pumpkin-protocol/src/client/play/ping_response.rs index 5c8891586..e4fbfc498 100644 --- a/pumpkin-protocol/src/client/play/ping_response.rs +++ b/pumpkin-protocol/src/client/play/ping_response.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_PONG_RESPONSE; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(PLAY_PONG_RESPONSE)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_PONG_RESPONSE)] pub struct CPingResponse { - payload: i64, + pub payload: i64, } impl CPingResponse { diff --git a/pumpkin-protocol/src/client/play/player_abilities.rs b/pumpkin-protocol/src/client/play/player_abilities.rs index 1f8e287db..d453227a3 100644 --- a/pumpkin-protocol/src/client/play/player_abilities.rs +++ b/pumpkin-protocol/src/client/play/player_abilities.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_PLAYER_ABILITIES; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_PLAYER_ABILITIES)] +#[packet(PLAY_PLAYER_ABILITIES)] pub struct CPlayerAbilities { flags: i8, flying_speed: f32, diff --git a/pumpkin-protocol/src/client/play/player_chat_message.rs b/pumpkin-protocol/src/client/play/player_chat_message.rs index 76573f752..44a31f6da 100644 --- a/pumpkin-protocol/src/client/play/player_chat_message.rs +++ b/pumpkin-protocol/src/client/play/player_chat_message.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_PLAYER_CHAT; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; -use crate::{codec::bit_set::BitSet, VarInt}; +use crate::{VarInt, codec::bit_set::BitSet}; #[derive(Serialize)] -#[client_packet(PLAY_PLAYER_CHAT)] +#[packet(PLAY_PLAYER_CHAT)] pub struct CPlayerChatMessage<'a> { #[serde(with = "uuid::serde::compact")] sender: uuid::Uuid, diff --git a/pumpkin-protocol/src/client/play/player_info_update.rs b/pumpkin-protocol/src/client/play/player_info_update.rs index 502485fa1..47896dbc2 100644 --- a/pumpkin-protocol/src/client/play/player_info_update.rs +++ b/pumpkin-protocol/src/client/play/player_info_update.rs @@ -1,12 +1,12 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_UPDATE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; -use crate::{bytebuf::ByteBufMut, ClientPacket, Property}; +use crate::{ClientPacket, Property, bytebuf::ByteBufMut}; use super::PlayerAction; -#[client_packet(PLAY_PLAYER_INFO_UPDATE)] +#[packet(PLAY_PLAYER_INFO_UPDATE)] pub struct CPlayerInfoUpdate<'a> { pub actions: i8, pub players: &'a [Player<'a>], diff --git a/pumpkin-protocol/src/client/play/player_position.rs b/pumpkin-protocol/src/client/play/player_position.rs index 8aae24c6e..0fa208b7a 100644 --- a/pumpkin-protocol/src/client/play/player_position.rs +++ b/pumpkin-protocol/src/client/play/player_position.rs @@ -1,18 +1,20 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::PLAY_PLAYER_POSITION; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; -use crate::{bytebuf::ByteBufMut, ClientPacket, PositionFlag, VarInt}; +use crate::{ + ClientPacket, PositionFlag, ServerPacket, VarInt, bytebuf::ByteBuf, bytebuf::ByteBufMut, +}; -#[client_packet(PLAY_PLAYER_POSITION)] +#[packet(PLAY_PLAYER_POSITION)] pub struct CPlayerPosition<'a> { - teleport_id: VarInt, - position: Vector3, - delta: Vector3, - yaw: f32, - pitch: f32, - releatives: &'a [PositionFlag], + pub teleport_id: VarInt, + pub position: Vector3, + pub delta: Vector3, + pub yaw: f32, + pub pitch: f32, + pub releatives: &'a [PositionFlag], } impl<'a> CPlayerPosition<'a> { @@ -35,6 +37,28 @@ impl<'a> CPlayerPosition<'a> { } } +impl ServerPacket for CPlayerPosition<'_> { + fn read(bytebuf: &mut impl bytes::Buf) -> Result { + fn get_vec( + bytebuf: &mut impl bytes::Buf, + ) -> Result, crate::bytebuf::ReadingError> { + Ok(Vector3::new( + bytebuf.try_get_f64()?, + bytebuf.try_get_f64()?, + bytebuf.try_get_f64()?, + )) + } + Ok(Self { + teleport_id: bytebuf.try_get_var_int()?, + position: get_vec(bytebuf)?, + delta: get_vec(bytebuf)?, + yaw: bytebuf.try_get_f32()?, + pitch: bytebuf.try_get_f32()?, + releatives: &[], // TODO + }) + } +} + impl ClientPacket for CPlayerPosition<'_> { fn write(&self, bytebuf: &mut impl BufMut) { bytebuf.put_var_int(&self.teleport_id); diff --git a/pumpkin-protocol/src/client/play/player_remove.rs b/pumpkin-protocol/src/client/play/player_remove.rs index cfb57d369..0eba59792 100644 --- a/pumpkin-protocol/src/client/play/player_remove.rs +++ b/pumpkin-protocol/src/client/play/player_remove.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_REMOVE; -use pumpkin_macros::client_packet; -use serde::{ser::SerializeSeq, Serialize}; +use pumpkin_macros::packet; +use serde::{Serialize, ser::SerializeSeq}; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_PLAYER_INFO_REMOVE)] +#[packet(PLAY_PLAYER_INFO_REMOVE)] pub struct CRemovePlayerInfo<'a> { players_count: VarInt, #[serde(serialize_with = "serialize_slice_uuids")] diff --git a/pumpkin-protocol/src/client/play/remove_entities.rs b/pumpkin-protocol/src/client/play/remove_entities.rs index 2b5f38016..5979ee90d 100644 --- a/pumpkin-protocol/src/client/play/remove_entities.rs +++ b/pumpkin-protocol/src/client/play/remove_entities.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_REMOVE_ENTITIES; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_REMOVE_ENTITIES)] +#[packet(PLAY_REMOVE_ENTITIES)] pub struct CRemoveEntities<'a> { count: VarInt, entity_ids: &'a [VarInt], diff --git a/pumpkin-protocol/src/client/play/reset_score.rs b/pumpkin-protocol/src/client/play/reset_score.rs index d9c7e6707..35990260a 100644 --- a/pumpkin-protocol/src/client/play/reset_score.rs +++ b/pumpkin-protocol/src/client/play/reset_score.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_RESET_SCORE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_RESET_SCORE)] +#[packet(PLAY_RESET_SCORE)] pub struct CResetScore { entity_name: String, objective_name: Option, diff --git a/pumpkin-protocol/src/client/play/respawn.rs b/pumpkin-protocol/src/client/play/respawn.rs index 66cf233e9..d2860b9a4 100644 --- a/pumpkin-protocol/src/client/play/respawn.rs +++ b/pumpkin-protocol/src/client/play/respawn.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_RESPAWN; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; -use serde::Serialize; +use serde::{Deserialize, Serialize}; -use crate::{codec::identifier::Identifier, VarInt}; +use crate::{VarInt, codec::identifier::Identifier}; -#[derive(Serialize)] -#[client_packet(PLAY_RESPAWN)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_RESPAWN)] pub struct CRespawn { dimension_type: VarInt, dimension_name: Identifier, diff --git a/pumpkin-protocol/src/client/play/server_links.rs b/pumpkin-protocol/src/client/play/server_links.rs index 566e90ce5..8e0d53bb5 100644 --- a/pumpkin-protocol/src/client/play/server_links.rs +++ b/pumpkin-protocol/src/client/play/server_links.rs @@ -1,10 +1,10 @@ use crate::{Link, VarInt}; use pumpkin_data::packet::clientbound::PLAY_SERVER_LINKS; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SERVER_LINKS)] +#[packet(PLAY_SERVER_LINKS)] pub struct CPlayServerLinks<'a> { links_count: &'a VarInt, links: &'a [Link<'a>], diff --git a/pumpkin-protocol/src/client/play/set_border_center.rs b/pumpkin-protocol/src/client/play/set_border_center.rs index f4df21066..4eebd8b5c 100644 --- a/pumpkin-protocol/src/client/play/set_border_center.rs +++ b/pumpkin-protocol/src/client/play/set_border_center.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_CENTER; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SET_BORDER_CENTER)] +#[packet(PLAY_SET_BORDER_CENTER)] pub struct CSetBorderCenter { x: f64, z: f64, diff --git a/pumpkin-protocol/src/client/play/set_border_lerp_size.rs b/pumpkin-protocol/src/client/play/set_border_lerp_size.rs index e768d10ea..4f9e42f4e 100644 --- a/pumpkin-protocol/src/client/play/set_border_lerp_size.rs +++ b/pumpkin-protocol/src/client/play/set_border_lerp_size.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_LERP_SIZE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::codec::var_long::VarLong; #[derive(Serialize)] -#[client_packet(PLAY_SET_BORDER_LERP_SIZE)] +#[packet(PLAY_SET_BORDER_LERP_SIZE)] pub struct CSetBorderLerpSize { old_diameter: f64, new_diameter: f64, diff --git a/pumpkin-protocol/src/client/play/set_border_size.rs b/pumpkin-protocol/src/client/play/set_border_size.rs index 9a1193dd0..8eab207ed 100644 --- a/pumpkin-protocol/src/client/play/set_border_size.rs +++ b/pumpkin-protocol/src/client/play/set_border_size.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_SIZE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SET_BORDER_SIZE)] +#[packet(PLAY_SET_BORDER_SIZE)] pub struct CSetBorderSize { diameter: f64, } diff --git a/pumpkin-protocol/src/client/play/set_border_warning_delay.rs b/pumpkin-protocol/src/client/play/set_border_warning_delay.rs index c74475e8c..5e0d2b13d 100644 --- a/pumpkin-protocol/src/client/play/set_border_warning_delay.rs +++ b/pumpkin-protocol/src/client/play/set_border_warning_delay.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DELAY; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_SET_BORDER_WARNING_DELAY)] +#[packet(PLAY_SET_BORDER_WARNING_DELAY)] pub struct CSetBorderWarningDelay { warning_time: VarInt, } diff --git a/pumpkin-protocol/src/client/play/set_border_warning_distance.rs b/pumpkin-protocol/src/client/play/set_border_warning_distance.rs index 5d8be60da..fa8e0926d 100644 --- a/pumpkin-protocol/src/client/play/set_border_warning_distance.rs +++ b/pumpkin-protocol/src/client/play/set_border_warning_distance.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DISTANCE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_SET_BORDER_WARNING_DISTANCE)] +#[packet(PLAY_SET_BORDER_WARNING_DISTANCE)] pub struct CSetBorderWarningDistance { warning_blocks: VarInt, } diff --git a/pumpkin-protocol/src/client/play/set_container_content.rs b/pumpkin-protocol/src/client/play/set_container_content.rs index da715f576..c9b104efa 100644 --- a/pumpkin-protocol/src/client/play/set_container_content.rs +++ b/pumpkin-protocol/src/client/play/set_container_content.rs @@ -1,12 +1,12 @@ -use crate::codec::slot::Slot; use crate::VarInt; +use crate::codec::slot::Slot; use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_CONTENT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_CONTAINER_SET_CONTENT)] +#[packet(PLAY_CONTAINER_SET_CONTENT)] pub struct CSetContainerContent<'a> { window_id: VarInt, state_id: VarInt, diff --git a/pumpkin-protocol/src/client/play/set_container_property.rs b/pumpkin-protocol/src/client/play/set_container_property.rs index 06924b80d..c8a8d195c 100644 --- a/pumpkin-protocol/src/client/play/set_container_property.rs +++ b/pumpkin-protocol/src/client/play/set_container_property.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_DATA; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_CONTAINER_SET_DATA)] +#[packet(PLAY_CONTAINER_SET_DATA)] pub struct CSetContainerProperty { window_id: VarInt, property: i16, diff --git a/pumpkin-protocol/src/client/play/set_container_slot.rs b/pumpkin-protocol/src/client/play/set_container_slot.rs index ada4544bc..22bb3bbc2 100644 --- a/pumpkin-protocol/src/client/play/set_container_slot.rs +++ b/pumpkin-protocol/src/client/play/set_container_slot.rs @@ -1,12 +1,12 @@ -use crate::codec::slot::Slot; use crate::VarInt; +use crate::codec::slot::Slot; use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_SLOT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_CONTAINER_SET_SLOT)] +#[packet(PLAY_CONTAINER_SET_SLOT)] pub struct CSetContainerSlot<'a> { window_id: i8, state_id: VarInt, diff --git a/pumpkin-protocol/src/client/play/set_equipment.rs b/pumpkin-protocol/src/client/play/set_equipment.rs index e13e00d4c..a38e8a0d9 100644 --- a/pumpkin-protocol/src/client/play/set_equipment.rs +++ b/pumpkin-protocol/src/client/play/set_equipment.rs @@ -1,15 +1,15 @@ -use crate::bytebuf::{serializer::Serializer, ByteBufMut}; +use crate::bytebuf::{ByteBufMut, serializer::Serializer}; use bytes::BytesMut; use pumpkin_data::packet::clientbound::PLAY_SET_EQUIPMENT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::{ - codec::{slot::Slot, var_int::VarInt}, ClientPacket, + codec::{slot::Slot, var_int::VarInt}, }; -#[client_packet(PLAY_SET_EQUIPMENT)] +#[packet(PLAY_SET_EQUIPMENT)] pub struct CSetEquipment { entity_id: VarInt, equipment: Vec<(EquipmentSlot, Slot)>, @@ -40,7 +40,7 @@ impl ClientPacket for CSetEquipment { equipment .1 .serialize(&mut serializer) - .expect("Could not serialize packet"); + .expect("Could not serialize Equipment Slot"); bytebuf.put(serializer.output); } } diff --git a/pumpkin-protocol/src/client/play/set_experience.rs b/pumpkin-protocol/src/client/play/set_experience.rs index 0e565a565..fb8aa35dc 100644 --- a/pumpkin-protocol/src/client/play/set_experience.rs +++ b/pumpkin-protocol/src/client/play/set_experience.rs @@ -1,15 +1,15 @@ use pumpkin_data::packet::clientbound::PLAY_SET_EXPERIENCE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_SET_EXPERIENCE)] +#[packet(PLAY_SET_EXPERIENCE)] pub struct CSetExperience { progress: f32, - level: VarInt, total_experience: VarInt, + level: VarInt, } impl CSetExperience { diff --git a/pumpkin-protocol/src/client/play/set_health.rs b/pumpkin-protocol/src/client/play/set_health.rs index 4384ce628..e60735506 100644 --- a/pumpkin-protocol/src/client/play/set_health.rs +++ b/pumpkin-protocol/src/client/play/set_health.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_HEALTH; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_SET_HEALTH)] +#[packet(PLAY_SET_HEALTH)] pub struct CSetHealth { health: f32, food: VarInt, diff --git a/pumpkin-protocol/src/client/play/set_held_item.rs b/pumpkin-protocol/src/client/play/set_held_item.rs index 8e8ba6d0a..1643d15f8 100644 --- a/pumpkin-protocol/src/client/play/set_held_item.rs +++ b/pumpkin-protocol/src/client/play/set_held_item.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_SET_HELD_SLOT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SET_HELD_SLOT)] +#[packet(PLAY_SET_HELD_SLOT)] pub struct CSetHeldItem { slot: i8, } diff --git a/pumpkin-protocol/src/client/play/set_time.rs b/pumpkin-protocol/src/client/play/set_time.rs index e432796e5..b7b744945 100644 --- a/pumpkin-protocol/src/client/play/set_time.rs +++ b/pumpkin-protocol/src/client/play/set_time.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_SET_TIME; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SET_TIME)] +#[packet(PLAY_SET_TIME)] pub struct CUpdateTime { world_age: i64, time_of_day: i64, diff --git a/pumpkin-protocol/src/client/play/set_title.rs b/pumpkin-protocol/src/client/play/set_title.rs index f9a2254b4..2d02abbc0 100644 --- a/pumpkin-protocol/src/client/play/set_title.rs +++ b/pumpkin-protocol/src/client/play/set_title.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_TITLE_TEXT; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SET_TITLE_TEXT)] +#[packet(PLAY_SET_TITLE_TEXT)] pub struct CTitleText<'a> { title: &'a TextComponent, } diff --git a/pumpkin-protocol/src/client/play/sound_effect.rs b/pumpkin-protocol/src/client/play/sound_effect.rs index 35bb02418..da729d832 100644 --- a/pumpkin-protocol/src/client/play/sound_effect.rs +++ b/pumpkin-protocol/src/client/play/sound_effect.rs @@ -1,11 +1,12 @@ -use bytes::BufMut; use pumpkin_data::{packet::clientbound::PLAY_SOUND, sound::SoundCategory}; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; +use serde::Serialize; -use crate::{bytebuf::ByteBufMut, ClientPacket, IDOrSoundEvent, SoundEvent, VarInt}; +use crate::{IDOrSoundEvent, SoundEvent, VarInt}; -#[client_packet(PLAY_SOUND)] +#[derive(Serialize)] +#[packet(PLAY_SOUND)] pub struct CSoundEffect { sound_event: IDOrSoundEvent, sound_category: VarInt, @@ -42,25 +43,3 @@ impl CSoundEffect { } } } - -impl ClientPacket for CSoundEffect { - fn write(&self, bytebuf: &mut impl BufMut) { - bytebuf.put_var_int(&self.sound_event.id); - if self.sound_event.id.0 == 0 { - if let Some(test) = &self.sound_event.sound_event { - bytebuf.put_identifier(&test.sound_name); - - bytebuf.put_option(&test.range, |p, v| { - p.put_f32(*v); - }); - } - } - bytebuf.put_var_int(&self.sound_category); - bytebuf.put_i32(self.position.x); - bytebuf.put_i32(self.position.y); - bytebuf.put_i32(self.position.z); - bytebuf.put_f32(self.volume); - bytebuf.put_f32(self.pitch); - bytebuf.put_f64(self.seed); - } -} diff --git a/pumpkin-protocol/src/client/play/spawn_entity.rs b/pumpkin-protocol/src/client/play/spawn_entity.rs index 8527c734d..aaaea77cb 100644 --- a/pumpkin-protocol/src/client/play/spawn_entity.rs +++ b/pumpkin-protocol/src/client/play/spawn_entity.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_ADD_ENTITY; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_ADD_ENTITY)] +#[packet(PLAY_ADD_ENTITY)] pub struct CSpawnEntity { entity_id: VarInt, #[serde(with = "uuid::serde::compact")] diff --git a/pumpkin-protocol/src/client/play/store_cookie.rs b/pumpkin-protocol/src/client/play/store_cookie.rs index d20e7d91d..077ab36c2 100644 --- a/pumpkin-protocol/src/client/play/store_cookie.rs +++ b/pumpkin-protocol/src/client/play/store_cookie.rs @@ -1,12 +1,12 @@ -use crate::{codec::identifier::Identifier, VarInt}; +use crate::{VarInt, codec::identifier::Identifier}; use pumpkin_data::packet::clientbound::PLAY_STORE_COOKIE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; /// Stores some arbitrary data on the client, which persists between server transfers. /// The Notchian client only accepts cookies of up to 5 kiB in size. #[derive(Serialize)] -#[client_packet(PLAY_STORE_COOKIE)] +#[packet(PLAY_STORE_COOKIE)] pub struct CStoreCookie<'a> { key: &'a Identifier, payload_length: VarInt, diff --git a/pumpkin-protocol/src/client/play/subtitle.rs b/pumpkin-protocol/src/client/play/subtitle.rs index 8953eaf32..c5c9528ab 100644 --- a/pumpkin-protocol/src/client/play/subtitle.rs +++ b/pumpkin-protocol/src/client/play/subtitle.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_SUBTITLE_TEXT; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SET_SUBTITLE_TEXT)] +#[packet(PLAY_SET_SUBTITLE_TEXT)] pub struct CSubtitle<'a> { subtitle: &'a TextComponent, } diff --git a/pumpkin-protocol/src/client/play/system_chat_message.rs b/pumpkin-protocol/src/client/play/system_chat_message.rs index 054240241..99356bf7a 100644 --- a/pumpkin-protocol/src/client/play/system_chat_message.rs +++ b/pumpkin-protocol/src/client/play/system_chat_message.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_SYSTEM_CHAT; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_SYSTEM_CHAT)] +#[packet(PLAY_SYSTEM_CHAT)] pub struct CSystemChatMessage<'a> { content: &'a TextComponent, overlay: bool, diff --git a/pumpkin-protocol/src/client/play/take_item.rs b/pumpkin-protocol/src/client/play/take_item.rs index 4366a7684..aada9f184 100644 --- a/pumpkin-protocol/src/client/play/take_item.rs +++ b/pumpkin-protocol/src/client/play/take_item.rs @@ -1,10 +1,10 @@ use crate::VarInt; use pumpkin_data::packet::clientbound::PLAY_TAKE_ITEM_ENTITY; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_TAKE_ITEM_ENTITY)] +#[packet(PLAY_TAKE_ITEM_ENTITY)] pub struct CTakeItemEntity { /// The Entity ID of the Item Entity entity_id: VarInt, diff --git a/pumpkin-protocol/src/client/play/teleport_entity.rs b/pumpkin-protocol/src/client/play/teleport_entity.rs index 789852406..51d07ce9e 100644 --- a/pumpkin-protocol/src/client/play/teleport_entity.rs +++ b/pumpkin-protocol/src/client/play/teleport_entity.rs @@ -1,11 +1,11 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::PLAY_TELEPORT_ENTITY; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; -use crate::{bytebuf::ByteBufMut, ClientPacket, PositionFlag, VarInt}; +use crate::{ClientPacket, PositionFlag, VarInt, bytebuf::ByteBufMut}; -#[client_packet(PLAY_TELEPORT_ENTITY)] +#[packet(PLAY_TELEPORT_ENTITY)] pub struct CTeleportEntity<'a> { entity_id: VarInt, position: Vector3, diff --git a/pumpkin-protocol/src/client/play/transfer.rs b/pumpkin-protocol/src/client/play/transfer.rs index 176859923..ae69b97ea 100644 --- a/pumpkin-protocol/src/client/play/transfer.rs +++ b/pumpkin-protocol/src/client/play/transfer.rs @@ -1,17 +1,17 @@ use crate::VarInt; use pumpkin_data::packet::clientbound::PLAY_TRANSFER; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(PLAY_TRANSFER)] +#[derive(Serialize, Deserialize)] +#[packet(PLAY_TRANSFER)] pub struct CTransfer<'a> { host: &'a str, - port: &'a VarInt, + port: VarInt, } impl<'a> CTransfer<'a> { - pub fn new(host: &'a str, port: &'a VarInt) -> Self { + pub fn new(host: &'a str, port: VarInt) -> Self { Self { host, port } } } diff --git a/pumpkin-protocol/src/client/play/unload_chunk.rs b/pumpkin-protocol/src/client/play/unload_chunk.rs index 582ba4877..8f0e6e2a6 100644 --- a/pumpkin-protocol/src/client/play/unload_chunk.rs +++ b/pumpkin-protocol/src/client/play/unload_chunk.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::PLAY_FORGET_LEVEL_CHUNK; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_FORGET_LEVEL_CHUNK)] +#[packet(PLAY_FORGET_LEVEL_CHUNK)] pub struct CUnloadChunk { z: i32, x: i32, diff --git a/pumpkin-protocol/src/client/play/update_entity_pos.rs b/pumpkin-protocol/src/client/play/update_entity_pos.rs index 1453e7f9c..041ca554b 100644 --- a/pumpkin-protocol/src/client/play/update_entity_pos.rs +++ b/pumpkin-protocol/src/client/play/update_entity_pos.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_MOVE_ENTITY_POS; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_MOVE_ENTITY_POS)] +#[packet(PLAY_MOVE_ENTITY_POS)] pub struct CUpdateEntityPos { entity_id: VarInt, delta: Vector3, diff --git a/pumpkin-protocol/src/client/play/update_entity_pos_rot.rs b/pumpkin-protocol/src/client/play/update_entity_pos_rot.rs index eb631fcec..1bfce165d 100644 --- a/pumpkin-protocol/src/client/play/update_entity_pos_rot.rs +++ b/pumpkin-protocol/src/client/play/update_entity_pos_rot.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::clientbound::PLAY_MOVE_ENTITY_POS_ROT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_MOVE_ENTITY_POS_ROT)] +#[packet(PLAY_MOVE_ENTITY_POS_ROT)] pub struct CUpdateEntityPosRot { entity_id: VarInt, delta: Vector3, diff --git a/pumpkin-protocol/src/client/play/update_entity_rot.rs b/pumpkin-protocol/src/client/play/update_entity_rot.rs index b0377b695..caaced687 100644 --- a/pumpkin-protocol/src/client/play/update_entity_rot.rs +++ b/pumpkin-protocol/src/client/play/update_entity_rot.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_MOVE_ENTITY_ROT; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::VarInt; #[derive(Serialize)] -#[client_packet(PLAY_MOVE_ENTITY_ROT)] +#[packet(PLAY_MOVE_ENTITY_ROT)] pub struct CUpdateEntityRot { entity_id: VarInt, yaw: u8, diff --git a/pumpkin-protocol/src/client/play/update_mob_effect.rs b/pumpkin-protocol/src/client/play/update_mob_effect.rs new file mode 100644 index 000000000..10ed5c4eb --- /dev/null +++ b/pumpkin-protocol/src/client/play/update_mob_effect.rs @@ -0,0 +1,33 @@ +use pumpkin_data::packet::clientbound::PLAY_UPDATE_MOB_EFFECT; +use pumpkin_macros::packet; +use serde::Serialize; + +use crate::codec::var_int::VarInt; + +#[derive(Serialize)] +#[packet(PLAY_UPDATE_MOB_EFFECT)] +pub struct CUpdateMobEffect { + entity_id: VarInt, + effect_id: VarInt, + amplifier: VarInt, + duration: VarInt, + flags: i8, +} + +impl CUpdateMobEffect { + pub fn new( + entity_id: VarInt, + effect_id: VarInt, + amplifier: VarInt, + duration: VarInt, + flags: i8, + ) -> Self { + Self { + entity_id, + effect_id, + amplifier, + duration, + flags, + } + } +} diff --git a/pumpkin-protocol/src/client/play/update_objectives.rs b/pumpkin-protocol/src/client/play/update_objectives.rs index b98fdff7b..12069480b 100644 --- a/pumpkin-protocol/src/client/play/update_objectives.rs +++ b/pumpkin-protocol/src/client/play/update_objectives.rs @@ -1,11 +1,11 @@ use bytes::BufMut; use pumpkin_data::packet::clientbound::PLAY_SET_OBJECTIVE; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use pumpkin_util::text::TextComponent; -use crate::{bytebuf::ByteBufMut, ClientPacket, NumberFormat, VarInt}; +use crate::{ClientPacket, NumberFormat, VarInt, bytebuf::ByteBufMut}; -#[client_packet(PLAY_SET_OBJECTIVE)] +#[packet(PLAY_SET_OBJECTIVE)] pub struct CUpdateObjectives<'a> { objective_name: &'a str, mode: u8, diff --git a/pumpkin-protocol/src/client/play/update_score.rs b/pumpkin-protocol/src/client/play/update_score.rs index d02a2bc09..bcad77c01 100644 --- a/pumpkin-protocol/src/client/play/update_score.rs +++ b/pumpkin-protocol/src/client/play/update_score.rs @@ -1,13 +1,13 @@ use pumpkin_data::packet::clientbound::PLAY_SET_SCORE; use pumpkin_util::text::TextComponent; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; use crate::{NumberFormat, VarInt}; #[derive(Serialize)] -#[client_packet(PLAY_SET_SCORE)] +#[packet(PLAY_SET_SCORE)] pub struct CUpdateScore<'a> { entity_name: &'a str, objective_name: &'a str, diff --git a/pumpkin-protocol/src/client/play/worldevent.rs b/pumpkin-protocol/src/client/play/worldevent.rs index c708bc9af..5da0922e2 100644 --- a/pumpkin-protocol/src/client/play/worldevent.rs +++ b/pumpkin-protocol/src/client/play/worldevent.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::clientbound::PLAY_LEVEL_EVENT; use pumpkin_util::math::position::BlockPos; -use pumpkin_macros::client_packet; +use pumpkin_macros::packet; use serde::Serialize; #[derive(Serialize)] -#[client_packet(PLAY_LEVEL_EVENT)] +#[packet(PLAY_LEVEL_EVENT)] pub struct CWorldEvent<'a> { event: i32, location: &'a BlockPos, diff --git a/pumpkin-protocol/src/client/status/ping_response.rs b/pumpkin-protocol/src/client/status/ping_response.rs index 1929a168d..ccba6de91 100644 --- a/pumpkin-protocol/src/client/status/ping_response.rs +++ b/pumpkin-protocol/src/client/status/ping_response.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::STATUS_PONG_RESPONSE; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(STATUS_PONG_RESPONSE)] +#[derive(Serialize, Deserialize)] +#[packet(STATUS_PONG_RESPONSE)] pub struct CPingResponse { payload: i64, // must respond with the same as in `SPingRequest` } diff --git a/pumpkin-protocol/src/client/status/status_response.rs b/pumpkin-protocol/src/client/status/status_response.rs index 2d918e9f4..51b197eee 100644 --- a/pumpkin-protocol/src/client/status/status_response.rs +++ b/pumpkin-protocol/src/client/status/status_response.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::clientbound::STATUS_STATUS_RESPONSE; -use pumpkin_macros::client_packet; -use serde::Serialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] -#[client_packet(STATUS_STATUS_RESPONSE)] +#[derive(Serialize, Deserialize)] +#[packet(STATUS_STATUS_RESPONSE)] pub struct CStatusResponse<'a> { json_response: &'a str, // 32767 } diff --git a/pumpkin-protocol/src/codec/bit_set.rs b/pumpkin-protocol/src/codec/bit_set.rs index 27aa329d3..3b7fe9341 100644 --- a/pumpkin-protocol/src/codec/bit_set.rs +++ b/pumpkin-protocol/src/codec/bit_set.rs @@ -6,7 +6,7 @@ use serde::{Serialize, Serializer}; use crate::bytebuf::ByteBuf; use crate::bytebuf::ByteBufMut; -use super::{var_int::VarInt, Codec, DecodeError}; +use super::{Codec, DecodeError, var_int::VarInt}; pub struct BitSet(pub VarInt, pub Vec); diff --git a/pumpkin-protocol/src/codec/identifier.rs b/pumpkin-protocol/src/codec/identifier.rs index 0c8fb4b58..896513f5a 100644 --- a/pumpkin-protocol/src/codec/identifier.rs +++ b/pumpkin-protocol/src/codec/identifier.rs @@ -1,7 +1,7 @@ use std::num::NonZeroUsize; use bytes::{Buf, BufMut}; -use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Visitor}; use crate::bytebuf::{ByteBuf, ByteBufMut}; diff --git a/pumpkin-protocol/src/codec/slot.rs b/pumpkin-protocol/src/codec/slot.rs index e3a754937..7596fa76f 100644 --- a/pumpkin-protocol/src/codec/slot.rs +++ b/pumpkin-protocol/src/codec/slot.rs @@ -3,8 +3,8 @@ use pumpkin_data::item::Item; use pumpkin_world::item::ItemStack; use serde::ser::SerializeSeq; use serde::{ - de::{self, SeqAccess}, Deserialize, Serialize, Serializer, + de::{self, SeqAccess}, }; #[derive(Debug, Clone)] @@ -130,13 +130,38 @@ impl Serialize for Slot { } impl Slot { - pub fn to_item(self) -> Option { - let item_id = self.item_id?.0.try_into().unwrap(); - let item = Item::from_id(item_id)?; - Some(ItemStack { - item, - item_count: self.item_count.0.try_into().unwrap(), - }) + pub fn new(item_id: u16, count: u32) -> Self { + Slot { + item_count: count.into(), + item_id: Some((item_id as i32).into()), + // TODO: add these + num_components_to_add: None, + num_components_to_remove: None, + components_to_add: None, + components_to_remove: None, + } + } + + pub fn to_stack(self) -> Result, &'static str> { + let item_id = self.item_id; + let Some(item_id) = item_id else { + return Ok(None); + }; + let item_id = item_id.0.try_into().map_err(|_| "Item id too large")?; + let item = Item::from_id(item_id).ok_or("Item id invalid")?; + if self.item_count.0 > item.components.max_stack_size as i32 { + Err("Over sized stack") + } else { + let stack = ItemStack { + item, + item_count: self + .item_count + .0 + .try_into() + .map_err(|_| "Stack count too large")?, + }; + Ok(Some(stack)) + } } pub const fn empty() -> Self { @@ -153,15 +178,7 @@ impl Slot { impl From<&ItemStack> for Slot { fn from(item: &ItemStack) -> Self { - Slot { - item_count: item.item_count.into(), - item_id: Some(VarInt(item.item.id as i32)), - // TODO: add these - num_components_to_add: None, - num_components_to_remove: None, - components_to_add: None, - components_to_remove: None, - } + Slot::new(item.item.id, item.item_count as u32) } } diff --git a/pumpkin-protocol/src/codec/var_int.rs b/pumpkin-protocol/src/codec/var_int.rs index 4f502687f..15f0dbce9 100644 --- a/pumpkin-protocol/src/codec/var_int.rs +++ b/pumpkin-protocol/src/codec/var_int.rs @@ -3,8 +3,8 @@ use std::{num::NonZeroUsize, ops::Deref}; use super::{Codec, DecodeError}; use bytes::{Buf, BufMut}; use serde::{ - de::{SeqAccess, Visitor}, Deserialize, Deserializer, Serialize, Serializer, + de::{SeqAccess, Visitor}, }; pub type VarIntType = i32; @@ -12,7 +12,7 @@ pub type VarIntType = i32; /** * A variable-length integer type used by the Minecraft network protocol. */ -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct VarInt(pub VarIntType); impl Codec for VarInt { diff --git a/pumpkin-protocol/src/codec/var_long.rs b/pumpkin-protocol/src/codec/var_long.rs index ceb2c1c99..c58c89fea 100644 --- a/pumpkin-protocol/src/codec/var_long.rs +++ b/pumpkin-protocol/src/codec/var_long.rs @@ -3,8 +3,8 @@ use std::{num::NonZeroUsize, ops::Deref}; use super::{Codec, DecodeError}; use bytes::{Buf, BufMut}; use serde::{ - de::{self, SeqAccess, Visitor}, Deserialize, Deserializer, Serialize, Serializer, + de::{self, SeqAccess, Visitor}, }; pub type VarLongType = i64; diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index d64ababab..5434d1c53 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -1,9 +1,9 @@ use std::num::NonZeroU16; -use bytebuf::{packet::Packet, ReadingError}; +use bytebuf::{ByteBufMut, ReadingError, packet::Packet}; use bytes::{Buf, BufMut, Bytes}; use codec::{identifier::Identifier, var_int::VarInt}; -use pumpkin_util::text::{style::Style, TextComponent}; +use pumpkin_util::text::{TextComponent, style::Style}; use serde::{Deserialize, Serialize, Serializer}; pub mod bytebuf; @@ -65,13 +65,33 @@ impl TryFrom for ConnectionState { } } -#[derive(Serialize)] +#[derive(Deserialize, Clone)] pub struct IDOrSoundEvent { pub id: VarInt, pub sound_event: Option, } -#[derive(Serialize)] +impl Serialize for IDOrSoundEvent { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut buf = Vec::new(); + buf.put_var_int(&self.id); + if self.id.0 == 0 { + if let Some(sound_event) = &self.sound_event { + buf.put_identifier(&sound_event.sound_name); + + buf.put_option(&sound_event.range, |p, v| { + p.put_f32(*v); + }); + } + } + serializer.serialize_bytes(&buf) + } +} + +#[derive(Serialize, Deserialize, Clone)] pub struct SoundEvent { pub sound_name: Identifier, pub range: Option, diff --git a/pumpkin-protocol/src/packet_decoder.rs b/pumpkin-protocol/src/packet_decoder.rs index 0f98e3c14..70efa434c 100644 --- a/pumpkin-protocol/src/packet_decoder.rs +++ b/pumpkin-protocol/src/packet_decoder.rs @@ -1,11 +1,11 @@ -use aes::cipher::{generic_array::GenericArray, BlockDecryptMut, BlockSizeUser, KeyIvInit}; +use aes::cipher::{BlockDecryptMut, BlockSizeUser, KeyIvInit, generic_array::GenericArray}; use bytes::{Buf, Bytes, BytesMut}; use libdeflater::{DecompressionError, Decompressor}; use thiserror::Error; use crate::{ + MAX_PACKET_SIZE, RawPacket, VarInt, codec::{Codec, DecodeError}, - RawPacket, VarInt, MAX_PACKET_SIZE, }; type Cipher = cfb8::Decryptor; @@ -193,8 +193,8 @@ mod tests { use super::*; use aes::Aes128; use bytes::BufMut; - use cfb8::cipher::AsyncStreamCipher; use cfb8::Encryptor as Cfb8Encryptor; + use cfb8::cipher::AsyncStreamCipher; use libdeflater::{CompressionLvl, Compressor}; /// Helper function to compress data using libdeflater's Zlib compressor diff --git a/pumpkin-protocol/src/packet_encoder.rs b/pumpkin-protocol/src/packet_encoder.rs index 1ea1f6818..a272083a8 100644 --- a/pumpkin-protocol/src/packet_encoder.rs +++ b/pumpkin-protocol/src/packet_encoder.rs @@ -1,11 +1,11 @@ -use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit}; +use aes::cipher::{BlockEncryptMut, BlockSizeUser, KeyIvInit, generic_array::GenericArray}; use bytes::{BufMut, BytesMut}; use thiserror::Error; use libdeflater::{CompressionLvl, Compressor}; use crate::{ - codec::Codec, ClientPacket, CompressionLevel, CompressionThreshold, VarInt, MAX_PACKET_SIZE, + ClientPacket, CompressionLevel, CompressionThreshold, MAX_PACKET_SIZE, VarInt, codec::Codec, }; type Cipher = cfb8::Encryptor; @@ -218,16 +218,16 @@ mod tests { use crate::client::status::CStatusResponse; use crate::{bytebuf::packet::Packet, codec::DecodeError}; use aes::Aes128; - use cfb8::cipher::AsyncStreamCipher; use cfb8::Decryptor as Cfb8Decryptor; + use cfb8::cipher::AsyncStreamCipher; use libdeflater::{DecompressionError, Decompressor}; use pumpkin_data::packet::clientbound::STATUS_STATUS_RESPONSE; - use pumpkin_macros::client_packet; + use pumpkin_macros::packet; use serde::Serialize; /// Define a custom packet for testing maximum packet size #[derive(Serialize)] - #[client_packet(STATUS_STATUS_RESPONSE)] + #[packet(STATUS_STATUS_RESPONSE)] pub struct MaxSizePacket { data: Vec, } diff --git a/pumpkin-protocol/src/server/config/acknowledge_finish_config.rs b/pumpkin-protocol/src/server/config/acknowledge_finish_config.rs index d57d7d130..e4c9c945a 100644 --- a/pumpkin-protocol/src/server/config/acknowledge_finish_config.rs +++ b/pumpkin-protocol/src/server/config/acknowledge_finish_config.rs @@ -1,6 +1,7 @@ use pumpkin_data::packet::serverbound::CONFIG_FINISH_CONFIGURATION; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; -#[derive(serde::Deserialize)] -#[server_packet(CONFIG_FINISH_CONFIGURATION)] -pub struct SAcknowledgeFinishConfig {} +#[derive(Serialize)] +#[packet(CONFIG_FINISH_CONFIGURATION)] +pub struct SAcknowledgeFinishConfig; diff --git a/pumpkin-protocol/src/server/config/client_information.rs b/pumpkin-protocol/src/server/config/client_information.rs index 0274128ba..19d21acf4 100644 --- a/pumpkin-protocol/src/server/config/client_information.rs +++ b/pumpkin-protocol/src/server/config/client_information.rs @@ -1,10 +1,11 @@ use pumpkin_data::packet::serverbound::CONFIG_CLIENT_INFORMATION; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; use crate::VarInt; -#[derive(serde::Deserialize)] -#[server_packet(CONFIG_CLIENT_INFORMATION)] +#[derive(serde::Deserialize, Serialize)] +#[packet(CONFIG_CLIENT_INFORMATION)] pub struct SClientInformationConfig { pub locale: String, // 16 pub view_distance: i8, diff --git a/pumpkin-protocol/src/server/config/cookie_response.rs b/pumpkin-protocol/src/server/config/cookie_response.rs index 3e1f874ea..ae80e766f 100644 --- a/pumpkin-protocol/src/server/config/cookie_response.rs +++ b/pumpkin-protocol/src/server/config/cookie_response.rs @@ -1,14 +1,14 @@ use bytes::Buf; use pumpkin_data::packet::serverbound::CONFIG_COOKIE_RESPONSE; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use crate::{ + ServerPacket, VarInt, bytebuf::{ByteBuf, ReadingError}, codec::identifier::Identifier, - ServerPacket, VarInt, }; -#[server_packet(CONFIG_COOKIE_RESPONSE)] +#[packet(CONFIG_COOKIE_RESPONSE)] /// Response to a Cookie Request (configuration) from the server. /// The Notchian (vanilla) server only accepts responses of up to 5 kiB in size. pub struct SConfigCookieResponse { diff --git a/pumpkin-protocol/src/server/config/known_packs.rs b/pumpkin-protocol/src/server/config/known_packs.rs index 4e10cc9ea..22b165dd3 100644 --- a/pumpkin-protocol/src/server/config/known_packs.rs +++ b/pumpkin-protocol/src/server/config/known_packs.rs @@ -1,10 +1,11 @@ use pumpkin_data::packet::serverbound::CONFIG_SELECT_KNOWN_PACKS; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; use crate::VarInt; -#[derive(serde::Deserialize)] -#[server_packet(CONFIG_SELECT_KNOWN_PACKS)] +#[derive(serde::Deserialize, Serialize)] +#[packet(CONFIG_SELECT_KNOWN_PACKS)] pub struct SKnownPacks { pub known_pack_count: VarInt, // known_packs: &'a [KnownPack] diff --git a/pumpkin-protocol/src/server/config/mod.rs b/pumpkin-protocol/src/server/config/mod.rs index 0a8c3d6fd..e7e779608 100644 --- a/pumpkin-protocol/src/server/config/mod.rs +++ b/pumpkin-protocol/src/server/config/mod.rs @@ -3,9 +3,11 @@ mod client_information; mod cookie_response; mod known_packs; mod plugin_message; +mod resource_pack_response; pub use acknowledge_finish_config::*; pub use client_information::*; pub use cookie_response::*; pub use known_packs::*; pub use plugin_message::*; +pub use resource_pack_response::*; diff --git a/pumpkin-protocol/src/server/config/plugin_message.rs b/pumpkin-protocol/src/server/config/plugin_message.rs index 9aa53ccf9..34d1f8cae 100644 --- a/pumpkin-protocol/src/server/config/plugin_message.rs +++ b/pumpkin-protocol/src/server/config/plugin_message.rs @@ -1,15 +1,15 @@ use bytes::Buf; use pumpkin_data::packet::serverbound::CONFIG_CUSTOM_PAYLOAD; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use crate::{ + ServerPacket, bytebuf::{ByteBuf, ReadingError}, codec::identifier::Identifier, - ServerPacket, }; const MAX_PAYLOAD_SIZE: usize = 1048576; -#[server_packet(CONFIG_CUSTOM_PAYLOAD)] +#[packet(CONFIG_CUSTOM_PAYLOAD)] pub struct SPluginMessage { pub channel: Identifier, pub data: bytes::Bytes, diff --git a/pumpkin-protocol/src/server/config/resource_pack_response.rs b/pumpkin-protocol/src/server/config/resource_pack_response.rs new file mode 100644 index 000000000..f067c6070 --- /dev/null +++ b/pumpkin-protocol/src/server/config/resource_pack_response.rs @@ -0,0 +1,41 @@ +use pumpkin_data::packet::serverbound::CONFIG_RESOURCE_PACK; +use pumpkin_macros::packet; +use serde::Serialize; + +use crate::VarInt; + +pub enum ResourcePackResponseResult { + DownloadSuccess, + DownloadFail, + Downloaded, + Accepted, + Declined, + InvalidUrl, + ReloadFailed, + Discarded, + Unknown(i32), +} + +#[derive(serde::Deserialize, Serialize)] +#[packet(CONFIG_RESOURCE_PACK)] +pub struct SConfigResourcePack { + #[serde(with = "uuid::serde::compact")] + pub uuid: uuid::Uuid, + result: VarInt, +} + +impl SConfigResourcePack { + pub fn response_result(&self) -> ResourcePackResponseResult { + match self.result.0 { + 0 => ResourcePackResponseResult::DownloadSuccess, + 1 => ResourcePackResponseResult::Declined, + 2 => ResourcePackResponseResult::DownloadFail, + 3 => ResourcePackResponseResult::Accepted, + 4 => ResourcePackResponseResult::Downloaded, + 5 => ResourcePackResponseResult::InvalidUrl, + 6 => ResourcePackResponseResult::ReloadFailed, + 7 => ResourcePackResponseResult::Discarded, + x => ResourcePackResponseResult::Unknown(x), + } + } +} diff --git a/pumpkin-protocol/src/server/handshake/mod.rs b/pumpkin-protocol/src/server/handshake/mod.rs index 268bd34ee..db3d5bb3d 100644 --- a/pumpkin-protocol/src/server/handshake/mod.rs +++ b/pumpkin-protocol/src/server/handshake/mod.rs @@ -1,13 +1,13 @@ -use bytes::Buf; -use pumpkin_data::packet::serverbound::HANDSHAKE_INTENTION; -use pumpkin_macros::server_packet; - +use crate::bytebuf::ByteBufMut; use crate::{ + ClientPacket, ConnectionState, ServerPacket, VarInt, bytebuf::{ByteBuf, ReadingError}, - ConnectionState, ServerPacket, VarInt, }; +use bytes::Buf; +use pumpkin_data::packet::serverbound::HANDSHAKE_INTENTION; +use pumpkin_macros::packet; -#[server_packet(HANDSHAKE_INTENTION)] +#[packet(HANDSHAKE_INTENTION)] pub struct SHandShake { pub protocol_version: VarInt, pub server_address: String, // 255 @@ -15,6 +15,15 @@ pub struct SHandShake { pub next_state: ConnectionState, } +impl ClientPacket for SHandShake { + fn write(&self, bytebuf: &mut impl bytes::BufMut) { + bytebuf.put_var_int(&self.protocol_version); + bytebuf.put_string_len(&self.server_address, 255); + bytebuf.put_u16(self.server_port); + bytebuf.put_var_int(&VarInt(self.next_state as i32)); + } +} + impl ServerPacket for SHandShake { fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { diff --git a/pumpkin-protocol/src/server/login/cookie_response.rs b/pumpkin-protocol/src/server/login/cookie_response.rs index 1d248b10b..7f536e9ce 100644 --- a/pumpkin-protocol/src/server/login/cookie_response.rs +++ b/pumpkin-protocol/src/server/login/cookie_response.rs @@ -1,13 +1,13 @@ use crate::{ + ServerPacket, VarInt, bytebuf::{ByteBuf, ReadingError}, codec::identifier::Identifier, - ServerPacket, VarInt, }; use bytes::Buf; use pumpkin_data::packet::serverbound::LOGIN_COOKIE_RESPONSE; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; -#[server_packet(LOGIN_COOKIE_RESPONSE)] +#[packet(LOGIN_COOKIE_RESPONSE)] /// Response to a Cookie Request (login) from the server. /// The Notchian server only accepts responses of up to 5 kiB in size. pub struct SLoginCookieResponse { diff --git a/pumpkin-protocol/src/server/login/encryption_response.rs b/pumpkin-protocol/src/server/login/encryption_response.rs index 32efa839c..0e481d8b5 100644 --- a/pumpkin-protocol/src/server/login/encryption_response.rs +++ b/pumpkin-protocol/src/server/login/encryption_response.rs @@ -1,13 +1,13 @@ use bytes::Buf; use pumpkin_data::packet::serverbound::LOGIN_KEY; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use crate::{ - bytebuf::{ByteBuf, ReadingError}, ServerPacket, VarInt, + bytebuf::{ByteBuf, ReadingError}, }; -#[server_packet(LOGIN_KEY)] +#[packet(LOGIN_KEY)] pub struct SEncryptionResponse { pub shared_secret_length: VarInt, pub shared_secret: bytes::Bytes, diff --git a/pumpkin-protocol/src/server/login/login_response.rs b/pumpkin-protocol/src/server/login/login_response.rs index 45c79871d..58731fa0d 100644 --- a/pumpkin-protocol/src/server/login/login_response.rs +++ b/pumpkin-protocol/src/server/login/login_response.rs @@ -1,7 +1,8 @@ use pumpkin_data::packet::serverbound::LOGIN_LOGIN_ACKNOWLEDGED; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; -// Acknowledgement to the Login Success packet sent to the server. -#[derive(serde::Deserialize)] -#[server_packet(LOGIN_LOGIN_ACKNOWLEDGED)] -pub struct SLoginAcknowledged {} +/// Acknowledgement to the Login Success packet sent to the server. +#[derive(Serialize)] +#[packet(LOGIN_LOGIN_ACKNOWLEDGED)] +pub struct SLoginAcknowledged; diff --git a/pumpkin-protocol/src/server/login/login_start.rs b/pumpkin-protocol/src/server/login/login_start.rs index 2e684021f..a07bda3b5 100644 --- a/pumpkin-protocol/src/server/login/login_start.rs +++ b/pumpkin-protocol/src/server/login/login_start.rs @@ -1,18 +1,26 @@ +use crate::bytebuf::ByteBufMut; use bytes::Buf; use pumpkin_data::packet::serverbound::LOGIN_HELLO; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use crate::{ + ClientPacket, ServerPacket, bytebuf::{ByteBuf, ReadingError}, - ServerPacket, }; -#[server_packet(LOGIN_HELLO)] +#[packet(LOGIN_HELLO)] pub struct SLoginStart { pub name: String, // 16 pub uuid: uuid::Uuid, } +impl ClientPacket for SLoginStart { + fn write(&self, bytebuf: &mut impl bytes::BufMut) { + bytebuf.put_string_len(&self.name, 16); + bytebuf.put_uuid(&self.uuid); + } +} + impl ServerPacket for SLoginStart { fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { diff --git a/pumpkin-protocol/src/server/login/plugin_response.rs b/pumpkin-protocol/src/server/login/plugin_response.rs index 16f5c0850..1d731192c 100644 --- a/pumpkin-protocol/src/server/login/plugin_response.rs +++ b/pumpkin-protocol/src/server/login/plugin_response.rs @@ -1,14 +1,14 @@ use crate::{ - bytebuf::{ByteBuf, ReadingError}, ServerPacket, VarInt, + bytebuf::{ByteBuf, ReadingError}, }; use bytes::{Buf, Bytes}; use pumpkin_data::packet::serverbound::LOGIN_CUSTOM_QUERY_ANSWER; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; const MAX_PAYLOAD_SIZE: usize = 1048576; -#[server_packet(LOGIN_CUSTOM_QUERY_ANSWER)] +#[packet(LOGIN_CUSTOM_QUERY_ANSWER)] pub struct SLoginPluginResponse { pub message_id: VarInt, pub data: Option, diff --git a/pumpkin-protocol/src/server/play/chat_command.rs b/pumpkin-protocol/src/server/play/chat_command.rs index f52670dfd..510417fd8 100644 --- a/pumpkin-protocol/src/server/play/chat_command.rs +++ b/pumpkin-protocol/src/server/play/chat_command.rs @@ -1,8 +1,9 @@ use pumpkin_data::packet::serverbound::PLAY_CHAT_COMMAND; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; -#[derive(serde::Deserialize)] -#[server_packet(PLAY_CHAT_COMMAND)] +#[derive(serde::Deserialize, Serialize)] +#[packet(PLAY_CHAT_COMMAND)] pub struct SChatCommand { pub command: String, } diff --git a/pumpkin-protocol/src/server/play/chat_message.rs b/pumpkin-protocol/src/server/play/chat_message.rs index 0fac277c1..1e0e890c7 100644 --- a/pumpkin-protocol/src/server/play/chat_message.rs +++ b/pumpkin-protocol/src/server/play/chat_message.rs @@ -1,33 +1,54 @@ -use bytes::{Buf, Bytes}; +use bytes::Buf; use pumpkin_data::packet::serverbound::PLAY_CHAT; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; use crate::{ + ServerPacket, VarInt, bytebuf::{ByteBuf, ReadingError}, - FixedBitSet, ServerPacket, VarInt, }; -// derive(Deserialize)] -#[server_packet(PLAY_CHAT)] +#[derive(Serialize)] +#[packet(PLAY_CHAT)] pub struct SChatMessage { pub message: String, pub timestamp: i64, pub salt: i64, - pub signature: Option, + pub signature: Option>, pub message_count: VarInt, - pub acknowledged: FixedBitSet, + pub acknowledged: Vec, +} + +impl SChatMessage { + pub fn new( + message: String, + timestamp: i64, + salt: i64, + signature: Option>, + message_count: VarInt, + acknowledged: Vec, + ) -> Self { + Self { + message, + timestamp, + salt, + signature, + message_count, + acknowledged, + } + } } // TODO impl ServerPacket for SChatMessage { fn read(bytebuf: &mut impl Buf) -> Result { Ok(Self { - message: bytebuf.try_get_string()?, + message: bytebuf.try_get_string_len(256)?, timestamp: bytebuf.try_get_i64()?, salt: bytebuf.try_get_i64()?, - signature: bytebuf.try_get_option(|v| v.try_copy_to_bytes(256))?, + signature: bytebuf.try_get_option(|v| v.try_copy_to_bytes(256).map(|s| s.to_vec()))?, message_count: bytebuf.try_get_var_int()?, - acknowledged: bytebuf.try_get_fixed_bitset(20)?, + acknowledged: bytebuf.try_get_fixed_bitset(20).map(|s| s.to_vec())?, }) } } diff --git a/pumpkin-protocol/src/server/play/click_container.rs b/pumpkin-protocol/src/server/play/click_container.rs index e155b5be2..a246ec361 100644 --- a/pumpkin-protocol/src/server/play/click_container.rs +++ b/pumpkin-protocol/src/server/play/click_container.rs @@ -1,11 +1,12 @@ -use crate::codec::slot::Slot; use crate::VarInt; +use crate::codec::slot::Slot; use pumpkin_data::packet::serverbound::PLAY_CONTAINER_CLICK; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use serde::de::SeqAccess; -use serde::{de, Deserialize}; +use serde::{Deserialize, de}; -#[server_packet(PLAY_CONTAINER_CLICK)] +#[derive(Debug)] +#[packet(PLAY_CONTAINER_CLICK)] pub struct SClickContainer { pub window_id: VarInt, pub state_id: VarInt, @@ -86,7 +87,7 @@ impl<'de> Deserialize<'de> for SClickContainer { } } -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] pub enum SlotActionType { /// Performs a normal slot click. This can pickup or place items in the slot, possibly merging the cursor stack into the slot, or swapping the slot stack with the cursor stack if they can't be merged. Pickup, diff --git a/pumpkin-protocol/src/server/play/client_command.rs b/pumpkin-protocol/src/server/play/client_command.rs index 4c8a7a0ed..9e9dce972 100644 --- a/pumpkin-protocol/src/server/play/client_command.rs +++ b/pumpkin-protocol/src/server/play/client_command.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_CLIENT_COMMAND; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use serde::Deserialize; use crate::VarInt; #[derive(Deserialize)] -#[server_packet(PLAY_CLIENT_COMMAND)] +#[packet(PLAY_CLIENT_COMMAND)] pub struct SClientCommand { pub action_id: VarInt, } diff --git a/pumpkin-protocol/src/server/play/client_information.rs b/pumpkin-protocol/src/server/play/client_information.rs index 898bf1590..39587a19d 100644 --- a/pumpkin-protocol/src/server/play/client_information.rs +++ b/pumpkin-protocol/src/server/play/client_information.rs @@ -1,10 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_CLIENT_INFORMATION; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; use crate::VarInt; -#[derive(serde::Deserialize)] -#[server_packet(PLAY_CLIENT_INFORMATION)] +#[derive(serde::Deserialize, Serialize)] +#[packet(PLAY_CLIENT_INFORMATION)] pub struct SClientInformationPlay { pub locale: String, // 16 pub view_distance: i8, diff --git a/pumpkin-protocol/src/server/play/client_tick_end.rs b/pumpkin-protocol/src/server/play/client_tick_end.rs index 2602250db..16683bb6a 100644 --- a/pumpkin-protocol/src/server/play/client_tick_end.rs +++ b/pumpkin-protocol/src/server/play/client_tick_end.rs @@ -1,6 +1,5 @@ use pumpkin_data::packet::serverbound::PLAY_CLIENT_TICK_END; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; -#[derive(serde::Deserialize)] -#[server_packet(PLAY_CLIENT_TICK_END)] -pub struct SClientTickEnd {} +#[packet(PLAY_CLIENT_TICK_END)] +pub struct SClientTickEnd; diff --git a/pumpkin-protocol/src/server/play/close_container.rs b/pumpkin-protocol/src/server/play/close_container.rs index 0f080e6db..a5b092738 100644 --- a/pumpkin-protocol/src/server/play/close_container.rs +++ b/pumpkin-protocol/src/server/play/close_container.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_CONTAINER_CLOSE; -use pumpkin_macros::server_packet; -use serde::Deserialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; use crate::VarInt; -#[derive(Deserialize)] -#[server_packet(PLAY_CONTAINER_CLOSE)] +#[derive(Deserialize, Serialize)] +#[packet(PLAY_CONTAINER_CLOSE)] pub struct SCloseContainer { pub window_id: VarInt, } diff --git a/pumpkin-protocol/src/server/play/command_suggestion.rs b/pumpkin-protocol/src/server/play/command_suggestion.rs index 5cd455e96..346c9f62e 100644 --- a/pumpkin-protocol/src/server/play/command_suggestion.rs +++ b/pumpkin-protocol/src/server/play/command_suggestion.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_COMMAND_SUGGESTION; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use serde::Deserialize; use crate::VarInt; #[derive(Deserialize)] -#[server_packet(PLAY_COMMAND_SUGGESTION)] +#[packet(PLAY_COMMAND_SUGGESTION)] pub struct SCommandSuggestion { pub id: VarInt, pub command: String, diff --git a/pumpkin-protocol/src/server/play/confirm_teleport.rs b/pumpkin-protocol/src/server/play/confirm_teleport.rs index 4909fa771..9f9b70077 100644 --- a/pumpkin-protocol/src/server/play/confirm_teleport.rs +++ b/pumpkin-protocol/src/server/play/confirm_teleport.rs @@ -1,10 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_ACCEPT_TELEPORTATION; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; use crate::VarInt; -#[derive(serde::Deserialize)] -#[server_packet(PLAY_ACCEPT_TELEPORTATION)] +#[derive(serde::Deserialize, Serialize)] +#[packet(PLAY_ACCEPT_TELEPORTATION)] pub struct SConfirmTeleport { pub teleport_id: VarInt, } diff --git a/pumpkin-protocol/src/server/play/cookie_response.rs b/pumpkin-protocol/src/server/play/cookie_response.rs index fa26163a2..efe1a7bfa 100644 --- a/pumpkin-protocol/src/server/play/cookie_response.rs +++ b/pumpkin-protocol/src/server/play/cookie_response.rs @@ -1,13 +1,13 @@ use crate::{ + ServerPacket, VarInt, bytebuf::{ByteBuf, ReadingError}, codec::identifier::Identifier, - ServerPacket, VarInt, }; use bytes::Buf; use pumpkin_data::packet::serverbound::PLAY_COOKIE_RESPONSE; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; -#[server_packet(PLAY_COOKIE_RESPONSE)] +#[packet(PLAY_COOKIE_RESPONSE)] /// Response to a Cookie Request (play) from the server. /// The Notchian (vanilla) server only accepts responses of up to 5 kiB in size. pub struct SCookieResponse { diff --git a/pumpkin-protocol/src/server/play/interact.rs b/pumpkin-protocol/src/server/play/interact.rs index e7a68532d..17e4fac47 100644 --- a/pumpkin-protocol/src/server/play/interact.rs +++ b/pumpkin-protocol/src/server/play/interact.rs @@ -1,14 +1,14 @@ use bytes::Buf; use pumpkin_data::packet::serverbound::PLAY_INTERACT; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; use crate::{ - bytebuf::{ByteBuf, ReadingError}, ServerPacket, VarInt, + bytebuf::{ByteBuf, ReadingError}, }; -#[server_packet(PLAY_INTERACT)] +#[packet(PLAY_INTERACT)] pub struct SInteract { pub entity_id: VarInt, pub typ: VarInt, diff --git a/pumpkin-protocol/src/server/play/keep_alive.rs b/pumpkin-protocol/src/server/play/keep_alive.rs index c49be01a0..f5039e69e 100644 --- a/pumpkin-protocol/src/server/play/keep_alive.rs +++ b/pumpkin-protocol/src/server/play/keep_alive.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::serverbound::PLAY_KEEP_ALIVE; -use pumpkin_macros::server_packet; -use serde::Deserialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Deserialize)] -#[server_packet(PLAY_KEEP_ALIVE)] +#[derive(Deserialize, Serialize)] +#[packet(PLAY_KEEP_ALIVE)] pub struct SKeepAlive { pub keep_alive_id: i64, } diff --git a/pumpkin-protocol/src/server/play/pick_item.rs b/pumpkin-protocol/src/server/play/pick_item.rs index 99a12177c..5fe0477ae 100644 --- a/pumpkin-protocol/src/server/play/pick_item.rs +++ b/pumpkin-protocol/src/server/play/pick_item.rs @@ -1,17 +1,17 @@ use pumpkin_data::packet::serverbound::{PLAY_PICK_ITEM_FROM_BLOCK, PLAY_PICK_ITEM_FROM_ENTITY}; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; use serde::Deserialize; #[derive(Deserialize)] -#[server_packet(PLAY_PICK_ITEM_FROM_BLOCK)] +#[packet(PLAY_PICK_ITEM_FROM_BLOCK)] pub struct SPickItemFromBlock { pub pos: BlockPos, pub include_data: bool, } #[derive(Deserialize)] -#[server_packet(PLAY_PICK_ITEM_FROM_ENTITY)] +#[packet(PLAY_PICK_ITEM_FROM_ENTITY)] pub struct SPickItemFromEntity { pub id: i32, pub include_data: bool, diff --git a/pumpkin-protocol/src/server/play/ping_request.rs b/pumpkin-protocol/src/server/play/ping_request.rs index 12c493c11..160d51f83 100644 --- a/pumpkin-protocol/src/server/play/ping_request.rs +++ b/pumpkin-protocol/src/server/play/ping_request.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::serverbound::PLAY_PING_REQUEST; -use pumpkin_macros::server_packet; -use serde::Deserialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Deserialize)] -#[server_packet(PLAY_PING_REQUEST)] +#[derive(Deserialize, Serialize)] +#[packet(PLAY_PING_REQUEST)] pub struct SPlayPingRequest { pub payload: i64, } diff --git a/pumpkin-protocol/src/server/play/player_abilities.rs b/pumpkin-protocol/src/server/play/player_abilities.rs index e4e8a3c02..2faf1e167 100644 --- a/pumpkin-protocol/src/server/play/player_abilities.rs +++ b/pumpkin-protocol/src/server/play/player_abilities.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_PLAYER_ABILITIES; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use serde::Deserialize; //The vanilla client sends this packet when the player starts/stops flying. Bitmask 0x02 is set when the player is flying. #[derive(Deserialize)] -#[server_packet(PLAY_PLAYER_ABILITIES)] +#[packet(PLAY_PLAYER_ABILITIES)] pub struct SPlayerAbilities { pub flags: i8, } diff --git a/pumpkin-protocol/src/server/play/player_action.rs b/pumpkin-protocol/src/server/play/player_action.rs index 1a233f897..d552e5556 100644 --- a/pumpkin-protocol/src/server/play/player_action.rs +++ b/pumpkin-protocol/src/server/play/player_action.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_PLAYER_ACTION; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; use crate::VarInt; #[derive(serde::Deserialize)] -#[server_packet(PLAY_PLAYER_ACTION)] +#[packet(PLAY_PLAYER_ACTION)] pub struct SPlayerAction { pub status: VarInt, pub location: BlockPos, diff --git a/pumpkin-protocol/src/server/play/player_command.rs b/pumpkin-protocol/src/server/play/player_command.rs index a946a07c3..e8b0de964 100644 --- a/pumpkin-protocol/src/server/play/player_command.rs +++ b/pumpkin-protocol/src/server/play/player_command.rs @@ -1,13 +1,13 @@ use bytes::Buf; use pumpkin_data::packet::serverbound::PLAY_PLAYER_COMMAND; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use crate::{ - bytebuf::{ByteBuf, ReadingError}, ServerPacket, VarInt, + bytebuf::{ByteBuf, ReadingError}, }; -#[server_packet(PLAY_PLAYER_COMMAND)] +#[packet(PLAY_PLAYER_COMMAND)] pub struct SPlayerCommand { pub entity_id: VarInt, pub action: VarInt, diff --git a/pumpkin-protocol/src/server/play/player_ground.rs b/pumpkin-protocol/src/server/play/player_ground.rs index 4cac6bde1..4bdded1e7 100644 --- a/pumpkin-protocol/src/server/play/player_ground.rs +++ b/pumpkin-protocol/src/server/play/player_ground.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::serverbound::PLAY_MOVE_PLAYER_STATUS_ONLY; -use pumpkin_macros::server_packet; -use serde::Deserialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Deserialize)] -#[server_packet(PLAY_MOVE_PLAYER_STATUS_ONLY)] +#[derive(Deserialize, Serialize)] +#[packet(PLAY_MOVE_PLAYER_STATUS_ONLY)] pub struct SSetPlayerGround { pub on_ground: bool, } diff --git a/pumpkin-protocol/src/server/play/player_input.rs b/pumpkin-protocol/src/server/play/player_input.rs index c1693cadf..4a17ebf6c 100644 --- a/pumpkin-protocol/src/server/play/player_input.rs +++ b/pumpkin-protocol/src/server/play/player_input.rs @@ -1,8 +1,8 @@ use pumpkin_data::packet::serverbound::PLAY_PLAYER_INPUT; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; #[derive(serde::Deserialize)] -#[server_packet(PLAY_PLAYER_INPUT)] +#[packet(PLAY_PLAYER_INPUT)] pub struct SPlayerInput { // Yep exactly how it looks like _input: i8, diff --git a/pumpkin-protocol/src/server/play/player_loaded.rs b/pumpkin-protocol/src/server/play/player_loaded.rs index 10c56c542..f9e60029d 100644 --- a/pumpkin-protocol/src/server/play/player_loaded.rs +++ b/pumpkin-protocol/src/server/play/player_loaded.rs @@ -1,6 +1,5 @@ use pumpkin_data::packet::serverbound::PLAY_PLAYER_LOADED; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; -#[derive(serde::Deserialize)] -#[server_packet(PLAY_PLAYER_LOADED)] +#[packet(PLAY_PLAYER_LOADED)] pub struct SPlayerLoaded; diff --git a/pumpkin-protocol/src/server/play/player_position.rs b/pumpkin-protocol/src/server/play/player_position.rs index 09a6ea818..84395b056 100644 --- a/pumpkin-protocol/src/server/play/player_position.rs +++ b/pumpkin-protocol/src/server/play/player_position.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::serverbound::PLAY_MOVE_PLAYER_POS; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; #[derive(serde::Deserialize)] -#[server_packet(PLAY_MOVE_PLAYER_POS)] +#[packet(PLAY_MOVE_PLAYER_POS)] pub struct SPlayerPosition { pub position: Vector3, pub ground: bool, diff --git a/pumpkin-protocol/src/server/play/player_position_rotation.rs b/pumpkin-protocol/src/server/play/player_position_rotation.rs index a3376fea5..690267a3e 100644 --- a/pumpkin-protocol/src/server/play/player_position_rotation.rs +++ b/pumpkin-protocol/src/server/play/player_position_rotation.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::serverbound::PLAY_MOVE_PLAYER_POS_ROT; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use pumpkin_util::math::vector3::Vector3; #[derive(serde::Deserialize)] -#[server_packet(PLAY_MOVE_PLAYER_POS_ROT)] +#[packet(PLAY_MOVE_PLAYER_POS_ROT)] pub struct SPlayerPositionRotation { pub position: Vector3, pub yaw: f32, diff --git a/pumpkin-protocol/src/server/play/player_rotation.rs b/pumpkin-protocol/src/server/play/player_rotation.rs index 512b5219f..7fabeb3cc 100644 --- a/pumpkin-protocol/src/server/play/player_rotation.rs +++ b/pumpkin-protocol/src/server/play/player_rotation.rs @@ -1,8 +1,8 @@ use pumpkin_data::packet::serverbound::PLAY_MOVE_PLAYER_ROT; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; #[derive(serde::Deserialize)] -#[server_packet(PLAY_MOVE_PLAYER_ROT)] +#[packet(PLAY_MOVE_PLAYER_ROT)] pub struct SPlayerRotation { pub yaw: f32, pub pitch: f32, diff --git a/pumpkin-protocol/src/server/play/set_creative_slot.rs b/pumpkin-protocol/src/server/play/set_creative_slot.rs index 849a48562..44a56dd84 100644 --- a/pumpkin-protocol/src/server/play/set_creative_slot.rs +++ b/pumpkin-protocol/src/server/play/set_creative_slot.rs @@ -1,10 +1,10 @@ use pumpkin_data::packet::serverbound::PLAY_SET_CREATIVE_MODE_SLOT; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use crate::codec::slot::Slot; #[derive(serde::Deserialize, Debug)] -#[server_packet(PLAY_SET_CREATIVE_MODE_SLOT)] +#[packet(PLAY_SET_CREATIVE_MODE_SLOT)] pub struct SSetCreativeSlot { pub slot: i16, pub clicked_item: Slot, diff --git a/pumpkin-protocol/src/server/play/set_held_item.rs b/pumpkin-protocol/src/server/play/set_held_item.rs index 3c2ecefc7..7d568116f 100644 --- a/pumpkin-protocol/src/server/play/set_held_item.rs +++ b/pumpkin-protocol/src/server/play/set_held_item.rs @@ -1,9 +1,9 @@ use pumpkin_data::packet::serverbound::PLAY_SET_CARRIED_ITEM; -use pumpkin_macros::server_packet; -use serde::Deserialize; +use pumpkin_macros::packet; +use serde::{Deserialize, Serialize}; -#[derive(Deserialize)] -#[server_packet(PLAY_SET_CARRIED_ITEM)] +#[derive(Deserialize, Serialize)] +#[packet(PLAY_SET_CARRIED_ITEM)] pub struct SSetHeldItem { pub slot: i16, } diff --git a/pumpkin-protocol/src/server/play/swing_arm.rs b/pumpkin-protocol/src/server/play/swing_arm.rs index 5134d15c5..25a3b6324 100644 --- a/pumpkin-protocol/src/server/play/swing_arm.rs +++ b/pumpkin-protocol/src/server/play/swing_arm.rs @@ -1,10 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_SWING; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; use crate::VarInt; -#[derive(serde::Deserialize)] -#[server_packet(PLAY_SWING)] +#[derive(serde::Deserialize, Serialize)] +#[packet(PLAY_SWING)] pub struct SSwingArm { pub hand: VarInt, } diff --git a/pumpkin-protocol/src/server/play/update_sign.rs b/pumpkin-protocol/src/server/play/update_sign.rs index 8427ea9fb..6a9ed0e1e 100644 --- a/pumpkin-protocol/src/server/play/update_sign.rs +++ b/pumpkin-protocol/src/server/play/update_sign.rs @@ -1,14 +1,14 @@ use bytes::Buf; use pumpkin_data::packet::serverbound::PLAY_SIGN_UPDATE; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use pumpkin_util::math::position::BlockPos; use crate::{ - bytebuf::{ByteBuf, ReadingError}, ServerPacket, + bytebuf::{ByteBuf, ReadingError}, }; -#[server_packet(PLAY_SIGN_UPDATE)] +#[packet(PLAY_SIGN_UPDATE)] pub struct SUpdateSign { pub location: BlockPos, pub is_front_text: bool, diff --git a/pumpkin-protocol/src/server/play/use_item.rs b/pumpkin-protocol/src/server/play/use_item.rs index 03abfc98c..05e9b2d3d 100644 --- a/pumpkin-protocol/src/server/play/use_item.rs +++ b/pumpkin-protocol/src/server/play/use_item.rs @@ -1,11 +1,11 @@ use pumpkin_data::packet::serverbound::PLAY_USE_ITEM; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use serde::Deserialize; use crate::VarInt; #[derive(Deserialize)] -#[server_packet(PLAY_USE_ITEM)] +#[packet(PLAY_USE_ITEM)] pub struct SUseItem { // 0 for main hand, 1 for off hand pub hand: VarInt, diff --git a/pumpkin-protocol/src/server/play/use_item_on.rs b/pumpkin-protocol/src/server/play/use_item_on.rs index d0d015881..436c0c2c7 100644 --- a/pumpkin-protocol/src/server/play/use_item_on.rs +++ b/pumpkin-protocol/src/server/play/use_item_on.rs @@ -1,12 +1,12 @@ use pumpkin_data::packet::serverbound::PLAY_USE_ITEM_ON; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; use serde::Deserialize; use crate::VarInt; #[derive(Deserialize)] -#[server_packet(PLAY_USE_ITEM_ON)] +#[packet(PLAY_USE_ITEM_ON)] pub struct SUseItemOn { pub hand: VarInt, pub location: BlockPos, diff --git a/pumpkin-protocol/src/server/status/ping_request.rs b/pumpkin-protocol/src/server/status/ping_request.rs index 1c46e7d8b..090dde1ca 100644 --- a/pumpkin-protocol/src/server/status/ping_request.rs +++ b/pumpkin-protocol/src/server/status/ping_request.rs @@ -1,8 +1,9 @@ use pumpkin_data::packet::serverbound::STATUS_PING_REQUEST; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; -#[derive(serde::Deserialize)] -#[server_packet(STATUS_PING_REQUEST)] +#[derive(serde::Deserialize, Serialize)] +#[packet(STATUS_PING_REQUEST)] pub struct SStatusPingRequest { pub payload: i64, } diff --git a/pumpkin-protocol/src/server/status/status_request.rs b/pumpkin-protocol/src/server/status/status_request.rs index 07f22dade..c68a43b77 100644 --- a/pumpkin-protocol/src/server/status/status_request.rs +++ b/pumpkin-protocol/src/server/status/status_request.rs @@ -1,8 +1,7 @@ use pumpkin_data::packet::serverbound::STATUS_STATUS_REQUEST; -use pumpkin_macros::server_packet; +use pumpkin_macros::packet; +use serde::Serialize; -#[derive(serde::Deserialize)] -#[server_packet(STATUS_STATUS_REQUEST)] -pub struct SStatusRequest { - // empty -} +#[derive(Serialize)] +#[packet(STATUS_STATUS_REQUEST)] +pub struct SStatusRequest; diff --git a/pumpkin-registry/src/lib.rs b/pumpkin-registry/src/lib.rs index 0f8391753..f71392182 100644 --- a/pumpkin-registry/src/lib.rs +++ b/pumpkin-registry/src/lib.rs @@ -11,7 +11,7 @@ use instrument::Instrument; use jukebox_song::JukeboxSong; use paint::Painting; use pumpkin_protocol::{client::config::RegistryEntry, codec::identifier::Identifier}; -pub use recipe::{flatten_3x3, Recipe, RecipeResult, RecipeType, RECIPES}; +pub use recipe::{RECIPES, Recipe, RecipeResult, RecipeType, flatten_3x3}; use serde::{Deserialize, Serialize}; use trim_material::TrimMaterial; use trim_pattern::TrimPattern; diff --git a/pumpkin-registry/src/recipe/read.rs b/pumpkin-registry/src/recipe/read.rs index 90664450a..3132f282a 100644 --- a/pumpkin-registry/src/recipe/read.rs +++ b/pumpkin-registry/src/recipe/read.rs @@ -1,13 +1,13 @@ use crate::flatten_3x3; -use crate::recipe::read::ingredients::Ingredients; use crate::recipe::read::SpecialCraftingType::{ ArmorDye, BannerDuplicate, BookCloning, Firework, RepairItem, ShieldDecoration, ShulkerboxColoring, SuspiciousStew, TippedArrow, }; +use crate::recipe::read::ingredients::Ingredients; use crate::recipe::recipe_formats::{ShapedCrafting, ShapelessCrafting}; use pumpkin_data::tag::RegistryEntryList; use serde::de::{Error, MapAccess, Visitor}; -use serde::{de, Deserialize, Deserializer}; +use serde::{Deserialize, Deserializer, de}; use std::collections::HashMap; use std::fmt::Formatter; use std::str::FromStr; diff --git a/pumpkin-util/Cargo.toml b/pumpkin-util/Cargo.toml index 0cb0be940..1617dc26f 100644 --- a/pumpkin-util/Cargo.toml +++ b/pumpkin-util/Cargo.toml @@ -8,7 +8,8 @@ pumpkin-nbt = { path = "../pumpkin-nbt" } serde.workspace = true serde_json.workspace = true bytes.workspace = true -uuid.workspace = true +rand = "0.9" + num-traits = "0.2" diff --git a/pumpkin-util/src/lib.rs b/pumpkin-util/src/lib.rs index 2e635f1f4..ab2b790bc 100644 --- a/pumpkin-util/src/lib.rs +++ b/pumpkin-util/src/lib.rs @@ -5,6 +5,8 @@ pub mod random; pub mod text; pub mod translation; +use std::ops::{Index, IndexMut}; + pub use gamemode::GameMode; pub use permission::PermissionLvl; @@ -25,6 +27,60 @@ pub enum ProfileAction { UsingBannedSkin, } +/// Takes a mutable reference of an index and returns a mutable "slice" where we can mutate both at +/// the same time +pub struct MutableSplitSlice<'a, T> { + start: &'a mut [T], + end: &'a mut [T], +} + +impl<'a, T> MutableSplitSlice<'a, T> { + pub fn extract_ith(base: &'a mut [T], index: usize) -> (&'a mut T, Self) { + let (start, end_inclusive) = base.split_at_mut(index); + let (value, end) = end_inclusive + .split_first_mut() + .expect("Index is not in base slice"); + + (value, Self { start, end }) + } + + pub fn len(&self) -> usize { + self.start.len() + self.end.len() + 1 + } + + pub fn is_empty(&self) -> bool { + false + } +} + +impl Index for MutableSplitSlice<'_, T> { + type Output = T; + + #[allow(clippy::comparison_chain)] + fn index(&self, index: usize) -> &Self::Output { + if index < self.start.len() { + &self.start[index] + } else if index == self.start.len() { + panic!("We tried to index into the element that was removed"); + } else { + &self.end[index - self.start.len() - 1] + } + } +} + +impl IndexMut for MutableSplitSlice<'_, T> { + #[allow(clippy::comparison_chain)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + if index < self.start.len() { + &mut self.start[index] + } else if index == self.start.len() { + panic!("We tried to index into the element that was removed"); + } else { + &mut self.end[index - self.start.len() - 1] + } + } +} + #[macro_export] macro_rules! assert_eq_delta { ($x:expr, $y:expr, $d:expr) => { diff --git a/pumpkin-util/src/math/int_provider.rs b/pumpkin-util/src/math/int_provider.rs new file mode 100644 index 000000000..b7f447d1f --- /dev/null +++ b/pumpkin-util/src/math/int_provider.rs @@ -0,0 +1,63 @@ +use serde::Deserialize; + +#[derive(Deserialize, Clone)] +#[serde(tag = "type")] +pub enum NormalInvProvider { + #[serde(rename = "minecraft:uniform")] + Uniform(UniformIntProvider), + // TODO: Add more... +} + +#[derive(Deserialize, Clone)] +#[serde(untagged)] +pub enum InvProvider { + Object(NormalInvProvider), + Constant(i32), +} + +impl InvProvider { + pub fn get_min(&self) -> i32 { + match self { + InvProvider::Object(inv_provider) => match inv_provider { + NormalInvProvider::Uniform(uniform) => uniform.get_min(), + }, + InvProvider::Constant(i) => *i, + } + } + + pub fn get(&self) -> i32 { + match self { + InvProvider::Object(inv_provider) => match inv_provider { + NormalInvProvider::Uniform(uniform) => uniform.get(), + }, + InvProvider::Constant(i) => *i, + } + } + + pub fn get_max(&self) -> i32 { + match self { + InvProvider::Object(inv_provider) => match inv_provider { + NormalInvProvider::Uniform(uniform) => uniform.get_max(), + }, + InvProvider::Constant(i) => *i, + } + } +} + +#[derive(Deserialize, Clone)] +pub struct UniformIntProvider { + min_inclusive: i32, + max_inclusive: i32, +} + +impl UniformIntProvider { + pub fn get_min(&self) -> i32 { + self.min_inclusive + } + pub fn get(&self) -> i32 { + rand::random_range(self.min_inclusive..self.max_inclusive) + } + pub fn get_max(&self) -> i32 { + self.max_inclusive + } +} diff --git a/pumpkin-util/src/math/mod.rs b/pumpkin-util/src/math/mod.rs index 17b8523bb..114927e1e 100644 --- a/pumpkin-util/src/math/mod.rs +++ b/pumpkin-util/src/math/mod.rs @@ -2,6 +2,7 @@ use num_traits::{One, PrimInt, Zero}; pub mod boundingbox; pub mod experience; +pub mod int_provider; pub mod position; pub mod vector2; pub mod vector3; diff --git a/pumpkin-util/src/math/position.rs b/pumpkin-util/src/math/position.rs index c80a74d09..d3e447864 100644 --- a/pumpkin-util/src/math/position.rs +++ b/pumpkin-util/src/math/position.rs @@ -34,6 +34,22 @@ impl BlockPos { z: (encoded_position << 26 >> 38) as i32, }) } + + pub fn floored(x: f64, y: f64, z: f64) -> Self { + Self(Vector3::new( + x.floor() as i32, + y.floor() as i32, + z.floor() as i32, + )) + } + + pub fn to_f64(&self) -> Vector3 { + Vector3::new( + self.0.x as f64 + 0.5, + self.0.y as f64, + self.0.z as f64 + 0.5, + ) + } } impl Serialize for BlockPos { fn serialize(&self, serializer: S) -> Result diff --git a/pumpkin-util/src/math/vector3.rs b/pumpkin-util/src/math/vector3.rs index 8e0615153..c76213ddb 100644 --- a/pumpkin-util/src/math/vector3.rs +++ b/pumpkin-util/src/math/vector3.rs @@ -295,3 +295,16 @@ impl serde::Serialize for Vector3 { serializer.serialize_bytes(&buf) } } + +impl serde::Serialize for Vector3 { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut buf = Vec::new(); + buf.put_i32(self.x); + buf.put_i32(self.y); + buf.put_i32(self.z); + serializer.serialize_bytes(&buf) + } +} diff --git a/pumpkin-util/src/random/legacy_rand.rs b/pumpkin-util/src/random/legacy_rand.rs index 3574bb0de..bf67c51f8 100644 --- a/pumpkin-util/src/random/legacy_rand.rs +++ b/pumpkin-util/src/random/legacy_rand.rs @@ -1,5 +1,5 @@ use super::{ - gaussian::GaussianGenerator, hash_block_pos, java_string_hash, RandomDeriverImpl, RandomImpl, + RandomDeriverImpl, RandomImpl, gaussian::GaussianGenerator, hash_block_pos, java_string_hash, }; pub struct LegacyRand { @@ -121,7 +121,7 @@ impl RandomDeriverImpl for LegacySplitter { #[cfg(test)] mod test { - use crate::random::{legacy_rand::LegacySplitter, RandomDeriverImpl, RandomImpl}; + use crate::random::{RandomDeriverImpl, RandomImpl, legacy_rand::LegacySplitter}; use super::LegacyRand; diff --git a/pumpkin-util/src/random/xoroshiro128.rs b/pumpkin-util/src/random/xoroshiro128.rs index 65d92533c..730942a74 100644 --- a/pumpkin-util/src/random/xoroshiro128.rs +++ b/pumpkin-util/src/random/xoroshiro128.rs @@ -1,4 +1,4 @@ -use super::{gaussian::GaussianGenerator, hash_block_pos, RandomDeriverImpl, RandomImpl}; +use super::{RandomDeriverImpl, RandomImpl, gaussian::GaussianGenerator, hash_block_pos}; pub struct Xoroshiro { lo: u64, @@ -154,7 +154,7 @@ impl RandomDeriverImpl for XoroshiroSplitter { mod tests { use crate::random::{RandomDeriverImpl, RandomImpl}; - use super::{mix_stafford_13, Xoroshiro}; + use super::{Xoroshiro, mix_stafford_13}; // Values checked against results from the equivalent Java source diff --git a/pumpkin-util/src/text/mod.rs b/pumpkin-util/src/text/mod.rs index 5647144e3..61c98fb11 100644 --- a/pumpkin-util/src/text/mod.rs +++ b/pumpkin-util/src/text/mod.rs @@ -266,7 +266,7 @@ pub enum TextContent { mod test { use pumpkin_nbt::serializer::to_bytes_unnamed; - use crate::text::{color::NamedColor, TextComponent}; + use crate::text::{TextComponent, color::NamedColor}; #[test] fn test_serialize_text_component() { diff --git a/pumpkin-world/Cargo.toml b/pumpkin-world/Cargo.toml index a3dd85303..586393c9e 100644 --- a/pumpkin-world/Cargo.toml +++ b/pumpkin-world/Cargo.toml @@ -28,9 +28,9 @@ dashmap = "6.1" num-traits = "0.2" # Compression -flate2 = "1.0" +flate2 = "1.1" lz4 = "1.28" -zstd = "0.13.2" +zstd = "0.13.3" file-guard = "0.2" diff --git a/pumpkin-world/benches/chunk_noise_populate.rs b/pumpkin-world/benches/chunk_noise_populate.rs index fa113cafd..46d4d11e2 100644 --- a/pumpkin-world/benches/chunk_noise_populate.rs +++ b/pumpkin-world/benches/chunk_noise_populate.rs @@ -1,6 +1,6 @@ -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{Criterion, criterion_group, criterion_main}; use pumpkin_world::{ - bench_create_and_populate_noise, GlobalProtoNoiseRouter, GlobalRandomConfig, NOISE_ROUTER_ASTS, + GlobalProtoNoiseRouter, GlobalRandomConfig, NOISE_ROUTER_ASTS, bench_create_and_populate_noise, }; fn criterion_benchmark(c: &mut Criterion) { diff --git a/pumpkin-world/src/block/registry.rs b/pumpkin-world/src/block/registry.rs index d92f38989..06d11e99b 100644 --- a/pumpkin-world/src/block/registry.rs +++ b/pumpkin-world/src/block/registry.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::sync::LazyLock; +use pumpkin_util::math::int_provider::InvProvider; use serde::Deserialize; use crate::loot::LootTable; @@ -118,6 +119,8 @@ pub struct Block { pub id: u16, pub item_id: u16, pub hardness: f32, + pub experience: Option, + pub blast_resistance: f32, pub wall_variant_id: Option, pub translation_key: String, pub name: String, @@ -126,6 +129,10 @@ pub struct Block { pub default_state_id: u16, pub states: Vec, } +#[derive(Deserialize, Clone)] +pub struct Experience { + pub experience: InvProvider, +} #[derive(Deserialize, Clone, Debug)] pub struct Property { pub name: String, diff --git a/pumpkin-world/src/chunk/anvil.rs b/pumpkin-world/src/chunk/anvil.rs index de2aa867b..a7dfa3092 100644 --- a/pumpkin-world/src/chunk/anvil.rs +++ b/pumpkin-world/src/chunk/anvil.rs @@ -427,7 +427,7 @@ impl AnvilChunkFormat { palette: palette .into_iter() .map(|entry| PaletteEntry { - name: entry.1 .0.to_string(), + name: entry.1.0.to_string(), properties: { /* let properties = &get_block(entry.1 .0).unwrap().properties; @@ -505,9 +505,9 @@ mod tests { use temp_dir::TempDir; use crate::chunk::ChunkWriter; - use crate::generation::{get_world_gen, Seed}; + use crate::generation::{Seed, get_world_gen}; use crate::{ - chunk::{anvil::AnvilChunkFormat, ChunkReader, ChunkReadingError}, + chunk::{ChunkReader, ChunkReadingError, anvil::AnvilChunkFormat}, level::LevelFolder, }; diff --git a/pumpkin-world/src/chunk/linear.rs b/pumpkin-world/src/chunk/linear.rs index c8d4c68e0..5a65339ce 100644 --- a/pumpkin-world/src/chunk/linear.rs +++ b/pumpkin-world/src/chunk/linear.rs @@ -464,9 +464,9 @@ mod tests { use temp_dir::TempDir; use crate::chunk::ChunkWriter; - use crate::generation::{get_world_gen, Seed}; + use crate::generation::{Seed, get_world_gen}; use crate::{ - chunk::{linear::LinearChunkFormat, ChunkReader, ChunkReadingError}, + chunk::{ChunkReader, ChunkReadingError, linear::LinearChunkFormat}, level::LevelFolder, }; diff --git a/pumpkin-world/src/chunk/mod.rs b/pumpkin-world/src/chunk/mod.rs index 6b2143a84..5ddc3d129 100644 --- a/pumpkin-world/src/chunk/mod.rs +++ b/pumpkin-world/src/chunk/mod.rs @@ -1,6 +1,6 @@ use dashmap::{ - mapref::one::{Ref, RefMut}, DashMap, + mapref::one::{Ref, RefMut}, }; use pumpkin_data::chunk::ChunkStatus; use pumpkin_nbt::{deserializer::from_bytes, nbt_long_array}; @@ -15,10 +15,10 @@ use std::{ use thiserror::Error; use crate::{ + WORLD_HEIGHT, block::BlockState, coordinates::{ChunkRelativeBlockCoordinates, Height}, level::LevelFolder, - WORLD_HEIGHT, }; pub mod anvil; diff --git a/pumpkin-world/src/generation/aquifer_sampler.rs b/pumpkin-world/src/generation/aquifer_sampler.rs index 0f08c9b5e..0b6b7b569 100644 --- a/pumpkin-world/src/generation/aquifer_sampler.rs +++ b/pumpkin-world/src/generation/aquifer_sampler.rs @@ -14,7 +14,7 @@ use super::{ chunk_noise_router::ChunkNoiseRouter, density_function::{NoisePos, UnblendedNoisePos}, }, - positions::{block_pos, chunk_pos, MIN_HEIGHT_CELL}, + positions::{MIN_HEIGHT_CELL, block_pos, chunk_pos}, proto_chunk::StandardChunkFluidLevelSampler, section_coords, }; @@ -214,18 +214,10 @@ impl WorldAquiferSampler { let o = halved_diff - scaled_level.abs(); let q = if scaled_level > 0f64 { - if o > 0f64 { - o / 1.5f64 - } else { - o / 2.5f64 - } + if o > 0f64 { o / 1.5f64 } else { o / 2.5f64 } } else { let p = 3f64 + o; - if p > 0f64 { - p / 3f64 - } else { - p / 10f64 - } + if p > 0f64 { p / 3f64 } else { p / 10f64 } }; let r = if (-2f64..=2f64).contains(&q) { @@ -661,6 +653,7 @@ mod test { use crate::{ block::BlockState, generation::{ + GlobalRandomConfig, chunk_noise::{ BlockStateSampler, ChainedBlockStateSampler, ChunkNoiseGenerator, ChunkNoiseHeightEstimator, LAVA_BLOCK, WATER_BLOCK, @@ -674,7 +667,6 @@ mod test { }, positions::chunk_pos, proto_chunk::StandardChunkFluidLevelSampler, - GlobalRandomConfig, }, noise_router::NOISE_ROUTER_ASTS, }; diff --git a/pumpkin-world/src/generation/chunk_noise.rs b/pumpkin-world/src/generation/chunk_noise.rs index f39fa4d38..0aa804f79 100644 --- a/pumpkin-world/src/generation/chunk_noise.rs +++ b/pumpkin-world/src/generation/chunk_noise.rs @@ -6,6 +6,7 @@ use pumpkin_util::math::{floor_div, floor_mod, vector2::Vector2}; use crate::{block::BlockState, generation::section_coords}; use super::{ + GlobalRandomConfig, aquifer_sampler::{ AquiferSampler, AquiferSamplerImpl, FluidLevelSampler, SeaLevelAquiferSampler, WorldAquiferSampler, @@ -23,7 +24,6 @@ use super::{ }, ore_sampler::OreVeinSampler, positions::chunk_pos, - GlobalRandomConfig, }; pub const STONE_BLOCK: BlockState = block_state!("stone"); diff --git a/pumpkin-world/src/generation/generic_generator.rs b/pumpkin-world/src/generation/generic_generator.rs index 11e2b8fe8..719276ef4 100644 --- a/pumpkin-world/src/generation/generic_generator.rs +++ b/pumpkin-world/src/generation/generic_generator.rs @@ -2,14 +2,14 @@ use noise::{NoiseFn, Perlin}; use pumpkin_util::math::vector2::Vector2; use crate::{ + WORLD_LOWEST_Y, chunk::{ChunkData, Subchunks}, coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates}, - WORLD_LOWEST_Y, }; use super::{ - generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator, WorldGenerator}, Seed, + generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator, WorldGenerator}, }; pub struct GenericGenerator { diff --git a/pumpkin-world/src/generation/implementation/superflat.rs b/pumpkin-world/src/generation/implementation/superflat.rs index 6d28f7aca..08fcb7d2a 100644 --- a/pumpkin-world/src/generation/implementation/superflat.rs +++ b/pumpkin-world/src/generation/implementation/superflat.rs @@ -5,9 +5,9 @@ use crate::{ block::state::BlockState, coordinates::XZBlockCoordinates, generation::{ + Seed, generator::{BiomeGenerator, GeneratorInit, TerrainGenerator}, generic_generator::GenericGenerator, - Seed, }, }; diff --git a/pumpkin-world/src/generation/implementation/test.rs b/pumpkin-world/src/generation/implementation/test.rs index bb25cfa83..60a868e7a 100644 --- a/pumpkin-world/src/generation/implementation/test.rs +++ b/pumpkin-world/src/generation/implementation/test.rs @@ -1,14 +1,14 @@ use pumpkin_util::math::{vector2::Vector2, vector3::Vector3}; use crate::{ + WORLD_LOWEST_Y, WORLD_MAX_Y, chunk::{ChunkData, Subchunks}, coordinates::ChunkRelativeBlockCoordinates, generation::{ - generator::GeneratorInit, noise_router::proto_noise_router::GlobalProtoNoiseRouter, - proto_chunk::ProtoChunk, GlobalRandomConfig, Seed, WorldGenerator, + GlobalRandomConfig, Seed, WorldGenerator, generator::GeneratorInit, + noise_router::proto_noise_router::GlobalProtoNoiseRouter, proto_chunk::ProtoChunk, }, noise_router::NOISE_ROUTER_ASTS, - WORLD_LOWEST_Y, WORLD_MAX_Y, }; pub struct TestGenerator { diff --git a/pumpkin-world/src/generation/mod.rs b/pumpkin-world/src/generation/mod.rs index bfb8a3a98..24a0681ed 100644 --- a/pumpkin-world/src/generation/mod.rs +++ b/pumpkin-world/src/generation/mod.rs @@ -21,7 +21,7 @@ use implementation::{ //overworld::biome::plains::PlainsGenerator, test::TestGenerator, }; -use pumpkin_util::random::{xoroshiro128::Xoroshiro, RandomDeriver, RandomImpl}; +use pumpkin_util::random::{RandomDeriver, RandomImpl, xoroshiro128::Xoroshiro}; pub use seed::Seed; use generator::GeneratorInit; diff --git a/pumpkin-world/src/generation/noise/perlin.rs b/pumpkin-world/src/generation/noise/perlin.rs index 4dc9444cd..8f8e89581 100644 --- a/pumpkin-world/src/generation/noise/perlin.rs +++ b/pumpkin-world/src/generation/noise/perlin.rs @@ -2,7 +2,7 @@ use num_traits::Pow; use pumpkin_data::chunk::DoublePerlinNoiseParameters; use pumpkin_util::random::RandomGenerator; -use super::{lerp3, GRADIENTS}; +use super::{GRADIENTS, lerp3}; #[derive(Clone)] pub struct PerlinNoiseSampler { @@ -357,7 +357,7 @@ mod double_perlin_noise_sampler_test { use crate::generation::noise::perlin::DoublePerlinNoiseSampler; use pumpkin_data::chunk::DoublePerlinNoiseParameters; use pumpkin_util::random::{ - legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl, + RandomGenerator, RandomImpl, legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, }; #[test] @@ -560,7 +560,7 @@ mod double_perlin_noise_sampler_test { #[cfg(test)] mod octave_perline_noise_sampler_test { use pumpkin_util::random::{ - legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl, + RandomGenerator, RandomImpl, legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, }; use super::OctavePerlinNoiseSampler; @@ -733,7 +733,7 @@ mod perlin_noise_sampler_test { use pumpkin_util::{ assert_eq_delta, - random::{xoroshiro128::Xoroshiro, RandomDeriverImpl, RandomGenerator, RandomImpl}, + random::{RandomDeriverImpl, RandomGenerator, RandomImpl, xoroshiro128::Xoroshiro}, }; use crate::{generation::noise::perlin::PerlinNoiseSampler, read_data_from_file}; @@ -1268,7 +1268,9 @@ mod perlin_noise_sampler_test { assert_eq!(first, -15); assert_eq!( amplitudes, - [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + [ + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + ] ); } diff --git a/pumpkin-world/src/generation/noise/simplex.rs b/pumpkin-world/src/generation/noise/simplex.rs index 04712de13..114b8d050 100644 --- a/pumpkin-world/src/generation/noise/simplex.rs +++ b/pumpkin-world/src/generation/noise/simplex.rs @@ -1,7 +1,7 @@ use std::hash::Hash; use num_traits::Pow; -use pumpkin_util::random::{legacy_rand::LegacyRand, RandomImpl}; +use pumpkin_util::random::{RandomImpl, legacy_rand::LegacyRand}; use super::GRADIENTS; @@ -274,7 +274,7 @@ impl OctaveSimplexNoiseSampler { #[cfg(test)] mod octave_simplex_noise_sampler_test { - use pumpkin_util::random::{xoroshiro128::Xoroshiro, RandomImpl}; + use pumpkin_util::random::{RandomImpl, xoroshiro128::Xoroshiro}; use crate::generation::noise::simplex::OctaveSimplexNoiseSampler; @@ -410,7 +410,7 @@ mod octave_simplex_noise_sampler_test { #[cfg(test)] mod simplex_noise_sampler_test { - use pumpkin_util::random::{xoroshiro128::Xoroshiro, RandomImpl}; + use pumpkin_util::random::{RandomImpl, xoroshiro128::Xoroshiro}; use crate::generation::noise::simplex::SimplexNoiseSampler; diff --git a/pumpkin-world/src/generation/noise_router/density_function/misc.rs b/pumpkin-world/src/generation/noise_router/density_function/misc.rs index c96b7c2a5..d0823bbc1 100644 --- a/pumpkin-world/src/generation/noise_router/density_function/misc.rs +++ b/pumpkin-world/src/generation/noise_router/density_function/misc.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use pumpkin_util::random::{legacy_rand::LegacyRand, RandomImpl}; +use pumpkin_util::random::{RandomImpl, legacy_rand::LegacyRand}; use crate::{ generation::{ diff --git a/pumpkin-world/src/generation/noise_router/density_function/test.rs b/pumpkin-world/src/generation/noise_router/density_function/test.rs index 914f38178..f905b6417 100644 --- a/pumpkin-world/src/generation/noise_router/density_function/test.rs +++ b/pumpkin-world/src/generation/noise_router/density_function/test.rs @@ -5,6 +5,7 @@ use std::fs; use std::path::Path; use std::sync::LazyLock; +use crate::generation::GlobalRandomConfig; use crate::generation::noise_router::chunk_density_function::{ ChunkNoiseFunctionSampleOptions, SampleAction, }; @@ -12,9 +13,8 @@ use crate::generation::noise_router::chunk_noise_router::{ ChunkNoiseDensityFunction, ChunkNoiseFunctionComponent, }; use crate::generation::noise_router::proto_noise_router::{ - recursive_build_proto_stack, DoublePerlinNoiseBuilder, ProtoNoiseFunctionComponent, + DoublePerlinNoiseBuilder, ProtoNoiseFunctionComponent, recursive_build_proto_stack, }; -use crate::generation::GlobalRandomConfig; use crate::noise_router::NOISE_ROUTER_ASTS; use crate::read_data_from_file; use crate::{ diff --git a/pumpkin-world/src/generation/noise_router/multi_noise_sampler.rs b/pumpkin-world/src/generation/noise_router/multi_noise_sampler.rs index 5a7e9c599..ee01e7510 100644 --- a/pumpkin-world/src/generation/noise_router/multi_noise_sampler.rs +++ b/pumpkin-world/src/generation/noise_router/multi_noise_sampler.rs @@ -1,6 +1,6 @@ use crate::{ - generation::biome_coords, noise_router::density_function_ast::WrapperType, - GlobalProtoNoiseRouter, + GlobalProtoNoiseRouter, generation::biome_coords, + noise_router::density_function_ast::WrapperType, }; use super::{ @@ -187,7 +187,9 @@ impl<'a> MultiNoiseSampler<'a> { )) } _ => { - panic!("These density functions should not be a part of the MultiNoiseSampler! We probably need to re-write code"); + panic!( + "These density functions should not be a part of the MultiNoiseSampler! We probably need to re-write code" + ); } } } diff --git a/pumpkin-world/src/generation/noise_router/proto_noise_router.rs b/pumpkin-world/src/generation/noise_router/proto_noise_router.rs index 93cda967c..7a39e6e7a 100644 --- a/pumpkin-world/src/generation/noise_router/proto_noise_router.rs +++ b/pumpkin-world/src/generation/noise_router/proto_noise_router.rs @@ -7,24 +7,24 @@ use enum_dispatch::enum_dispatch; use pumpkin_data::chunk::DoublePerlinNoiseParameters; use crate::{ + GlobalRandomConfig, generation::noise::perlin::DoublePerlinNoiseSampler, noise_router::{ density_function_ast::{DensityFunctionRepr, SplineRepr}, noise_router_ast::NoiseRouterRepr, }, - GlobalRandomConfig, }; use super::{ chunk_density_function::ChunkNoiseFunctionSampleOptions, chunk_noise_router::{ChunkNoiseFunctionComponent, StaticChunkNoiseFunctionComponentImpl}, density_function::{ + IndexToNoisePos, NoiseFunctionComponentRange, NoisePos, PassThrough, + StaticIndependentChunkNoiseFunctionComponentImpl, Wrapper, math::{Binary, Clamp, Constant, Linear, Unary}, misc::{ClampedYGradient, EndIsland, RangeChoice, WeirdScaled}, noise::{InterpolatedNoiseSampler, Noise, ShiftA, ShiftB, ShiftedNoise}, spline::{Spline, SplineFunction, SplinePoint, SplineValue}, - IndexToNoisePos, NoiseFunctionComponentRange, NoisePos, PassThrough, - StaticIndependentChunkNoiseFunctionComponentImpl, Wrapper, }, }; diff --git a/pumpkin-world/src/generation/positions.rs b/pumpkin-world/src/generation/positions.rs index 6cb79d352..334632978 100644 --- a/pumpkin-world/src/generation/positions.rs +++ b/pumpkin-world/src/generation/positions.rs @@ -4,7 +4,7 @@ pub mod block_pos { use pumpkin_util::math::vector3::Vector3; use super::{ - BITS_X, BITS_Y, BITS_Z, BIT_SHIFT_X, BIT_SHIFT_Z, SIZE_BITS_X, SIZE_BITS_Y, SIZE_BITS_Z, + BIT_SHIFT_X, BIT_SHIFT_Z, BITS_X, BITS_Y, BITS_Z, SIZE_BITS_X, SIZE_BITS_Y, SIZE_BITS_Z, }; #[inline] diff --git a/pumpkin-world/src/generation/proto_chunk.rs b/pumpkin-world/src/generation/proto_chunk.rs index 9884fc888..b83d2156c 100644 --- a/pumpkin-world/src/generation/proto_chunk.rs +++ b/pumpkin-world/src/generation/proto_chunk.rs @@ -8,11 +8,11 @@ use crate::{ }; use super::{ + GlobalRandomConfig, aquifer_sampler::{FluidLevel, FluidLevelSampler, FluidLevelSamplerImpl}, chunk_noise::{ChunkNoiseGenerator, LAVA_BLOCK, STONE_BLOCK, WATER_BLOCK}, noise_router::proto_noise_router::GlobalProtoNoiseRouter, positions::chunk_pos::{start_block_x, start_block_z}, - GlobalRandomConfig, }; pub struct StandardChunkFluidLevelSampler { @@ -239,13 +239,13 @@ mod test { use crate::{ generation::{ + GlobalRandomConfig, noise_router::{ density_function::{NoiseFunctionComponentRange, PassThrough}, proto_noise_router::{GlobalProtoNoiseRouter, ProtoNoiseFunctionComponent}, }, - GlobalRandomConfig, }, - noise_router::{density_function_ast::WrapperType, NOISE_ROUTER_ASTS}, + noise_router::{NOISE_ROUTER_ASTS, density_function_ast::WrapperType}, read_data_from_file, }; diff --git a/pumpkin-world/src/generation/seed.rs b/pumpkin-world/src/generation/seed.rs index fb39f7e32..722098670 100644 --- a/pumpkin-world/src/generation/seed.rs +++ b/pumpkin-world/src/generation/seed.rs @@ -1,4 +1,4 @@ -use pumpkin_util::random::{get_seed, java_string_hash, legacy_rand::LegacyRand, RandomImpl}; +use pumpkin_util::random::{RandomImpl, get_seed, java_string_hash, legacy_rand::LegacyRand}; #[derive(Clone, Copy)] pub struct Seed(pub u64); diff --git a/pumpkin-world/src/item/categories.rs b/pumpkin-world/src/item/categories.rs index 301ac4129..06936a7dd 100644 --- a/pumpkin-world/src/item/categories.rs +++ b/pumpkin-world/src/item/categories.rs @@ -1,69 +1,46 @@ +use pumpkin_data::tag::Tagable; + use crate::item::ItemStack; +const SWORDS_TAG: &str = "#minecraft:swords"; +const HEAD_ARMOR_TAG: &str = "#minecraft:head_armor"; +const CHEST_ARMOR_TAG: &str = "#minecraft:chest_armor"; +const LEG_ARMOR_TAG: &str = "#minecraft:leg_armor"; +const FOOT_ARMOR_TAG: &str = "#minecraft:foot_armor"; + impl ItemStack { + #[inline] pub fn is_sword(&self) -> bool { - [ - 818, // Wooden - 823, // Stone - 828, // Gold - 833, // Iron - 838, // Diamond - 843, // Netherite - ] - .contains(&self.item.id) + self.item.is_tagged_with(SWORDS_TAG).expect( + "This is a default minecraft tag that should have been gotten from the extractor", + ) } + #[inline] pub fn is_helmet(&self) -> bool { - [ - // Leather - 856, // Netherite - 876, // Turtle helmet - 794, // Chainmail - 860, // Diamond - 868, // Gold - 872, // Iron - 864, - ] - .contains(&self.item.id) + self.item.is_tagged_with(HEAD_ARMOR_TAG).expect( + "This is a default minecraft tag that should have been gotten from the extractor", + ) } + #[inline] pub fn is_chestplate(&self) -> bool { - [ - // Leather - 857, // Netherite - 877, // Chainmail - 861, // Diamond - 869, // Gold - 873, // Iron - 865, // Elytra - 773, - ] - .contains(&self.item.id) + self.item.is_tagged_with(CHEST_ARMOR_TAG).expect( + "This is a default minecraft tag that should have been gotten from the extractor", + ) } + #[inline] pub fn is_leggings(&self) -> bool { - [ - // Leather - 858, // Netherite - 878, // Chainmail - 862, // Diamond - 870, // Gold - 874, // Iron - 866, - ] - .contains(&self.item.id) + self.item.is_tagged_with(LEG_ARMOR_TAG).expect( + "This is a default minecraft tag that should have been gotten from the extractor", + ) } + #[inline] pub fn is_boots(&self) -> bool { - [ - // Leather - 859, // Netherite - 879, // Chainmail - 863, // Diamond - 871, // Gold - 875, // Iron - 867, - ] - .contains(&self.item.id) + self.item.is_tagged_with(FOOT_ARMOR_TAG).expect( + "This is a default minecraft tag that should have been gotten from the extractor", + ) } } diff --git a/pumpkin-world/src/item/mod.rs b/pumpkin-world/src/item/mod.rs index 935202ca2..44a5410d8 100644 --- a/pumpkin-world/src/item/mod.rs +++ b/pumpkin-world/src/item/mod.rs @@ -1,6 +1,8 @@ use pumpkin_data::item::Item; +use pumpkin_data::tag::{RegistryKey, get_tag_values}; mod categories; + #[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "lowercase")] /// Item Rarity @@ -11,9 +13,10 @@ pub enum Rarity { Epic, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Debug)] pub struct ItemStack { pub item_count: u8, + // TODO: Should this be a ref? all of our items are const pub item: Item, } @@ -28,26 +31,71 @@ impl ItemStack { Self { item_count, item } } + /// Determines the mining speed for a block based on tool rules. + /// Direct matches return immediately, tagged blocks are checked separately. + /// If no match is found, returns the tool's default mining speed or `1.0`. pub fn get_speed(&self, block: &str) -> f32 { - if let Some(tool) = self.item.components.tool { - for rule in tool.rules { - if rule.speed.is_none() || !rule.blocks.contains(&block) { - continue; + // No tool? Use default speed + let Some(tool) = &self.item.components.tool else { + return 1.0; + }; + + for rule in tool.rules { + // Skip if speed is not set + let Some(speed) = rule.speed else { + continue; + }; + + for entry in rule.blocks { + if entry.eq(&block) { + return speed; + } + + if entry.starts_with('#') { + // Check if block is in the tag group + if let Some(blocks) = + get_tag_values(RegistryKey::Block, entry.strip_prefix('#').unwrap()) + { + if blocks.iter().any(|s| s == block) { + return speed; + } + } } - return rule.speed.unwrap(); } - return tool.default_mining_speed.unwrap_or(1.0); } - 1.0 + // Return default mining speed if no match is found + tool.default_mining_speed.unwrap_or(1.0) } + /// Determines if a tool is valid for block drops based on tool rules. + /// Direct matches return immediately, while tagged blocks are checked separately. pub fn is_correct_for_drops(&self, block: &str) -> bool { - if let Some(tool) = self.item.components.tool { - for rule in tool.rules { - if rule.correct_for_drops.is_none() || !rule.blocks.contains(&block) { - continue; + // Return false if no tool component exists + let Some(tool) = &self.item.components.tool else { + return false; + }; + + for rule in tool.rules { + // Skip rules without a drop condition + let Some(correct_for_drops) = rule.correct_for_drops else { + continue; + }; + + for entry in rule.blocks { + if entry.eq(&block) { + return correct_for_drops; + } + + if entry.starts_with('#') { + // Check if block exists within the tag group + if let Some(blocks) = + get_tag_values(RegistryKey::Block, entry.strip_prefix('#').unwrap()) + { + if blocks.iter().any(|s| s == block) { + return correct_for_drops; + } + } } - return rule.correct_for_drops.unwrap(); } } false diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index 3f751780b..728fc9ad9 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -2,24 +2,24 @@ use std::{fs, path::PathBuf, sync::Arc}; use dashmap::{DashMap, Entry}; use num_traits::Zero; -use pumpkin_config::{chunk::ChunkFormat, ADVANCED_CONFIG}; +use pumpkin_config::{ADVANCED_CONFIG, chunk::ChunkFormat}; use pumpkin_util::math::vector2::Vector2; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use tokio::{ runtime::Handle, - sync::{mpsc, RwLock}, + sync::{RwLock, mpsc}, }; use crate::{ chunk::{ - anvil::AnvilChunkFormat, linear::LinearChunkFormat, ChunkData, ChunkParsingError, - ChunkReader, ChunkReadingError, ChunkWriter, + ChunkData, ChunkParsingError, ChunkReader, ChunkReadingError, ChunkWriter, + anvil::AnvilChunkFormat, linear::LinearChunkFormat, }, - generation::{get_world_gen, Seed, WorldGenerator}, - lock::{anvil::AnvilLevelLocker, LevelLocker}, + generation::{Seed, WorldGenerator, get_world_gen}, + lock::{LevelLocker, anvil::AnvilLevelLocker}, world_info::{ - anvil::{AnvilLevelInfo, LEVEL_DAT_BACKUP_FILE_NAME, LEVEL_DAT_FILE_NAME}, LevelData, WorldInfoError, WorldInfoReader, WorldInfoWriter, + anvil::{AnvilLevelInfo, LEVEL_DAT_BACKUP_FILE_NAME, LEVEL_DAT_FILE_NAME}, }, }; @@ -167,6 +167,7 @@ impl Level { } pub fn mark_chunk_as_newly_watched(&self, chunk: Vector2) { + log::trace!("{:?} marked as newly watched", chunk); match self.chunk_watchers.entry(chunk) { Entry::Occupied(mut occupied) => { let value = occupied.get_mut(); @@ -195,6 +196,7 @@ impl Level { /// Returns whether the chunk should be removed from memory pub fn mark_chunk_as_not_watched(&self, chunk: Vector2) -> bool { + log::trace!("{:?} marked as no longer watched", chunk); match self.chunk_watchers.entry(chunk) { Entry::Occupied(mut occupied) => { let value = occupied.get_mut(); @@ -225,6 +227,7 @@ impl Level { } pub async fn clean_chunk(&self, chunk: &Vector2) { + log::trace!("{:?} is being cleaned", chunk); if let Some(data) = self.loaded_chunks.remove(chunk) { self.write_chunk(data).await; } diff --git a/pumpkin-world/src/lib.rs b/pumpkin-world/src/lib.rs index 505de580e..d8e58e971 100644 --- a/pumpkin-world/src/lib.rs +++ b/pumpkin-world/src/lib.rs @@ -45,7 +45,7 @@ macro_rules! read_data_from_file { // TODO: is there a way to do in-file benches? pub use generation::{ - noise_router::proto_noise_router::GlobalProtoNoiseRouter, GlobalRandomConfig, + GlobalRandomConfig, noise_router::proto_noise_router::GlobalProtoNoiseRouter, }; pub use noise_router::NOISE_ROUTER_ASTS; diff --git a/pumpkin-world/src/world_info/anvil.rs b/pumpkin-world/src/world_info/anvil.rs index 60d140d1a..5c179e862 100644 --- a/pumpkin-world/src/world_info/anvil.rs +++ b/pumpkin-world/src/world_info/anvil.rs @@ -4,7 +4,7 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; -use flate2::{read::GzDecoder, write::GzEncoder, Compression}; +use flate2::{Compression, read::GzDecoder, write::GzEncoder}; use serde::{Deserialize, Serialize}; use crate::{ @@ -125,7 +125,7 @@ mod test { world_info::{DataPacks, LevelData, WorldGenSettings, WorldInfoError, WorldVersion}, }; - use super::{AnvilLevelInfo, LevelDat, WorldInfoReader, WorldInfoWriter, LEVEL_DAT_FILE_NAME}; + use super::{AnvilLevelInfo, LEVEL_DAT_FILE_NAME, LevelDat, WorldInfoReader, WorldInfoWriter}; #[test] fn test_preserve_level_dat_seed() { diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index e513da7b8..ff671ec60 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -2,8 +2,8 @@ name = "pumpkin" version = "0.1.0-dev" description = "Empowering everyone to host fast and efficient Minecraft servers." -edition = "2021" -rust-version = "1.83" +edition.workspace = true +rust-version = "1.85" [package.metadata.tauri-winres] # FileDescription is handled as the Program name by Windows! diff --git a/pumpkin/src/block/blocks/chest.rs b/pumpkin/src/block/blocks/chest.rs index d3be956b4..492d0dd66 100644 --- a/pumpkin/src/block/blocks/chest.rs +++ b/pumpkin/src/block/blocks/chest.rs @@ -8,7 +8,7 @@ use pumpkin_inventory::{Chest, OpenContainer}; use pumpkin_macros::pumpkin_block; use pumpkin_protocol::{client::play::CBlockAction, codec::var_int::VarInt}; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::registry::{get_block, Block}; +use pumpkin_world::block::registry::{Block, get_block}; use crate::{ block::{pumpkin_block::PumpkinBlock, registry::BlockActionResult}, diff --git a/pumpkin/src/block/blocks/lever.rs b/pumpkin/src/block/blocks/lever.rs index 429ec3e06..4ff65c472 100644 --- a/pumpkin/src/block/blocks/lever.rs +++ b/pumpkin/src/block/blocks/lever.rs @@ -4,7 +4,7 @@ use pumpkin_data::item::Item; use pumpkin_macros::pumpkin_block; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use crate::{ block::{properties::Direction, pumpkin_block::PumpkinBlock, registry::BlockActionResult}, diff --git a/pumpkin/src/block/blocks/mod.rs b/pumpkin/src/block/blocks/mod.rs index 9068b1e08..35cb191a3 100644 --- a/pumpkin/src/block/blocks/mod.rs +++ b/pumpkin/src/block/blocks/mod.rs @@ -10,6 +10,7 @@ pub(crate) mod crafting_table; pub(crate) mod furnace; pub(crate) mod jukebox; pub(crate) mod lever; +pub(crate) mod tnt; /// The standard destroy with container removes the player forcibly from the container, /// drops items to the floor, and back to the player's inventory if the item stack is in movement. diff --git a/pumpkin/src/block/blocks/tnt.rs b/pumpkin/src/block/blocks/tnt.rs new file mode 100644 index 000000000..ff516345c --- /dev/null +++ b/pumpkin/src/block/blocks/tnt.rs @@ -0,0 +1,70 @@ +use std::sync::Arc; + +use crate::block::pumpkin_block::PumpkinBlock; +use crate::block::registry::BlockActionResult; +use crate::entity::player::Player; +use crate::entity::tnt::TNTEntity; +use crate::server::Server; +use crate::world::World; +use async_trait::async_trait; +use pumpkin_data::entity::EntityType; +use pumpkin_data::item::Item; +use pumpkin_data::sound::SoundCategory; +use pumpkin_macros::pumpkin_block; +use pumpkin_util::math::position::BlockPos; +use pumpkin_world::block::registry::Block; +use rand::Rng; + +#[pumpkin_block("minecraft:tnt")] +pub struct TNTBlock; + +const DEFAULT_FUSE: u32 = 80; +const DEFAULT_POWER: f32 = 4.0; + +#[async_trait] +impl PumpkinBlock for TNTBlock { + async fn use_with_item( + &self, + _block: &Block, + player: &Player, + location: BlockPos, + item: &Item, + server: &Server, + ) -> BlockActionResult { + if *item != Item::FLINT_AND_STEEL || *item == Item::FIRE_CHARGE { + return BlockActionResult::Continue; + } + let world = player.world().await; + world.set_block_state(&location, 0).await; + let entity = server.add_entity(location.to_f64(), EntityType::TNT, &world); + let pos = entity.pos.load(); + let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, DEFAULT_FUSE)); + world.spawn_entity(tnt.clone()).await; + tnt.send_meta_packet().await; + world + .play_sound( + pumpkin_data::sound::Sound::EntityTntPrimed, + SoundCategory::Blocks, + &pos, + ) + .await; + BlockActionResult::Consume + } + async fn explode( + &self, + _block: &Block, + world: &Arc, + location: BlockPos, + server: &Server, + ) { + let entity = server.add_entity(location.to_f64(), EntityType::TNT, world); + let fuse = rand::thread_rng().gen_range(0..DEFAULT_FUSE / 4) + DEFAULT_FUSE / 8; + let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, fuse)); + world.spawn_entity(tnt.clone()).await; + tnt.send_meta_packet().await; + } + + fn should_drop_items_on_explosion(&self) -> bool { + false + } +} diff --git a/pumpkin/src/block/mod.rs b/pumpkin/src/block/mod.rs index 62abcf80d..b11fb929e 100644 --- a/pumpkin/src/block/mod.rs +++ b/pumpkin/src/block/mod.rs @@ -1,5 +1,6 @@ -use blocks::{chest::ChestBlock, furnace::FurnaceBlock, lever::LeverBlock}; +use blocks::{chest::ChestBlock, furnace::FurnaceBlock, lever::LeverBlock, tnt::TNTBlock}; use properties::{ + BlockPropertiesManager, age::Age, attachment::Attachment, axis::Axis, @@ -13,23 +14,21 @@ use properties::{ signal_fire::SignalFire, slab_type::SlabType, stair_shape::StairShape, + unstable::Unstable, waterlog::Waterlogged, - BlockPropertiesManager, }; use pumpkin_data::entity::EntityType; -use pumpkin_data::item::Item; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; use pumpkin_world::block::registry::{Block, State}; -use pumpkin_world::item::ItemStack; use rand::Rng; -use crate::block::blocks::jukebox::JukeboxBlock; use crate::block::registry::BlockRegistry; use crate::entity::item::ItemEntity; use crate::server::Server; use crate::world::World; use crate::{block::blocks::crafting_table::CraftingTableBlock, entity::player::Player}; +use crate::{block::blocks::jukebox::JukeboxBlock, entity::experience_orb::ExperienceOrbEntity}; use std::sync::Arc; mod blocks; @@ -45,12 +44,19 @@ pub fn default_registry() -> Arc { manager.register(CraftingTableBlock); manager.register(FurnaceBlock); manager.register(ChestBlock); + manager.register(TNTBlock); manager.register(LeverBlock); Arc::new(manager) } -pub async fn drop_loot(server: &Server, world: &Arc, block: &Block, pos: &BlockPos) { +pub async fn drop_loot( + server: &Server, + world: &Arc, + block: &Block, + pos: &BlockPos, + experience: bool, +) { // TODO: Currently only the item block is dropped, We should drop the loop table let height = EntityType::ITEM.dimension[1] / 2.0; let pos = Vector3::new( @@ -60,12 +66,19 @@ pub async fn drop_loot(server: &Server, world: &Arc, block: &Block, pos: ); let entity = server.add_entity(pos, EntityType::ITEM, world); - let item_entity = Arc::new(ItemEntity::new( - entity, - &ItemStack::new(1, Item::from_id(block.item_id).unwrap()), - )); + let item_entity = Arc::new(ItemEntity::new(entity, block.item_id, 1)); world.spawn_entity(item_entity.clone()).await; item_entity.send_meta_packet().await; + + if experience { + if let Some(experience) = &block.experience { + let amount = experience.experience.get(); + // TODO: Silk touch gives no exp + if amount > 0 { + ExperienceOrbEntity::spawn(world, server, pos, amount as u32).await; + } + } + } } pub async fn calc_block_breaking(player: &Player, state: &State, block_name: &str) -> f32 { @@ -101,6 +114,7 @@ pub fn default_block_properties_manager() -> Arc { manager.register(North::False); manager.register(Open::False()); manager.register(Powered::False()); + manager.register(Unstable::False()); manager.register(SignalFire::False()); manager.register(SlabType::Bottom); manager.register(South::False); diff --git a/pumpkin/src/block/properties/attachment.rs b/pumpkin/src/block/properties/attachment.rs index 39d12f418..698bdddc4 100644 --- a/pumpkin/src/block/properties/attachment.rs +++ b/pumpkin/src/block/properties/attachment.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/axis.rs b/pumpkin/src/block/properties/axis.rs index 615254d4e..b1f700d9e 100644 --- a/pumpkin/src/block/properties/axis.rs +++ b/pumpkin/src/block/properties/axis.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/cardinal.rs b/pumpkin/src/block/properties/cardinal.rs index ee5d90ca5..94dcd6f25 100644 --- a/pumpkin/src/block/properties/cardinal.rs +++ b/pumpkin/src/block/properties/cardinal.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/face.rs b/pumpkin/src/block/properties/face.rs index 3b7735ce4..efdee686b 100644 --- a/pumpkin/src/block/properties/face.rs +++ b/pumpkin/src/block/properties/face.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/facing.rs b/pumpkin/src/block/properties/facing.rs index 558233925..3f54c9b0f 100644 --- a/pumpkin/src/block/properties/facing.rs +++ b/pumpkin/src/block/properties/facing.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/half.rs b/pumpkin/src/block/properties/half.rs index 01964ba83..abfb84c50 100644 --- a/pumpkin/src/block/properties/half.rs +++ b/pumpkin/src/block/properties/half.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/layers.rs b/pumpkin/src/block/properties/layers.rs index bce83b332..a9627d635 100644 --- a/pumpkin/src/block/properties/layers.rs +++ b/pumpkin/src/block/properties/layers.rs @@ -4,8 +4,8 @@ use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; use pumpkin_world::block::{ - registry::{Block, State}, BlockDirection, + registry::{Block, State}, }; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/mod.rs b/pumpkin/src/block/properties/mod.rs index 71494b9c5..d4356a980 100644 --- a/pumpkin/src/block/properties/mod.rs +++ b/pumpkin/src/block/properties/mod.rs @@ -5,8 +5,8 @@ use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; use pumpkin_world::{ block::{ - registry::{Block, State, BLOCKS}, BlockDirection, + registry::{BLOCKS, Block, State}, }, item::ItemStack, }; @@ -24,6 +24,7 @@ pub(crate) mod powered; pub(crate) mod signal_fire; pub(crate) mod slab_type; pub(crate) mod stair_shape; +pub(crate) mod unstable; pub(crate) mod waterlog; use crate::world::World; @@ -220,6 +221,9 @@ impl BlockPropertiesManager { } pub async fn on_interact(&self, block: &Block, block_state: &State, item: &ItemStack) -> u16 { + if block_state.id == 0 { + return block_state.id; + } if let Some(properties) = self.properties_registry.get(&block.id) { if let Some(states) = properties .property_mappings diff --git a/pumpkin/src/block/properties/signal_fire.rs b/pumpkin/src/block/properties/signal_fire.rs index a739d571e..17d6ccdf3 100644 --- a/pumpkin/src/block/properties/signal_fire.rs +++ b/pumpkin/src/block/properties/signal_fire.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/slab_type.rs b/pumpkin/src/block/properties/slab_type.rs index 355354b9b..89c704ec1 100644 --- a/pumpkin/src/block/properties/slab_type.rs +++ b/pumpkin/src/block/properties/slab_type.rs @@ -4,8 +4,8 @@ use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; use pumpkin_world::block::{ - registry::{Block, State}, BlockDirection, + registry::{Block, State}, }; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/properties/stair_shape.rs b/pumpkin/src/block/properties/stair_shape.rs index be2a3f418..f9e4ae9ae 100644 --- a/pumpkin/src/block/properties/stair_shape.rs +++ b/pumpkin/src/block/properties/stair_shape.rs @@ -1,12 +1,12 @@ use crate::{ - block::properties::{facing::Facing, half::evaluate_half, BlockPropertyMetadata}, + block::properties::{BlockPropertyMetadata, facing::Facing, half::evaluate_half}, world::World, }; use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use super::{BlockProperties, BlockProperty, Direction}; diff --git a/pumpkin/src/block/properties/unstable.rs b/pumpkin/src/block/properties/unstable.rs new file mode 100644 index 000000000..3bfb0c9f1 --- /dev/null +++ b/pumpkin/src/block/properties/unstable.rs @@ -0,0 +1,20 @@ +use async_trait::async_trait; +use pumpkin_macros::block_property; +use pumpkin_world::block::registry::Block; +use pumpkin_world::item::ItemStack; + +use super::{BlockProperty, BlockPropertyMetadata}; + +#[block_property("unstable")] +pub struct Unstable(bool); + +#[async_trait] +impl BlockProperty for Unstable { + async fn on_interact(&self, value: String, _block: &Block, _item: &ItemStack) -> String { + if value == Self::True().value() { + Self::False().value() + } else { + Self::True().value() + } + } +} diff --git a/pumpkin/src/block/properties/waterlog.rs b/pumpkin/src/block/properties/waterlog.rs index 04a47ff39..46dc2a787 100644 --- a/pumpkin/src/block/properties/waterlog.rs +++ b/pumpkin/src/block/properties/waterlog.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use pumpkin_macros::block_property; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::{registry::Block, BlockDirection}; +use pumpkin_world::block::{BlockDirection, registry::Block}; use pumpkin_world::item::ItemStack; use super::{BlockProperties, BlockProperty, BlockPropertyMetadata, Direction}; diff --git a/pumpkin/src/block/pumpkin_block.rs b/pumpkin/src/block/pumpkin_block.rs index 5a88ceaf8..3ebffa126 100644 --- a/pumpkin/src/block/pumpkin_block.rs +++ b/pumpkin/src/block/pumpkin_block.rs @@ -7,8 +7,9 @@ use pumpkin_data::item::Item; use pumpkin_inventory::OpenContainer; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::registry::Block; use pumpkin_world::block::BlockDirection; +use pumpkin_world::block::registry::Block; +use std::sync::Arc; use super::properties::Direction; @@ -30,6 +31,17 @@ pub trait PumpkinBlock: Send + Sync { _server: &Server, ) { } + fn should_drop_items_on_explosion(&self) -> bool { + true + } + async fn explode( + &self, + _block: &Block, + _world: &Arc, + _location: BlockPos, + _server: &Server, + ) { + } async fn use_with_item( &self, _block: &Block, diff --git a/pumpkin/src/block/registry.rs b/pumpkin/src/block/registry.rs index cb8743d5d..3c33acaec 100644 --- a/pumpkin/src/block/registry.rs +++ b/pumpkin/src/block/registry.rs @@ -6,8 +6,8 @@ use pumpkin_data::item::Item; use pumpkin_inventory::OpenContainer; use pumpkin_protocol::server::play::SUseItemOn; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::block::registry::Block; use pumpkin_world::block::BlockDirection; +use pumpkin_world::block::registry::Block; use std::collections::HashMap; use std::sync::Arc; @@ -45,6 +45,19 @@ impl BlockRegistry { } } + pub async fn explode( + &self, + block: &Block, + world: &Arc, + location: BlockPos, + server: &Server, + ) { + let pumpkin_block = self.get_pumpkin_block(block); + if let Some(pumpkin_block) = pumpkin_block { + pumpkin_block.explode(block, world, location, server).await; + } + } + pub async fn use_with_item( &self, block: &Block, diff --git a/pumpkin/src/command/args/block.rs b/pumpkin/src/command/args/block.rs index 8b7b874d4..5debc6506 100644 --- a/pumpkin/src/command/args/block.rs +++ b/pumpkin/src/command/args/block.rs @@ -6,8 +6,8 @@ use crate::{command::dispatcher::CommandError, server::Server}; use super::{ super::{ - args::{ArgumentConsumer, RawArgs}, CommandSender, + args::{ArgumentConsumer, RawArgs}, }, Arg, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; diff --git a/pumpkin/src/command/args/bool.rs b/pumpkin/src/command/args/bool.rs index a304ebec6..9d32680fe 100644 --- a/pumpkin/src/command/args/bool.rs +++ b/pumpkin/src/command/args/bool.rs @@ -1,7 +1,7 @@ +use crate::command::CommandSender; use crate::command::args::{Arg, ArgumentConsumer, FindArg, GetClientSideArgParser}; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; diff --git a/pumpkin/src/command/args/bossbar_color.rs b/pumpkin/src/command/args/bossbar_color.rs index f30e54a90..63882599b 100644 --- a/pumpkin/src/command/args/bossbar_color.rs +++ b/pumpkin/src/command/args/bossbar_color.rs @@ -1,9 +1,9 @@ +use crate::command::CommandSender; use crate::command::args::{ Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use crate::world::bossbar::BossbarColor; use async_trait::async_trait; diff --git a/pumpkin/src/command/args/bossbar_style.rs b/pumpkin/src/command/args/bossbar_style.rs index f06e3c16c..82c6c7d76 100644 --- a/pumpkin/src/command/args/bossbar_style.rs +++ b/pumpkin/src/command/args/bossbar_style.rs @@ -1,9 +1,9 @@ +use crate::command::CommandSender; use crate::command::args::{ Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use crate::world::bossbar::BossbarDivisions; use async_trait::async_trait; diff --git a/pumpkin/src/command/args/bounded_num.rs b/pumpkin/src/command/args/bounded_num.rs index 0d048a5ec..48ae72a0a 100644 --- a/pumpkin/src/command/args/bounded_num.rs +++ b/pumpkin/src/command/args/bounded_num.rs @@ -4,9 +4,9 @@ use std::str::FromStr; use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion}; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use super::super::args::ArgumentConsumer; diff --git a/pumpkin/src/command/args/command.rs b/pumpkin/src/command/args/command.rs index 65da1f9ac..f7b7fec16 100644 --- a/pumpkin/src/command/args/command.rs +++ b/pumpkin/src/command/args/command.rs @@ -5,10 +5,10 @@ use pumpkin_protocol::client::play::{ use crate::{ command::{ + CommandSender, args::SplitSingleWhitespaceIncludingEmptyParts, dispatcher::CommandError, tree::{CommandTree, RawArgs}, - CommandSender, }, server::Server, }; diff --git a/pumpkin/src/command/args/entities.rs b/pumpkin/src/command/args/entities.rs index 398680786..ea5c80274 100644 --- a/pumpkin/src/command/args/entities.rs +++ b/pumpkin/src/command/args/entities.rs @@ -3,9 +3,9 @@ use std::sync::Arc; use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::entity::player::Player; use crate::server::Server; diff --git a/pumpkin/src/command/args/entity.rs b/pumpkin/src/command/args/entity.rs index 24a1a52b2..5016318e9 100644 --- a/pumpkin/src/command/args/entity.rs +++ b/pumpkin/src/command/args/entity.rs @@ -3,9 +3,9 @@ use std::sync::Arc; use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::entity::player::Player; use crate::server::Server; diff --git a/pumpkin/src/command/args/gamemode.rs b/pumpkin/src/command/args/gamemode.rs index 49b2127d9..24d69708c 100644 --- a/pumpkin/src/command/args/gamemode.rs +++ b/pumpkin/src/command/args/gamemode.rs @@ -5,7 +5,7 @@ use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, Suggestion use pumpkin_util::GameMode; use crate::{ - command::{dispatcher::CommandError, tree::RawArgs, CommandSender}, + command::{CommandSender, dispatcher::CommandError, tree::RawArgs}, server::Server, }; diff --git a/pumpkin/src/command/args/message.rs b/pumpkin/src/command/args/message.rs index 4cb24d7b9..7ddc09e68 100644 --- a/pumpkin/src/command/args/message.rs +++ b/pumpkin/src/command/args/message.rs @@ -7,8 +7,8 @@ use crate::{command::dispatcher::CommandError, server::Server}; use super::{ super::{ - args::{ArgumentConsumer, RawArgs}, CommandSender, + args::{ArgumentConsumer, RawArgs}, }, Arg, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; diff --git a/pumpkin/src/command/args/mod.rs b/pumpkin/src/command/args/mod.rs index 7bc02729c..8ac01d7ee 100644 --- a/pumpkin/src/command/args/mod.rs +++ b/pumpkin/src/command/args/mod.rs @@ -3,19 +3,20 @@ use std::{collections::HashMap, hash::Hash, sync::Arc}; use async_trait::async_trait; use bounded_num::{NotInBounds, Number}; use pumpkin_data::damage::DamageType; +use pumpkin_data::entity::EffectType; use pumpkin_data::particle::Particle; use pumpkin_data::sound::SoundCategory; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; use pumpkin_util::text::TextComponent; use pumpkin_util::{ - math::{position::BlockPos, vector2::Vector2, vector3::Vector3}, GameMode, + math::{position::BlockPos, vector2::Vector2, vector3::Vector3}, }; use super::{ + CommandSender, dispatcher::CommandError, tree::{CommandTree, RawArgs}, - CommandSender, }; use crate::world::bossbar::{BossbarColor, BossbarDivisions}; use crate::{entity::player::Player, server::Server}; @@ -27,17 +28,15 @@ pub mod bossbar_style; pub mod bounded_num; pub mod command; mod coordinate; -pub mod damage_type; pub mod entities; pub mod entity; pub mod gamemode; -pub mod item; pub mod message; -pub mod particle; pub mod players; pub mod position_2d; pub mod position_3d; pub mod position_block; +pub mod resource; pub mod resource_location; pub mod rotation; pub mod simple; @@ -105,6 +104,7 @@ pub enum Arg<'a> { Simple(&'a str), SoundCategory(SoundCategory), DamageType(DamageType), + Effect(EffectType), } /// see [`crate::commands::tree::builder::argument`] and [`CommandTree::execute`]/[`crate::commands::tree::builder::NonLeafNodeBuilder::execute`] diff --git a/pumpkin/src/command/args/players.rs b/pumpkin/src/command/args/players.rs index 7c71e690b..16b58f9c6 100644 --- a/pumpkin/src/command/args/players.rs +++ b/pumpkin/src/command/args/players.rs @@ -3,9 +3,9 @@ use std::sync::Arc; use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::entity::player::Player; use crate::server::Server; diff --git a/pumpkin/src/command/args/position_2d.rs b/pumpkin/src/command/args/position_2d.rs index 18c1dc29a..e6c546fbb 100644 --- a/pumpkin/src/command/args/position_2d.rs +++ b/pumpkin/src/command/args/position_2d.rs @@ -3,9 +3,9 @@ use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, Suggestion use pumpkin_util::math::vector2::Vector2; use pumpkin_util::math::vector3::Vector3; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use super::super::args::ArgumentConsumer; diff --git a/pumpkin/src/command/args/position_3d.rs b/pumpkin/src/command/args/position_3d.rs index eba02c4b7..a9848b023 100644 --- a/pumpkin/src/command/args/position_3d.rs +++ b/pumpkin/src/command/args/position_3d.rs @@ -2,9 +2,9 @@ use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; use pumpkin_util::math::vector3::Vector3; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use super::super::args::ArgumentConsumer; diff --git a/pumpkin/src/command/args/position_block.rs b/pumpkin/src/command/args/position_block.rs index 64f95fb33..e9d379fde 100644 --- a/pumpkin/src/command/args/position_block.rs +++ b/pumpkin/src/command/args/position_block.rs @@ -3,9 +3,9 @@ use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, Suggestion use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use super::super::args::ArgumentConsumer; diff --git a/pumpkin/src/command/args/damage_type.rs b/pumpkin/src/command/args/resource/damage_type.rs similarity index 88% rename from pumpkin/src/command/args/damage_type.rs rename to pumpkin/src/command/args/resource/damage_type.rs index e40db91a5..d5dab260b 100644 --- a/pumpkin/src/command/args/damage_type.rs +++ b/pumpkin/src/command/args/resource/damage_type.rs @@ -3,10 +3,13 @@ use pumpkin_data::damage::DamageType; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; use crate::command::{ - args::{Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser}, + CommandSender, + args::{ + Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg, + GetClientSideArgParser, + }, dispatcher::CommandError, tree::RawArgs, - CommandSender, }; use crate::server::Server; @@ -59,7 +62,7 @@ impl DefaultNameArgConsumer for DamageTypeArgumentConsumer { impl<'a> FindArg<'a> for DamageTypeArgumentConsumer { type Data = &'a DamageType; - fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result { + fn find_arg(args: &'a ConsumedArgs, name: &str) -> Result { match args.get(name) { Some(Arg::DamageType(data)) => Ok(data), _ => Err(CommandError::InvalidConsumption(Some(name.to_string()))), diff --git a/pumpkin/src/command/args/resource/effect.rs b/pumpkin/src/command/args/resource/effect.rs new file mode 100644 index 000000000..d071b5258 --- /dev/null +++ b/pumpkin/src/command/args/resource/effect.rs @@ -0,0 +1,71 @@ +use async_trait::async_trait; +use pumpkin_data::entity::EffectType; +use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; + +use crate::command::{ + CommandSender, + args::{ + Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg, + GetClientSideArgParser, + }, + dispatcher::CommandError, + tree::RawArgs, +}; +use crate::server::Server; + +pub struct EffectTypeArgumentConsumer; + +impl GetClientSideArgParser for EffectTypeArgumentConsumer { + fn get_client_side_parser(&self) -> ArgumentType { + ArgumentType::Resource { + identifier: "mob_effect", + } + } + + fn get_client_side_suggestion_type_override(&self) -> Option { + None + } +} + +#[async_trait] +impl ArgumentConsumer for EffectTypeArgumentConsumer { + async fn consume<'a>( + &'a self, + _sender: &CommandSender<'a>, + _server: &'a Server, + args: &mut RawArgs<'a>, + ) -> Option> { + let name = args.pop()?; + + // Create a static damage type first + let damage_type = EffectType::from_name(&name.replace("minecraft:", ""))?; + // Find matching static damage type from values array + Some(Arg::Effect(damage_type)) + } + + async fn suggest<'a>( + &'a self, + _sender: &CommandSender<'a>, + _server: &'a Server, + _input: &'a str, + ) -> Result>, CommandError> { + Ok(None) + } +} + +impl DefaultNameArgConsumer for EffectTypeArgumentConsumer { + fn default_name(&self) -> &'static str { + "mob_effect" + } +} + +impl<'a> FindArg<'a> for EffectTypeArgumentConsumer { + type Data = &'a EffectType; + + fn find_arg(args: &'a ConsumedArgs, name: &str) -> Result { + match args.get(name) { + Some(Arg::Effect(data)) => Ok(data), + _ => Err(CommandError::InvalidConsumption(Some(name.to_string()))), + } + } +} diff --git a/pumpkin/src/command/args/item.rs b/pumpkin/src/command/args/resource/item.rs similarity index 65% rename from pumpkin/src/command/args/item.rs rename to pumpkin/src/command/args/resource/item.rs index 81f61d723..4988884c4 100644 --- a/pumpkin/src/command/args/item.rs +++ b/pumpkin/src/command/args/resource/item.rs @@ -2,15 +2,16 @@ use async_trait::async_trait; use pumpkin_data::item::Item; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; -use crate::{command::dispatcher::CommandError, server::Server}; - -use super::{ - super::{ - args::{ArgumentConsumer, RawArgs}, - CommandSender, +use crate::command::{ + CommandSender, + args::{ + Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg, + GetClientSideArgParser, }, - Arg, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, + dispatcher::CommandError, + tree::RawArgs, }; +use crate::server::Server; pub struct ItemArgumentConsumer; @@ -55,16 +56,17 @@ impl DefaultNameArgConsumer for ItemArgumentConsumer { impl<'a> FindArg<'a> for ItemArgumentConsumer { type Data = (&'a str, Item); - fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result { + fn find_arg(args: &'a ConsumedArgs, name: &str) -> Result { match args.get(name) { - Some(Arg::Item(name)) => Item::from_name(&name.replace("minecraft:", "")).map_or_else( - || { - Err(CommandError::GeneralCommandIssue(format!( - "Item {name} does not exist." - ))) - }, - |item| Ok((*name, item)), - ), + Some(Arg::Item(name)) => Item::from_registry_key(&name.replace("minecraft:", "")) + .map_or_else( + || { + Err(CommandError::GeneralCommandIssue(format!( + "Item {name} does not exist." + ))) + }, + |item| Ok((*name, item)), + ), _ => Err(CommandError::InvalidConsumption(Some(name.to_string()))), } } diff --git a/pumpkin/src/command/args/resource/mod.rs b/pumpkin/src/command/args/resource/mod.rs new file mode 100644 index 000000000..4dbe64dd9 --- /dev/null +++ b/pumpkin/src/command/args/resource/mod.rs @@ -0,0 +1,4 @@ +pub mod damage_type; +pub mod effect; +pub mod item; +pub mod particle; diff --git a/pumpkin/src/command/args/particle.rs b/pumpkin/src/command/args/resource/particle.rs similarity index 88% rename from pumpkin/src/command/args/particle.rs rename to pumpkin/src/command/args/resource/particle.rs index 317375fef..6a2ac3eca 100644 --- a/pumpkin/src/command/args/particle.rs +++ b/pumpkin/src/command/args/resource/particle.rs @@ -3,10 +3,13 @@ use pumpkin_data::particle::Particle; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; use crate::command::{ - args::{Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser}, + CommandSender, + args::{ + Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg, + GetClientSideArgParser, + }, dispatcher::CommandError, tree::RawArgs, - CommandSender, }; use crate::server::Server; @@ -59,7 +62,7 @@ impl DefaultNameArgConsumer for ParticleArgumentConsumer { impl<'a> FindArg<'a> for ParticleArgumentConsumer { type Data = &'a Particle; - fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result { + fn find_arg(args: &'a ConsumedArgs, name: &str) -> Result { match args.get(name) { Some(Arg::Particle(data)) => Ok(data), _ => Err(CommandError::InvalidConsumption(Some(name.to_string()))), diff --git a/pumpkin/src/command/args/resource_location.rs b/pumpkin/src/command/args/resource_location.rs index b6644a313..d9e8ee5c9 100644 --- a/pumpkin/src/command/args/resource_location.rs +++ b/pumpkin/src/command/args/resource_location.rs @@ -1,9 +1,9 @@ +use crate::command::CommandSender; use crate::command::args::{ Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; diff --git a/pumpkin/src/command/args/rotation.rs b/pumpkin/src/command/args/rotation.rs index bc6c414c9..e9546c2a8 100644 --- a/pumpkin/src/command/args/rotation.rs +++ b/pumpkin/src/command/args/rotation.rs @@ -1,9 +1,9 @@ use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use super::super::args::ArgumentConsumer; diff --git a/pumpkin/src/command/args/simple.rs b/pumpkin/src/command/args/simple.rs index 183e70c66..e40b8af51 100644 --- a/pumpkin/src/command/args/simple.rs +++ b/pumpkin/src/command/args/simple.rs @@ -7,8 +7,8 @@ use crate::{command::dispatcher::CommandError, server::Server}; use super::{ super::{ - args::{ArgumentConsumer, RawArgs}, CommandSender, + args::{ArgumentConsumer, RawArgs}, }, Arg, FindArg, GetClientSideArgParser, }; diff --git a/pumpkin/src/command/args/sound.rs b/pumpkin/src/command/args/sound.rs index b3c0ace4a..4763d103c 100644 --- a/pumpkin/src/command/args/sound.rs +++ b/pumpkin/src/command/args/sound.rs @@ -6,8 +6,8 @@ use crate::{command::dispatcher::CommandError, server::Server}; use super::{ super::{ - args::{ArgumentConsumer, RawArgs}, CommandSender, + args::{ArgumentConsumer, RawArgs}, }, Arg, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; diff --git a/pumpkin/src/command/args/sound_category.rs b/pumpkin/src/command/args/sound_category.rs index 6fe531a1a..003f80c80 100644 --- a/pumpkin/src/command/args/sound_category.rs +++ b/pumpkin/src/command/args/sound_category.rs @@ -1,9 +1,9 @@ +use crate::command::CommandSender; use crate::command::args::{ Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use async_trait::async_trait; use pumpkin_data::sound::SoundCategory; diff --git a/pumpkin/src/command/args/summonable_entities.rs b/pumpkin/src/command/args/summonable_entities.rs index 6e86649cb..cf2ec81d4 100644 --- a/pumpkin/src/command/args/summonable_entities.rs +++ b/pumpkin/src/command/args/summonable_entities.rs @@ -6,8 +6,8 @@ use crate::{command::dispatcher::CommandError, server::Server}; use super::{ super::{ - args::{ArgumentConsumer, RawArgs}, CommandSender, + args::{ArgumentConsumer, RawArgs}, }, Arg, DefaultNameArgConsumer, FindArg, GetClientSideArgParser, }; diff --git a/pumpkin/src/command/args/textcomponent.rs b/pumpkin/src/command/args/textcomponent.rs index 739849c38..731089628 100644 --- a/pumpkin/src/command/args/textcomponent.rs +++ b/pumpkin/src/command/args/textcomponent.rs @@ -1,7 +1,7 @@ +use crate::command::CommandSender; use crate::command::args::{Arg, ArgumentConsumer, FindArg, GetClientSideArgParser}; use crate::command::dispatcher::CommandError; use crate::command::tree::RawArgs; -use crate::command::CommandSender; use crate::server::Server; use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; diff --git a/pumpkin/src/command/args/time.rs b/pumpkin/src/command/args/time.rs index de1fffb39..8ae90380f 100644 --- a/pumpkin/src/command/args/time.rs +++ b/pumpkin/src/command/args/time.rs @@ -2,10 +2,10 @@ use async_trait::async_trait; use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders}; use crate::command::{ + CommandSender, args::{Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser}, dispatcher::CommandError, tree::RawArgs, - CommandSender, }; use crate::server::Server; diff --git a/pumpkin/src/command/commands/ban.rs b/pumpkin/src/command/commands/ban.rs index df2301940..a07166343 100644 --- a/pumpkin/src/command/commands/ban.rs +++ b/pumpkin/src/command/commands/ban.rs @@ -1,18 +1,18 @@ use crate::{ command::{ - args::{message::MsgArgConsumer, players::PlayersArgumentConsumer, Arg, ConsumedArgs}, - tree::{builder::argument, CommandTree}, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, message::MsgArgConsumer, players::PlayersArgumentConsumer}, + tree::{CommandTree, builder::argument}, }, data::{ - banlist_serializer::BannedPlayerEntry, banned_player_data::BANNED_PLAYER_LIST, - SaveJSONConfiguration, + SaveJSONConfiguration, banlist_serializer::BannedPlayerEntry, + banned_player_data::BANNED_PLAYER_LIST, }, entity::player::Player, }; +use CommandError::InvalidConsumption; use async_trait::async_trait; use pumpkin_util::text::TextComponent; -use CommandError::InvalidConsumption; const NAMES: [&str; 1] = ["ban"]; const DESCRIPTION: &str = "bans a player"; @@ -20,10 +20,10 @@ const DESCRIPTION: &str = "bans a player"; const ARG_TARGET: &str = "player"; const ARG_REASON: &str = "reason"; -struct BanNoReasonExecutor; +struct NoReasonExecutor; #[async_trait] -impl CommandExecutor for BanNoReasonExecutor { +impl CommandExecutor for NoReasonExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -39,10 +39,10 @@ impl CommandExecutor for BanNoReasonExecutor { } } -struct BanReasonExecutor; +struct ReasonExecutor; #[async_trait] -impl CommandExecutor for BanReasonExecutor { +impl CommandExecutor for ReasonExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -107,7 +107,7 @@ async fn ban_player(sender: &CommandSender<'_>, player: &Player, reason: Option< pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_TARGET, PlayersArgumentConsumer) - .execute(BanNoReasonExecutor) - .then(argument(ARG_REASON, MsgArgConsumer).execute(BanReasonExecutor)), + .execute(NoReasonExecutor) + .then(argument(ARG_REASON, MsgArgConsumer).execute(ReasonExecutor)), ) } diff --git a/pumpkin/src/command/commands/banip.rs b/pumpkin/src/command/commands/banip.rs index fd8330af2..7f3636446 100644 --- a/pumpkin/src/command/commands/banip.rs +++ b/pumpkin/src/command/commands/banip.rs @@ -2,19 +2,19 @@ use std::{net::IpAddr, str::FromStr}; use crate::{ command::{ - args::{message::MsgArgConsumer, simple::SimpleArgConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, message::MsgArgConsumer, simple::SimpleArgConsumer}, + tree::CommandTree, + tree::builder::argument, }, data::{ - banlist_serializer::BannedIpEntry, banned_ip_data::BANNED_IP_LIST, SaveJSONConfiguration, + SaveJSONConfiguration, banlist_serializer::BannedIpEntry, banned_ip_data::BANNED_IP_LIST, }, server::Server, }; +use CommandError::InvalidConsumption; use async_trait::async_trait; use pumpkin_util::text::TextComponent; -use CommandError::InvalidConsumption; const NAMES: [&str; 1] = ["ban-ip"]; const DESCRIPTION: &str = "bans a player-ip"; @@ -36,10 +36,10 @@ async fn parse_ip(target: &str, server: &Server) -> Option { }) } -struct BanIpNoReasonExecutor; +struct NoReasonExecutor; #[async_trait] -impl CommandExecutor for BanIpNoReasonExecutor { +impl CommandExecutor for NoReasonExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -55,10 +55,10 @@ impl CommandExecutor for BanIpNoReasonExecutor { } } -struct BanIpReasonExecutor; +struct ReasonExecutor; #[async_trait] -impl CommandExecutor for BanIpReasonExecutor { +impl CommandExecutor for ReasonExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -148,7 +148,7 @@ async fn ban_ip(sender: &CommandSender<'_>, server: &Server, target: &str, reaso pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_TARGET, SimpleArgConsumer) - .execute(BanIpNoReasonExecutor) - .then(argument(ARG_REASON, MsgArgConsumer).execute(BanIpReasonExecutor)), + .execute(NoReasonExecutor) + .then(argument(ARG_REASON, MsgArgConsumer).execute(ReasonExecutor)), ) } diff --git a/pumpkin/src/command/commands/banlist.rs b/pumpkin/src/command/commands/banlist.rs index f5f09b709..03d94e5d1 100644 --- a/pumpkin/src/command/commands/banlist.rs +++ b/pumpkin/src/command/commands/banlist.rs @@ -1,25 +1,25 @@ use crate::{ command::{ - args::{simple::SimpleArgConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, simple::SimpleArgConsumer}, + tree::CommandTree, + tree::builder::argument, }, data::{banned_ip_data::BANNED_IP_LIST, banned_player_data::BANNED_PLAYER_LIST}, }; +use CommandError::InvalidConsumption; use async_trait::async_trait; use pumpkin_util::text::TextComponent; -use CommandError::InvalidConsumption; const NAMES: [&str; 1] = ["banlist"]; const DESCRIPTION: &str = "shows the banlist"; const ARG_LIST_TYPE: &str = "ips|players"; -struct BanListExecutor; +struct ListExecutor; #[async_trait] -impl CommandExecutor for BanListExecutor { +impl CommandExecutor for ListExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -66,7 +66,7 @@ impl CommandExecutor for BanListExecutor { _ => { return Err(CommandError::GeneralCommandIssue( "Incorrect argument for command".to_string(), - )) + )); } } @@ -74,10 +74,10 @@ impl CommandExecutor for BanListExecutor { } } -struct BanListAllExecutor; +struct ListAllExecutor; #[async_trait] -impl CommandExecutor for BanListAllExecutor { +impl CommandExecutor for ListAllExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -138,6 +138,6 @@ async fn handle_banlist(list: Vec<(String, String, String)>, sender: &CommandSen pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .execute(BanListAllExecutor) - .then(argument(ARG_LIST_TYPE, SimpleArgConsumer).execute(BanListExecutor)) + .execute(ListAllExecutor) + .then(argument(ARG_LIST_TYPE, SimpleArgConsumer).execute(ListExecutor)) } diff --git a/pumpkin/src/command/commands/bossbar.rs b/pumpkin/src/command/commands/bossbar.rs index a2d9bcea2..6c6ea96c5 100644 --- a/pumpkin/src/command/commands/bossbar.rs +++ b/pumpkin/src/command/commands/bossbar.rs @@ -9,16 +9,16 @@ use crate::command::args::{ConsumedArgs, FindArg, FindArgDefaultName}; use crate::command::dispatcher::CommandError; use crate::command::args::textcomponent::TextComponentArgConsumer; -use crate::command::tree::builder::{argument, argument_default_name, literal}; use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, argument_default_name, literal}; use crate::command::{CommandExecutor, CommandSender}; use crate::server::Server; use crate::world::bossbar::Bossbar; use crate::world::custom_bossbar::BossbarUpdateError; use async_trait::async_trait; +use pumpkin_util::text::TextComponent; use pumpkin_util::text::color::{Color, NamedColor}; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_util::text::TextComponent; use uuid::Uuid; const NAMES: [&str; 1] = ["bossbar"]; @@ -52,10 +52,10 @@ enum CommandValueSet { Visible, } -struct BossbarAddExecuter; +struct AddExecuter; #[async_trait] -impl CommandExecutor for BossbarAddExecuter { +impl CommandExecutor for AddExecuter { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -101,10 +101,10 @@ impl CommandExecutor for BossbarAddExecuter { } } -struct BossbarGetExecuter(CommandValueGet); +struct GetExecuter(CommandValueGet); #[async_trait] -impl CommandExecutor for BossbarGetExecuter { +impl CommandExecutor for GetExecuter { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -179,10 +179,10 @@ impl CommandExecutor for BossbarGetExecuter { } } -struct BossbarListExecuter; +struct ListExecuter; #[async_trait] -impl CommandExecutor for BossbarListExecuter { +impl CommandExecutor for ListExecuter { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -238,10 +238,10 @@ impl CommandExecutor for BossbarListExecuter { } } -struct BossbarRemoveExecuter; +struct RemoveExecuter; #[async_trait] -impl CommandExecutor for BossbarRemoveExecuter { +impl CommandExecutor for RemoveExecuter { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -289,10 +289,10 @@ impl CommandExecutor for BossbarRemoveExecuter { } } -struct BossbarSetExecuter(CommandValueSet); +struct SetExecuter(CommandValueSet); #[async_trait] -impl CommandExecutor for BossbarSetExecuter { +impl CommandExecutor for SetExecuter { #[expect(clippy::too_many_lines)] async fn execute<'a>( &self, @@ -591,25 +591,24 @@ fn value_consumer() -> BoundedNumArgumentConsumer { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) .then( - literal("add") - .then(argument_default_name(non_autocomplete_consumer()).then( - argument(ARG_NAME, TextComponentArgConsumer).execute(BossbarAddExecuter), - )), + literal("add").then( + argument_default_name(non_autocomplete_consumer()) + .then(argument(ARG_NAME, TextComponentArgConsumer).execute(AddExecuter)), + ), ) .then( literal("get").then( argument_default_name(autocomplete_consumer()) - .then(literal("max").execute(BossbarGetExecuter(CommandValueGet::Max))) - .then(literal("players").execute(BossbarGetExecuter(CommandValueGet::Players))) - .then(literal("value").execute(BossbarGetExecuter(CommandValueGet::Value))) - .then(literal("visible").execute(BossbarGetExecuter(CommandValueGet::Visible))), + .then(literal("max").execute(GetExecuter(CommandValueGet::Max))) + .then(literal("players").execute(GetExecuter(CommandValueGet::Players))) + .then(literal("value").execute(GetExecuter(CommandValueGet::Value))) + .then(literal("visible").execute(GetExecuter(CommandValueGet::Visible))), ), ) - .then(literal("list").execute(BossbarListExecuter)) + .then(literal("list").execute(ListExecuter)) .then( - literal("remove").then( - argument_default_name(autocomplete_consumer()).execute(BossbarRemoveExecuter), - ), + literal("remove") + .then(argument_default_name(autocomplete_consumer()).execute(RemoveExecuter)), ) .then( literal("set").then( @@ -617,45 +616,45 @@ pub fn init_command_tree() -> CommandTree { .then( literal("color").then( argument_default_name(BossbarColorArgumentConsumer) - .execute(BossbarSetExecuter(CommandValueSet::Color)), + .execute(SetExecuter(CommandValueSet::Color)), ), ) .then( literal("max").then( argument_default_name(max_value_consumer()) - .execute(BossbarSetExecuter(CommandValueSet::Max)), + .execute(SetExecuter(CommandValueSet::Max)), ), ) .then( literal("name").then( argument(ARG_NAME, TextComponentArgConsumer) - .execute(BossbarSetExecuter(CommandValueSet::Name)), + .execute(SetExecuter(CommandValueSet::Name)), ), ) .then( literal("players") .then( argument_default_name(PlayersArgumentConsumer) - .execute(BossbarSetExecuter(CommandValueSet::Players(true))), + .execute(SetExecuter(CommandValueSet::Players(true))), ) - .execute(BossbarSetExecuter(CommandValueSet::Players(false))), + .execute(SetExecuter(CommandValueSet::Players(false))), ) .then( literal("style").then( argument_default_name(BossbarStyleArgumentConsumer) - .execute(BossbarSetExecuter(CommandValueSet::Style)), + .execute(SetExecuter(CommandValueSet::Style)), ), ) .then( literal("value").then( argument_default_name(value_consumer()) - .execute(BossbarSetExecuter(CommandValueSet::Value)), + .execute(SetExecuter(CommandValueSet::Value)), ), ) .then( literal("visible").then( argument(ARG_VISIBLE, BoolArgConsumer) - .execute(BossbarSetExecuter(CommandValueSet::Visible)), + .execute(SetExecuter(CommandValueSet::Visible)), ), ), ), diff --git a/pumpkin/src/command/commands/clear.rs b/pumpkin/src/command/commands/clear.rs index 478be7886..ecfbafaba 100644 --- a/pumpkin/src/command/commands/clear.rs +++ b/pumpkin/src/command/commands/clear.rs @@ -2,15 +2,15 @@ use std::sync::Arc; use async_trait::async_trait; use pumpkin_inventory::Container; +use pumpkin_util::text::TextComponent; use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::color::NamedColor; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_util::text::TextComponent; use crate::command::args::entities::EntitiesArgumentConsumer; use crate::command::args::{Arg, ConsumedArgs}; -use crate::command::tree::builder::{argument, require}; use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, require}; use crate::command::{CommandError, CommandExecutor, CommandSender}; use crate::entity::player::Player; use CommandError::InvalidConsumption; @@ -73,10 +73,10 @@ fn clear_command_text_output(item_count: usize, targets: &[Arc]) -> Text } } -struct ClearExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for ClearExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -100,10 +100,10 @@ impl CommandExecutor for ClearExecutor { } } -struct ClearSelfExecutor; +struct SelfExecutor; #[async_trait] -impl CommandExecutor for ClearSelfExecutor { +impl CommandExecutor for SelfExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -126,6 +126,6 @@ impl CommandExecutor for ClearSelfExecutor { #[allow(clippy::redundant_closure_for_method_calls)] // causes lifetime issues pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_TARGET, EntitiesArgumentConsumer).execute(ClearExecutor)) - .then(require(|sender| sender.is_player()).execute(ClearSelfExecutor)) + .then(argument(ARG_TARGET, EntitiesArgumentConsumer).execute(Executor)) + .then(require(|sender| sender.is_player()).execute(SelfExecutor)) } diff --git a/pumpkin/src/command/commands/damage.rs b/pumpkin/src/command/commands/damage.rs index dbe4537d7..1621b57b6 100644 --- a/pumpkin/src/command/commands/damage.rs +++ b/pumpkin/src/command/commands/damage.rs @@ -1,19 +1,21 @@ use async_trait::async_trait; use pumpkin_data::damage::DamageType; use pumpkin_util::text::{ - color::{Color, NamedColor}, TextComponent, + color::{Color, NamedColor}, }; use crate::command::{ + CommandError, CommandExecutor, CommandSender, args::{ - bounded_num::BoundedNumArgumentConsumer, damage_type::DamageTypeArgumentConsumer, - entity::EntityArgumentConsumer, position_3d::Position3DArgumentConsumer, Arg, ConsumedArgs, - FindArg, + Arg, ConsumedArgs, FindArg, bounded_num::BoundedNumArgumentConsumer, + entity::EntityArgumentConsumer, position_3d::Position3DArgumentConsumer, + resource::damage_type::DamageTypeArgumentConsumer, + }, + tree::{ + CommandTree, + builder::{argument, literal}, }, - tree::builder::{argument, literal}, - tree::CommandTree, - CommandError, CommandExecutor, CommandSender, }; const NAMES: [&str; 1] = ["damage"]; @@ -29,8 +31,8 @@ fn amount_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().name(ARG_AMOUNT).min(0.0) } -struct DamageLocationExecutor; -struct DamageEntityExecutor(bool); +struct LocationExecutor; +struct EntityExecutor(bool); async fn send_damage_result( sender: &mut CommandSender<'_>, @@ -60,7 +62,7 @@ async fn send_damage_result( } #[async_trait] -impl CommandExecutor for DamageLocationExecutor { +impl CommandExecutor for LocationExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -100,7 +102,7 @@ impl CommandExecutor for DamageLocationExecutor { } #[async_trait] -impl CommandExecutor for DamageEntityExecutor { +impl CommandExecutor for EntityExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -155,28 +157,28 @@ pub fn init_command_tree() -> CommandTree { argument(ARG_TARGET, EntityArgumentConsumer).then( argument(ARG_AMOUNT, amount_consumer()) // Basic damage - .execute(DamageEntityExecutor(false)) + .execute(EntityExecutor(false)) // With damage type .then( argument(ARG_DAMAGE_TYPE, DamageTypeArgumentConsumer) - .execute(DamageEntityExecutor(false)) + .execute(EntityExecutor(false)) // At location .then( literal("at").then( argument(ARG_LOCATION, Position3DArgumentConsumer) - .execute(DamageLocationExecutor), + .execute(LocationExecutor), ), ) // By entity .then( literal("by").then( argument(ARG_ENTITY, EntityArgumentConsumer) - .execute(DamageEntityExecutor(false)) + .execute(EntityExecutor(false)) // From cause .then( literal("from").then( argument(ARG_CAUSE, EntityArgumentConsumer) - .execute(DamageEntityExecutor(true)), + .execute(EntityExecutor(true)), ), ), ), diff --git a/pumpkin/src/command/commands/deop.rs b/pumpkin/src/command/commands/deop.rs index ce6e98661..67684f9f8 100644 --- a/pumpkin/src/command/commands/deop.rs +++ b/pumpkin/src/command/commands/deop.rs @@ -1,24 +1,24 @@ use crate::{ command::{ - args::{players::PlayersArgumentConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, players::PlayersArgumentConsumer}, + tree::CommandTree, + tree::builder::argument, }, - data::{op_data::OPERATOR_CONFIG, SaveJSONConfiguration}, + data::{SaveJSONConfiguration, op_data::OPERATOR_CONFIG}, }; +use CommandError::InvalidConsumption; use async_trait::async_trait; use pumpkin_util::text::TextComponent; -use CommandError::InvalidConsumption; const NAMES: [&str; 1] = ["deop"]; const DESCRIPTION: &str = "Revokes operator status from a player."; const ARG_TARGETS: &str = "targets"; -struct DeopExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for DeopExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -61,5 +61,5 @@ impl CommandExecutor for DeopExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_TARGETS, PlayersArgumentConsumer).execute(DeopExecutor)) + .then(argument(ARG_TARGETS, PlayersArgumentConsumer).execute(Executor)) } diff --git a/pumpkin/src/command/commands/effect.rs b/pumpkin/src/command/commands/effect.rs new file mode 100644 index 000000000..8bc48209a --- /dev/null +++ b/pumpkin/src/command/commands/effect.rs @@ -0,0 +1,100 @@ +use async_trait::async_trait; + +use crate::command::args::resource::effect::EffectTypeArgumentConsumer; + +use crate::TextComponent; + +use crate::command::args::players::PlayersArgumentConsumer; + +use crate::command::args::{Arg, ConsumedArgs}; +use crate::command::dispatcher::CommandError; +use crate::command::dispatcher::CommandError::InvalidConsumption; +use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, literal}; +use crate::command::{CommandExecutor, CommandSender}; +use crate::server::Server; + +const NAMES: [&str; 1] = ["effect"]; + +const DESCRIPTION: &str = "Adds or removes the status effects of players and other entities."; + +// const ARG_CLEAR: &str = "clear"; +const ARG_GIVE: &str = "give"; + +const ARG_TARGET: &str = "target"; +const ARG_EFFECT: &str = "effect"; + +struct GiveExecutor; + +#[async_trait] +impl CommandExecutor for GiveExecutor { + async fn execute<'a>( + &self, + sender: &mut CommandSender<'a>, + _server: &Server, + args: &ConsumedArgs<'a>, + ) -> Result<(), CommandError> { + let Some(Arg::Players(targets)) = args.get(ARG_TARGET) else { + return Err(InvalidConsumption(Some(ARG_TARGET.into()))); + }; + let Some(Arg::Effect(effect)) = args.get(ARG_EFFECT) else { + return Err(InvalidConsumption(Some(ARG_EFFECT.into()))); + }; + + let target_count = targets.len(); + + for target in targets { + target + .add_effect( + crate::entity::effect::Effect { + r#type: *effect, + duration: 30, + amplifier: 1, + ambient: true, + show_particles: true, + show_icon: true, + }, + true, + ) + .await; + } + + let translation_name = + TextComponent::translate(format!("effect.minecraft.{}", effect.to_name()), []); + if target_count == 1 { + // TODO: use entity name + sender + .send_message(TextComponent::translate( + "commands.effect.give.success.single", + [ + translation_name, + TextComponent::text(targets[0].gameprofile.name.clone()), + ], + )) + .await; + } else { + sender + .send_message(TextComponent::translate( + "commands.effect.give.success.multiple", + [ + translation_name, + TextComponent::text(target_count.to_string()), + ], + )) + .await; + } + + Ok(()) + } +} + +#[allow(clippy::redundant_closure_for_method_calls)] +pub fn init_command_tree() -> CommandTree { + CommandTree::new(NAMES, DESCRIPTION).then( + literal(ARG_GIVE).then( + argument(ARG_TARGET, PlayersArgumentConsumer) + .then(argument(ARG_EFFECT, EffectTypeArgumentConsumer).execute(GiveExecutor)), + ), + ) + // TODO: Add more things +} diff --git a/pumpkin/src/command/commands/experience.rs b/pumpkin/src/command/commands/experience.rs index 73cf9633a..fe322596f 100644 --- a/pumpkin/src/command/commands/experience.rs +++ b/pumpkin/src/command/commands/experience.rs @@ -2,14 +2,14 @@ use std::sync::atomic::Ordering; use async_trait::async_trait; use pumpkin_util::math::experience; -use pumpkin_util::text::color::{Color, NamedColor}; use pumpkin_util::text::TextComponent; +use pumpkin_util::text::color::{Color, NamedColor}; use crate::command::args::bounded_num::BoundedNumArgumentConsumer; use crate::command::args::players::PlayersArgumentConsumer; use crate::command::args::{ConsumedArgs, FindArg}; -use crate::command::tree::builder::{argument, literal}; use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, literal}; use crate::command::{CommandError, CommandExecutor, CommandSender}; use crate::entity::player::Player; @@ -38,12 +38,12 @@ enum ExpType { Levels, } -struct ExperienceExecutor { +struct Executor { mode: Mode, exp_type: Option, } -impl ExperienceExecutor { +impl Executor { async fn handle_query( &self, sender: &mut CommandSender<'_>, @@ -202,7 +202,7 @@ impl ExperienceExecutor { } #[async_trait] -impl CommandExecutor for ExperienceExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -281,15 +281,15 @@ pub fn init_command_tree() -> CommandTree { literal("add").then( argument(ARG_TARGETS, PlayersArgumentConsumer).then( argument(ARG_AMOUNT, xp_amount()) - .then(literal("levels").execute(ExperienceExecutor { + .then(literal("levels").execute(Executor { mode: Mode::Add, exp_type: Some(ExpType::Levels), })) - .then(literal("points").execute(ExperienceExecutor { + .then(literal("points").execute(Executor { mode: Mode::Add, exp_type: Some(ExpType::Points), })) - .execute(ExperienceExecutor { + .execute(Executor { mode: Mode::Add, exp_type: Some(ExpType::Points), }), @@ -300,15 +300,15 @@ pub fn init_command_tree() -> CommandTree { literal("set").then( argument(ARG_TARGETS, PlayersArgumentConsumer).then( argument(ARG_AMOUNT, xp_amount()) - .then(literal("levels").execute(ExperienceExecutor { + .then(literal("levels").execute(Executor { mode: Mode::Set, exp_type: Some(ExpType::Levels), })) - .then(literal("points").execute(ExperienceExecutor { + .then(literal("points").execute(Executor { mode: Mode::Set, exp_type: Some(ExpType::Points), })) - .execute(ExperienceExecutor { + .execute(Executor { mode: Mode::Set, exp_type: Some(ExpType::Points), }), @@ -318,11 +318,11 @@ pub fn init_command_tree() -> CommandTree { .then( literal("query").then( argument(ARG_TARGETS, PlayersArgumentConsumer) - .then(literal("levels").execute(ExperienceExecutor { + .then(literal("levels").execute(Executor { mode: Mode::Query, exp_type: Some(ExpType::Levels), })) - .then(literal("points").execute(ExperienceExecutor { + .then(literal("points").execute(Executor { mode: Mode::Query, exp_type: Some(ExpType::Points), })), diff --git a/pumpkin/src/command/commands/fill.rs b/pumpkin/src/command/commands/fill.rs index 6fada48b6..f562f25eb 100644 --- a/pumpkin/src/command/commands/fill.rs +++ b/pumpkin/src/command/commands/fill.rs @@ -1,8 +1,8 @@ use crate::command::args::block::BlockArgumentConsumer; use crate::command::args::position_block::BlockPosArgumentConsumer; use crate::command::args::{ConsumedArgs, FindArg}; -use crate::command::tree::builder::{argument, literal}; use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, literal}; use crate::command::{CommandError, CommandExecutor, CommandSender}; use async_trait::async_trait; @@ -33,11 +33,11 @@ enum Mode { Replace, } -struct SetblockExecutor(Mode); +struct Executor(Mode); #[expect(clippy::too_many_lines)] #[async_trait] -impl CommandExecutor for SetblockExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -164,12 +164,12 @@ pub fn init_command_tree() -> CommandTree { argument(ARG_FROM, BlockPosArgumentConsumer).then( argument(ARG_TO, BlockPosArgumentConsumer).then( argument(ARG_BLOCK, BlockArgumentConsumer) - .then(literal("destroy").execute(SetblockExecutor(Mode::Destroy))) - .then(literal("hollow").execute(SetblockExecutor(Mode::Hollow))) - .then(literal("keep").execute(SetblockExecutor(Mode::Keep))) - .then(literal("outline").execute(SetblockExecutor(Mode::Outline))) - .then(literal("replace").execute(SetblockExecutor(Mode::Replace))) - .execute(SetblockExecutor(Mode::Replace)), + .then(literal("destroy").execute(Executor(Mode::Destroy))) + .then(literal("hollow").execute(Executor(Mode::Hollow))) + .then(literal("keep").execute(Executor(Mode::Keep))) + .then(literal("outline").execute(Executor(Mode::Outline))) + .then(literal("replace").execute(Executor(Mode::Replace))) + .execute(Executor(Mode::Replace)), ), ), ) diff --git a/pumpkin/src/command/commands/gamemode.rs b/pumpkin/src/command/commands/gamemode.rs index 016bd8eb6..984c8a3fb 100644 --- a/pumpkin/src/command/commands/gamemode.rs +++ b/pumpkin/src/command/commands/gamemode.rs @@ -1,18 +1,18 @@ use async_trait::async_trait; -use crate::command::args::gamemode::GamemodeArgumentConsumer; use crate::command::args::GetCloned; +use crate::command::args::gamemode::GamemodeArgumentConsumer; use crate::TextComponent; use crate::command::args::players::PlayersArgumentConsumer; +use crate::command::CommandSender::Player; use crate::command::args::{Arg, ConsumedArgs}; use crate::command::dispatcher::CommandError; use crate::command::dispatcher::CommandError::{InvalidConsumption, InvalidRequirement}; -use crate::command::tree::builder::{argument, require}; use crate::command::tree::CommandTree; -use crate::command::CommandSender::Player; +use crate::command::tree::builder::{argument, require}; use crate::command::{CommandExecutor, CommandSender}; use crate::server::Server; @@ -23,10 +23,10 @@ const DESCRIPTION: &str = "Change a player's gamemode."; const ARG_GAMEMODE: &str = "gamemode"; const ARG_TARGET: &str = "target"; -struct GamemodeTargetSelf; +struct TargetSelfExecutor; #[async_trait] -impl CommandExecutor for GamemodeTargetSelf { +impl CommandExecutor for TargetSelfExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -56,10 +56,10 @@ impl CommandExecutor for GamemodeTargetSelf { } } -struct GamemodeTargetPlayer; +struct TargetPlayerExecutor; #[async_trait] -impl CommandExecutor for GamemodeTargetPlayer { +impl CommandExecutor for TargetPlayerExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -108,7 +108,7 @@ impl CommandExecutor for GamemodeTargetPlayer { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_GAMEMODE, GamemodeArgumentConsumer) - .then(require(|sender| sender.is_player()).execute(GamemodeTargetSelf)) - .then(argument(ARG_TARGET, PlayersArgumentConsumer).execute(GamemodeTargetPlayer)), + .then(require(|sender| sender.is_player()).execute(TargetSelfExecutor)) + .then(argument(ARG_TARGET, PlayersArgumentConsumer).execute(TargetPlayerExecutor)), ) } diff --git a/pumpkin/src/command/commands/give.rs b/pumpkin/src/command/commands/give.rs index 9c2184383..177fe9e64 100644 --- a/pumpkin/src/command/commands/give.rs +++ b/pumpkin/src/command/commands/give.rs @@ -1,15 +1,15 @@ use async_trait::async_trait; +use pumpkin_util::text::TextComponent; use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::color::{Color, NamedColor}; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_util::text::TextComponent; use crate::command::args::bounded_num::BoundedNumArgumentConsumer; -use crate::command::args::item::ItemArgumentConsumer; use crate::command::args::players::PlayersArgumentConsumer; +use crate::command::args::resource::item::ItemArgumentConsumer; use crate::command::args::{ConsumedArgs, FindArg, FindArgDefaultName}; -use crate::command::tree::builder::{argument, argument_default_name}; use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, argument_default_name}; use crate::command::{CommandError, CommandExecutor, CommandSender}; const NAMES: [&str; 1] = ["give"]; @@ -25,10 +25,10 @@ fn item_count_consumer() -> BoundedNumArgumentConsumer { .max(i32::MAX) } -struct GiveExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for GiveExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -54,7 +54,7 @@ impl CommandExecutor for GiveExecutor { }; for target in targets { - target.give_items(item, item_count as u32).await; + target.give_items(item.clone(), item_count as u32).await; } let msg = if targets.len() == 1 { TextComponent::translate( @@ -112,8 +112,8 @@ pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument_default_name(PlayersArgumentConsumer).then( argument(ARG_ITEM, ItemArgumentConsumer) - .execute(GiveExecutor) - .then(argument_default_name(item_count_consumer()).execute(GiveExecutor)), + .execute(Executor) + .then(argument_default_name(item_count_consumer()).execute(Executor)), ), ) } diff --git a/pumpkin/src/command/commands/help.rs b/pumpkin/src/command/commands/help.rs index ea7184811..5e65a6801 100644 --- a/pumpkin/src/command/commands/help.rs +++ b/pumpkin/src/command/commands/help.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; +use pumpkin_util::text::TextComponent; use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::color::{Color, NamedColor}; -use pumpkin_util::text::TextComponent; use crate::command::args::bounded_num::BoundedNumArgumentConsumer; use crate::command::args::command::CommandTreeArgumentConsumer; @@ -25,10 +25,10 @@ fn page_number_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().name("page").min(1) } -struct CommandHelpExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for CommandHelpExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -132,7 +132,7 @@ impl CommandExecutor for BaseHelpExecutor { dispatcher .permissions .get(&tree.names[0]) - .map_or(true, |perm| sender.has_permission_lvl(*perm)) + .is_none_or(|perm| sender.has_permission_lvl(*perm)) }) .collect(); @@ -222,7 +222,7 @@ impl CommandExecutor for BaseHelpExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_COMMAND, CommandTreeArgumentConsumer).execute(CommandHelpExecutor)) + .then(argument(ARG_COMMAND, CommandTreeArgumentConsumer).execute(Executor)) .then(argument_default_name(page_number_consumer()).execute(BaseHelpExecutor)) .execute(BaseHelpExecutor) } diff --git a/pumpkin/src/command/commands/kick.rs b/pumpkin/src/command/commands/kick.rs index c0d3c492d..092694c06 100644 --- a/pumpkin/src/command/commands/kick.rs +++ b/pumpkin/src/command/commands/kick.rs @@ -1,13 +1,13 @@ use async_trait::async_trait; -use pumpkin_util::text::color::NamedColor; use pumpkin_util::text::TextComponent; +use pumpkin_util::text::color::NamedColor; +use crate::command::CommandError; use crate::command::args::message::MsgArgConsumer; use crate::command::args::players::PlayersArgumentConsumer; use crate::command::args::{Arg, ConsumedArgs}; -use crate::command::tree::builder::argument; use crate::command::tree::CommandTree; -use crate::command::CommandError; +use crate::command::tree::builder::argument; use crate::command::{CommandExecutor, CommandSender}; use CommandError::InvalidConsumption; @@ -18,10 +18,10 @@ const ARG_TARGETS: &str = "targets"; const ARG_REASON: &str = "reason"; -struct KickExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for KickExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -52,7 +52,7 @@ impl CommandExecutor for KickExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_TARGETS, PlayersArgumentConsumer) - .execute(KickExecutor) - .then(argument(ARG_REASON, MsgArgConsumer).execute(KickExecutor)), + .execute(Executor) + .then(argument(ARG_REASON, MsgArgConsumer).execute(Executor)), ) } diff --git a/pumpkin/src/command/commands/kill.rs b/pumpkin/src/command/commands/kill.rs index 03ffd16ce..45e3a8c99 100644 --- a/pumpkin/src/command/commands/kill.rs +++ b/pumpkin/src/command/commands/kill.rs @@ -1,13 +1,13 @@ use async_trait::async_trait; use pumpkin_data::entity; +use pumpkin_util::text::TextComponent; use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_util::text::TextComponent; use crate::command::args::entities::EntitiesArgumentConsumer; use crate::command::args::{Arg, ConsumedArgs}; -use crate::command::tree::builder::{argument, require}; use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, require}; use crate::command::{CommandError, CommandExecutor, CommandSender}; use CommandError::InvalidConsumption; @@ -16,10 +16,10 @@ const DESCRIPTION: &str = "Kills all target entities."; const ARG_TARGET: &str = "target"; -struct KillExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for KillExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -66,10 +66,10 @@ impl CommandExecutor for KillExecutor { } } -struct KillSelfExecutor; +struct SelfExecutor; #[async_trait] -impl CommandExecutor for KillSelfExecutor { +impl CommandExecutor for SelfExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -104,6 +104,6 @@ impl CommandExecutor for KillSelfExecutor { #[allow(clippy::redundant_closure_for_method_calls)] // causes lifetime issues pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_TARGET, EntitiesArgumentConsumer).execute(KillExecutor)) - .then(require(|sender| sender.is_player()).execute(KillSelfExecutor)) + .then(argument(ARG_TARGET, EntitiesArgumentConsumer).execute(Executor)) + .then(require(|sender| sender.is_player()).execute(SelfExecutor)) } diff --git a/pumpkin/src/command/commands/list.rs b/pumpkin/src/command/commands/list.rs index b1cc81621..d10d3b9dd 100644 --- a/pumpkin/src/command/commands/list.rs +++ b/pumpkin/src/command/commands/list.rs @@ -6,7 +6,7 @@ use pumpkin_util::text::TextComponent; use crate::{ command::{ - args::ConsumedArgs, tree::CommandTree, CommandError, CommandExecutor, CommandSender, + CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree, }, entity::player::Player, }; @@ -15,10 +15,10 @@ const NAMES: [&str; 1] = ["list"]; const DESCRIPTION: &str = "Print the list of online players."; -struct ListExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for ListExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -54,5 +54,5 @@ fn get_player_names(players: Vec>) -> String { } pub fn init_command_tree() -> CommandTree { - CommandTree::new(NAMES, DESCRIPTION).execute(ListExecutor) + CommandTree::new(NAMES, DESCRIPTION).execute(Executor) } diff --git a/pumpkin/src/command/commands/me.rs b/pumpkin/src/command/commands/me.rs index ad51b854c..984500790 100644 --- a/pumpkin/src/command/commands/me.rs +++ b/pumpkin/src/command/commands/me.rs @@ -3,10 +3,10 @@ use pumpkin_data::world::EMOTE_COMMAND; use pumpkin_util::text::TextComponent; use crate::command::{ - args::{message::MsgArgConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, message::MsgArgConsumer}, + tree::CommandTree, + tree::builder::argument, }; use CommandError::InvalidConsumption; @@ -16,10 +16,10 @@ const DESCRIPTION: &str = "Broadcasts a narrative message about yourself."; const ARG_MESSAGE: &str = "action"; -struct MeExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for MeExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -44,5 +44,5 @@ impl CommandExecutor for MeExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_MESSAGE, MsgArgConsumer).execute(MeExecutor)) + .then(argument(ARG_MESSAGE, MsgArgConsumer).execute(Executor)) } diff --git a/pumpkin/src/command/commands/mod.rs b/pumpkin/src/command/commands/mod.rs index 0459f26ac..87afd04ff 100644 --- a/pumpkin/src/command/commands/mod.rs +++ b/pumpkin/src/command/commands/mod.rs @@ -1,36 +1,90 @@ -pub mod ban; -pub mod banip; -pub mod banlist; -pub mod bossbar; -pub mod clear; -pub mod damage; -pub mod deop; -pub mod experience; -pub mod fill; -pub mod gamemode; -pub mod give; -pub mod help; -pub mod kick; -pub mod kill; -pub mod list; -pub mod me; -pub mod msg; -pub mod op; -pub mod pardon; -pub mod pardonip; -pub mod particle; -pub mod playsound; -pub mod plugin; -pub mod plugins; -pub mod pumpkin; -pub mod say; -pub mod seed; -pub mod setblock; -pub mod stop; -pub mod summon; -pub mod teleport; -pub mod time; -pub mod title; -pub mod transfer; -pub mod weather; -pub mod worldborder; +use pumpkin_util::PermissionLvl; + +use super::dispatcher::CommandDispatcher; + +mod ban; +mod banip; +mod banlist; +mod bossbar; +mod clear; +mod damage; +mod deop; +mod effect; +mod experience; +mod fill; +mod gamemode; +mod give; +mod help; +mod kick; +mod kill; +mod list; +mod me; +mod msg; +mod op; +mod pardon; +mod pardonip; +mod particle; +mod playsound; +mod plugin; +mod plugins; +mod pumpkin; +mod say; +mod seed; +mod setblock; +mod stop; +mod summon; +mod teleport; +mod time; +mod title; +mod transfer; +mod weather; +mod worldborder; + +#[must_use] +pub fn default_dispatcher() -> CommandDispatcher { + let mut dispatcher = CommandDispatcher::default(); + + // Zero + dispatcher.register(pumpkin::init_command_tree(), PermissionLvl::Zero); + dispatcher.register(help::init_command_tree(), PermissionLvl::Zero); + dispatcher.register(list::init_command_tree(), PermissionLvl::Zero); + dispatcher.register(transfer::init_command_tree(), PermissionLvl::Zero); + dispatcher.register(me::init_command_tree(), PermissionLvl::Zero); + dispatcher.register(msg::init_command_tree(), PermissionLvl::Zero); + // Two + dispatcher.register(kill::init_command_tree(), PermissionLvl::Two); + dispatcher.register(worldborder::init_command_tree(), PermissionLvl::Two); + dispatcher.register(effect::init_command_tree(), PermissionLvl::Two); + dispatcher.register(teleport::init_command_tree(), PermissionLvl::Two); + dispatcher.register(time::init_command_tree(), PermissionLvl::Two); + dispatcher.register(give::init_command_tree(), PermissionLvl::Two); + dispatcher.register(clear::init_command_tree(), PermissionLvl::Two); + dispatcher.register(setblock::init_command_tree(), PermissionLvl::Two); + dispatcher.register(seed::init_command_tree(), PermissionLvl::Two); + dispatcher.register(fill::init_command_tree(), PermissionLvl::Two); + dispatcher.register(playsound::init_command_tree(), PermissionLvl::Two); + dispatcher.register(title::init_command_tree(), PermissionLvl::Two); + dispatcher.register(summon::init_command_tree(), PermissionLvl::Two); + dispatcher.register(experience::init_command_tree(), PermissionLvl::Two); + dispatcher.register(weather::init_command_tree(), PermissionLvl::Two); + dispatcher.register(particle::init_command_tree(), PermissionLvl::Two); + dispatcher.register(damage::init_command_tree(), PermissionLvl::Two); + dispatcher.register(bossbar::init_command_tree(), PermissionLvl::Two); + dispatcher.register(say::init_command_tree(), PermissionLvl::Two); + dispatcher.register(gamemode::init_command_tree(), PermissionLvl::Two); + // Three + dispatcher.register(op::init_command_tree(), PermissionLvl::Three); + dispatcher.register(deop::init_command_tree(), PermissionLvl::Three); + dispatcher.register(kick::init_command_tree(), PermissionLvl::Three); + dispatcher.register(plugin::init_command_tree(), PermissionLvl::Three); + dispatcher.register(plugins::init_command_tree(), PermissionLvl::Three); + dispatcher.register(ban::init_command_tree(), PermissionLvl::Three); + dispatcher.register(banip::init_command_tree(), PermissionLvl::Three); + dispatcher.register(banlist::init_command_tree(), PermissionLvl::Three); + dispatcher.register(pardon::init_command_tree(), PermissionLvl::Three); + dispatcher.register(pardonip::init_command_tree(), PermissionLvl::Three); + // Four + dispatcher.register(stop::init_command_tree(), PermissionLvl::Four); + + dispatcher +} diff --git a/pumpkin/src/command/commands/msg.rs b/pumpkin/src/command/commands/msg.rs index af235bea1..4ab14d899 100644 --- a/pumpkin/src/command/commands/msg.rs +++ b/pumpkin/src/command/commands/msg.rs @@ -1,15 +1,15 @@ use async_trait::async_trait; use pumpkin_data::world::{MSG_COMMAND_INCOMING, MSG_COMMAND_OUTGOING}; -use pumpkin_util::text::{click::ClickEvent, hover::HoverEvent, TextComponent}; +use pumpkin_util::text::{TextComponent, click::ClickEvent, hover::HoverEvent}; use crate::command::{ + CommandError, CommandExecutor, CommandSender, args::{ - message::MsgArgConsumer, players::PlayersArgumentConsumer, Arg, ConsumedArgs, - FindArgDefaultName, + Arg, ConsumedArgs, FindArgDefaultName, message::MsgArgConsumer, + players::PlayersArgumentConsumer, }, - tree::builder::{argument, argument_default_name}, tree::CommandTree, - CommandError, CommandExecutor, CommandSender, + tree::builder::{argument, argument_default_name}, }; use CommandError::InvalidConsumption; @@ -19,10 +19,10 @@ const DESCRIPTION: &str = "Sends a private message to one or more players."; const ARG_MESSAGE: &str = "message"; -struct MsgExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for MsgExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -81,6 +81,6 @@ impl CommandExecutor for MsgExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument_default_name(PlayersArgumentConsumer) - .then(argument(ARG_MESSAGE, MsgArgConsumer).execute(MsgExecutor)), + .then(argument(ARG_MESSAGE, MsgArgConsumer).execute(Executor)), ) } diff --git a/pumpkin/src/command/commands/op.rs b/pumpkin/src/command/commands/op.rs index 8fae81ba4..6b656d328 100644 --- a/pumpkin/src/command/commands/op.rs +++ b/pumpkin/src/command/commands/op.rs @@ -1,25 +1,25 @@ use crate::{ command::{ - args::{players::PlayersArgumentConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, players::PlayersArgumentConsumer}, + tree::CommandTree, + tree::builder::argument, }, - data::{op_data::OPERATOR_CONFIG, SaveJSONConfiguration}, + data::{SaveJSONConfiguration, op_data::OPERATOR_CONFIG}, }; +use CommandError::InvalidConsumption; use async_trait::async_trait; -use pumpkin_config::{op::Op, BASIC_CONFIG}; +use pumpkin_config::{BASIC_CONFIG, op::Op}; use pumpkin_util::text::TextComponent; -use CommandError::InvalidConsumption; const NAMES: [&str; 1] = ["op"]; const DESCRIPTION: &str = "Grants operator status to a player."; const ARG_TARGETS: &str = "targets"; -struct OpExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for OpExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -81,5 +81,5 @@ impl CommandExecutor for OpExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_TARGETS, PlayersArgumentConsumer).execute(OpExecutor)) + .then(argument(ARG_TARGETS, PlayersArgumentConsumer).execute(Executor)) } diff --git a/pumpkin/src/command/commands/pardon.rs b/pumpkin/src/command/commands/pardon.rs index 5fb79cb23..2d0e7c352 100644 --- a/pumpkin/src/command/commands/pardon.rs +++ b/pumpkin/src/command/commands/pardon.rs @@ -1,25 +1,25 @@ use crate::{ command::{ - args::{simple::SimpleArgConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, simple::SimpleArgConsumer}, + tree::CommandTree, + tree::builder::argument, }, - data::{banned_player_data::BANNED_PLAYER_LIST, SaveJSONConfiguration}, + data::{SaveJSONConfiguration, banned_player_data::BANNED_PLAYER_LIST}, }; +use CommandError::InvalidConsumption; use async_trait::async_trait; use pumpkin_util::text::TextComponent; -use CommandError::InvalidConsumption; const NAMES: [&str; 1] = ["pardon"]; const DESCRIPTION: &str = "unbans a player"; const ARG_TARGET: &str = "player"; -struct PardonExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for PardonExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -60,5 +60,5 @@ impl CommandExecutor for PardonExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_TARGET, SimpleArgConsumer).execute(PardonExecutor)) + .then(argument(ARG_TARGET, SimpleArgConsumer).execute(Executor)) } diff --git a/pumpkin/src/command/commands/pardonip.rs b/pumpkin/src/command/commands/pardonip.rs index 2ca2b2e71..e2ff01f6f 100644 --- a/pumpkin/src/command/commands/pardonip.rs +++ b/pumpkin/src/command/commands/pardonip.rs @@ -2,26 +2,26 @@ use std::{net::IpAddr, str::FromStr}; use crate::{ command::{ - args::{simple::SimpleArgConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, simple::SimpleArgConsumer}, + tree::CommandTree, + tree::builder::argument, }, - data::{banned_ip_data::BANNED_IP_LIST, SaveJSONConfiguration}, + data::{SaveJSONConfiguration, banned_ip_data::BANNED_IP_LIST}, }; +use CommandError::InvalidConsumption; use async_trait::async_trait; use pumpkin_util::text::TextComponent; -use CommandError::InvalidConsumption; const NAMES: [&str; 1] = ["pardon-ip"]; const DESCRIPTION: &str = "unbans a ip"; const ARG_TARGET: &str = "ip"; -struct PardonIpExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for PardonIpExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -64,5 +64,5 @@ impl CommandExecutor for PardonIpExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_TARGET, SimpleArgConsumer).execute(PardonIpExecutor)) + .then(argument(ARG_TARGET, SimpleArgConsumer).execute(Executor)) } diff --git a/pumpkin/src/command/commands/particle.rs b/pumpkin/src/command/commands/particle.rs index 934f05c45..0bd5e1903 100644 --- a/pumpkin/src/command/commands/particle.rs +++ b/pumpkin/src/command/commands/particle.rs @@ -2,12 +2,12 @@ use async_trait::async_trait; use pumpkin_util::{math::vector3::Vector3, text::TextComponent}; use crate::command::{ + CommandError, CommandExecutor, CommandSender, args::{ - bounded_num::BoundedNumArgumentConsumer, particle::ParticleArgumentConsumer, - position_3d::Position3DArgumentConsumer, ConsumedArgs, FindArg, + ConsumedArgs, FindArg, bounded_num::BoundedNumArgumentConsumer, + position_3d::Position3DArgumentConsumer, resource::particle::ParticleArgumentConsumer, }, - tree::{builder::argument, CommandTree}, - CommandError, CommandExecutor, CommandSender, + tree::{CommandTree, builder::argument}, }; const NAMES: [&str; 1] = ["particle"]; @@ -20,10 +20,10 @@ const ARG_DELTA: &str = "delta"; const ARG_SPEED: &str = "speed"; const ARG_COUNT: &str = "count"; -struct ParticleExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for ParticleExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -64,25 +64,25 @@ impl CommandExecutor for ParticleExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_NAME, ParticleArgumentConsumer) - .execute(ParticleExecutor) + .execute(Executor) .then( argument(ARG_POS, Position3DArgumentConsumer) - .execute(ParticleExecutor) + .execute(Executor) .then( argument(ARG_DELTA, Position3DArgumentConsumer) - .execute(ParticleExecutor) + .execute(Executor) .then( argument( ARG_SPEED, BoundedNumArgumentConsumer::::new().min(0.0), ) - .execute(ParticleExecutor) + .execute(Executor) .then( argument( ARG_COUNT, BoundedNumArgumentConsumer::::new().min(0), ) - .execute(ParticleExecutor), + .execute(Executor), ), ), ), diff --git a/pumpkin/src/command/commands/playsound.rs b/pumpkin/src/command/commands/playsound.rs index 6f82a393a..73a659a1b 100644 --- a/pumpkin/src/command/commands/playsound.rs +++ b/pumpkin/src/command/commands/playsound.rs @@ -1,17 +1,17 @@ use async_trait::async_trait; use pumpkin_data::sound::SoundCategory; use pumpkin_util::text::TextComponent; -use rand::{thread_rng, Rng}; +use rand::{Rng, thread_rng}; use crate::command::{ + CommandError, CommandExecutor, CommandSender, args::{ - bounded_num::BoundedNumArgumentConsumer, players::PlayersArgumentConsumer, - position_3d::Position3DArgumentConsumer, sound::SoundArgumentConsumer, - sound_category::SoundCategoryArgumentConsumer, Arg, ConsumedArgs, FindArg, + Arg, ConsumedArgs, FindArg, bounded_num::BoundedNumArgumentConsumer, + players::PlayersArgumentConsumer, position_3d::Position3DArgumentConsumer, + sound::SoundArgumentConsumer, sound_category::SoundCategoryArgumentConsumer, }, - tree::builder::argument, tree::CommandTree, - CommandError, CommandExecutor, CommandSender, + tree::builder::argument, }; /// Command: playsound [] [] [] [] [] [] @@ -57,10 +57,10 @@ fn min_volume_consumer() -> BoundedNumArgumentConsumer { .max(1.0) } -struct SoundExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for SoundExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -109,7 +109,7 @@ impl CommandExecutor for SoundExecutor { }; // Use same random seed for all targets to ensure sound synchronization - let seed = thread_rng().gen::(); + let seed = thread_rng().r#gen::(); // Track how many players actually received the sound let mut players_who_heard = 0; @@ -183,18 +183,18 @@ pub fn init_command_tree() -> CommandTree { ARG_MIN_VOLUME, min_volume_consumer(), ) - .execute(SoundExecutor), + .execute(Executor), ) - .execute(SoundExecutor), + .execute(Executor), ) - .execute(SoundExecutor), + .execute(Executor), ) - .execute(SoundExecutor), + .execute(Executor), ) - .execute(SoundExecutor), + .execute(Executor), ) - .execute(SoundExecutor), + .execute(Executor), ) - .execute(SoundExecutor), + .execute(Executor), ) } diff --git a/pumpkin/src/command/commands/plugin.rs b/pumpkin/src/command/commands/plugin.rs index eefccc1e9..359c6820d 100644 --- a/pumpkin/src/command/commands/plugin.rs +++ b/pumpkin/src/command/commands/plugin.rs @@ -1,19 +1,19 @@ use async_trait::async_trait; use pumpkin_util::{ - text::{color::NamedColor, hover::HoverEvent, TextComponent}, PermissionLvl, + text::{TextComponent, color::NamedColor, hover::HoverEvent}, }; use crate::{ + PLUGIN_MANAGER, command::{ - args::{simple::SimpleArgConsumer, Arg, ConsumedArgs}, + CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, simple::SimpleArgConsumer}, tree::{ - builder::{argument, literal, require}, CommandTree, + builder::{argument, literal, require}, }, - CommandError, CommandExecutor, CommandSender, }, - PLUGIN_MANAGER, }; use crate::command::CommandError::InvalidConsumption; diff --git a/pumpkin/src/command/commands/plugins.rs b/pumpkin/src/command/commands/plugins.rs index 2d824b21b..6025f5d1b 100644 --- a/pumpkin/src/command/commands/plugins.rs +++ b/pumpkin/src/command/commands/plugins.rs @@ -1,21 +1,21 @@ use async_trait::async_trait; -use pumpkin_util::text::{color::NamedColor, hover::HoverEvent, TextComponent}; +use pumpkin_util::text::{TextComponent, color::NamedColor, hover::HoverEvent}; use crate::{ + PLUGIN_MANAGER, command::{ - args::ConsumedArgs, tree::CommandTree, CommandError, CommandExecutor, CommandSender, + CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree, }, - PLUGIN_MANAGER, }; const NAMES: [&str; 1] = ["plugins"]; const DESCRIPTION: &str = "List all available plugins."; -struct ListExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for ListExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -63,5 +63,5 @@ impl CommandExecutor for ListExecutor { } pub fn init_command_tree() -> CommandTree { - CommandTree::new(NAMES, DESCRIPTION).execute(ListExecutor) + CommandTree::new(NAMES, DESCRIPTION).execute(Executor) } diff --git a/pumpkin/src/command/commands/pumpkin.rs b/pumpkin/src/command/commands/pumpkin.rs index f250ac7e1..a7606f5fb 100644 --- a/pumpkin/src/command/commands/pumpkin.rs +++ b/pumpkin/src/command/commands/pumpkin.rs @@ -2,28 +2,28 @@ use async_trait::async_trait; use pumpkin_protocol::CURRENT_MC_PROTOCOL; use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_util::text::{color::NamedColor, TextComponent}; +use pumpkin_util::text::{TextComponent, color::NamedColor}; use std::borrow::Cow; use crate::{ + GIT_VERSION, command::{ - args::ConsumedArgs, tree::CommandTree, CommandError, CommandExecutor, CommandSender, + CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree, }, server::CURRENT_MC_VERSION, - GIT_VERSION, }; const NAMES: [&str; 2] = ["pumpkin", "version"]; const DESCRIPTION: &str = "Display information about Pumpkin."; -struct PumpkinExecutor; +struct Executor; const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); const CARGO_PKG_DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION"); #[async_trait] -impl CommandExecutor for PumpkinExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -98,5 +98,5 @@ impl CommandExecutor for PumpkinExecutor { } pub fn init_command_tree() -> CommandTree { - CommandTree::new(NAMES, DESCRIPTION).execute(PumpkinExecutor) + CommandTree::new(NAMES, DESCRIPTION).execute(Executor) } diff --git a/pumpkin/src/command/commands/say.rs b/pumpkin/src/command/commands/say.rs index 24e2de2ee..6fb4e7a5d 100644 --- a/pumpkin/src/command/commands/say.rs +++ b/pumpkin/src/command/commands/say.rs @@ -3,10 +3,10 @@ use pumpkin_data::world::SAY_COMMAND; use pumpkin_util::text::TextComponent; use crate::command::{ - args::{message::MsgArgConsumer, Arg, ConsumedArgs}, - tree::builder::argument, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{Arg, ConsumedArgs, message::MsgArgConsumer}, + tree::CommandTree, + tree::builder::argument, }; use CommandError::InvalidConsumption; @@ -16,10 +16,10 @@ const DESCRIPTION: &str = "Broadcast a message to all Players."; const ARG_MESSAGE: &str = "message"; -struct SayExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for SayExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -44,5 +44,5 @@ impl CommandExecutor for SayExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_MESSAGE, MsgArgConsumer).execute(SayExecutor)) + .then(argument(ARG_MESSAGE, MsgArgConsumer).execute(Executor)) } diff --git a/pumpkin/src/command/commands/seed.rs b/pumpkin/src/command/commands/seed.rs index 15ae52761..0f6a167f8 100644 --- a/pumpkin/src/command/commands/seed.rs +++ b/pumpkin/src/command/commands/seed.rs @@ -1,20 +1,20 @@ use crate::command::{ - args::ConsumedArgs, tree::CommandTree, CommandError, CommandExecutor, CommandSender, + CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree, }; use async_trait::async_trait; use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_util::text::{color::NamedColor, TextComponent}; +use pumpkin_util::text::{TextComponent, color::NamedColor}; use std::borrow::Cow; const NAMES: [&str; 1] = ["seed"]; const DESCRIPTION: &str = "Displays the world seed."; -struct PumpkinExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for PumpkinExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -31,7 +31,7 @@ impl CommandExecutor for PumpkinExecutor { None => { return Err(CommandError::GeneralCommandIssue( "Unable to get Seed".to_string(), - )) + )); } }, }; @@ -54,5 +54,5 @@ impl CommandExecutor for PumpkinExecutor { } pub fn init_command_tree() -> CommandTree { - CommandTree::new(NAMES, DESCRIPTION).execute(PumpkinExecutor) + CommandTree::new(NAMES, DESCRIPTION).execute(Executor) } diff --git a/pumpkin/src/command/commands/setblock.rs b/pumpkin/src/command/commands/setblock.rs index 20f218734..f1474d1cc 100644 --- a/pumpkin/src/command/commands/setblock.rs +++ b/pumpkin/src/command/commands/setblock.rs @@ -4,8 +4,8 @@ use pumpkin_util::text::TextComponent; use crate::command::args::block::BlockArgumentConsumer; use crate::command::args::position_block::BlockPosArgumentConsumer; use crate::command::args::{ConsumedArgs, FindArg}; -use crate::command::tree::builder::{argument, literal}; use crate::command::tree::CommandTree; +use crate::command::tree::builder::{argument, literal}; use crate::command::{CommandError, CommandExecutor, CommandSender}; const NAMES: [&str; 1] = ["setblock"]; @@ -27,10 +27,10 @@ enum Mode { Replace, } -struct SetblockExecutor(Mode); +struct Executor(Mode); #[async_trait] -impl CommandExecutor for SetblockExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -90,10 +90,10 @@ pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_BLOCK_POS, BlockPosArgumentConsumer).then( argument(ARG_BLOCK, BlockArgumentConsumer) - .then(literal("replace").execute(SetblockExecutor(Mode::Replace))) - .then(literal("destroy").execute(SetblockExecutor(Mode::Destroy))) - .then(literal("keep").execute(SetblockExecutor(Mode::Keep))) - .execute(SetblockExecutor(Mode::Replace)), + .then(literal("replace").execute(Executor(Mode::Replace))) + .then(literal("destroy").execute(Executor(Mode::Destroy))) + .then(literal("keep").execute(Executor(Mode::Keep))) + .execute(Executor(Mode::Replace)), ), ) } diff --git a/pumpkin/src/command/commands/stop.rs b/pumpkin/src/command/commands/stop.rs index c8891b1e1..1b8f6df83 100644 --- a/pumpkin/src/command/commands/stop.rs +++ b/pumpkin/src/command/commands/stop.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; -use pumpkin_util::text::color::NamedColor; use pumpkin_util::text::TextComponent; +use pumpkin_util::text::color::NamedColor; use crate::command::args::ConsumedArgs; use crate::command::tree::CommandTree; @@ -11,10 +11,10 @@ const NAMES: [&str; 1] = ["stop"]; const DESCRIPTION: &str = "Stop the server."; -struct StopExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for StopExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -32,5 +32,5 @@ impl CommandExecutor for StopExecutor { } pub fn init_command_tree() -> CommandTree { - CommandTree::new(NAMES, DESCRIPTION).execute(StopExecutor) + CommandTree::new(NAMES, DESCRIPTION).execute(Executor) } diff --git a/pumpkin/src/command/commands/summon.rs b/pumpkin/src/command/commands/summon.rs index c6f5ca815..ebd99ca65 100644 --- a/pumpkin/src/command/commands/summon.rs +++ b/pumpkin/src/command/commands/summon.rs @@ -3,13 +3,13 @@ use pumpkin_util::text::TextComponent; use crate::{ command::{ + CommandError, CommandExecutor, CommandSender, args::{ - position_3d::Position3DArgumentConsumer, - summonable_entities::SummonableEntitiesArgumentConsumer, ConsumedArgs, FindArg, + ConsumedArgs, FindArg, position_3d::Position3DArgumentConsumer, + summonable_entities::SummonableEntitiesArgumentConsumer, }, - tree::builder::argument, tree::CommandTree, - CommandError, CommandExecutor, CommandSender, + tree::builder::argument, }, entity::mob, }; @@ -21,10 +21,10 @@ const ARG_ENTITY: &str = "entity"; const ARG_POS: &str = "pos"; -struct SummonExecutor; +struct Executor; #[async_trait] -impl CommandExecutor for SummonExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -54,8 +54,8 @@ impl CommandExecutor for SummonExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_ENTITY, SummonableEntitiesArgumentConsumer) - .execute(SummonExecutor) - .then(argument(ARG_POS, Position3DArgumentConsumer).execute(SummonExecutor)), + .execute(Executor) + .then(argument(ARG_POS, Position3DArgumentConsumer).execute(Executor)), // TODO: Add NBT ) } diff --git a/pumpkin/src/command/commands/teleport.rs b/pumpkin/src/command/commands/teleport.rs index c2e53fdae..7d7048420 100644 --- a/pumpkin/src/command/commands/teleport.rs +++ b/pumpkin/src/command/commands/teleport.rs @@ -2,15 +2,15 @@ use async_trait::async_trait; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; +use crate::command::CommandError; +use crate::command::args::ConsumedArgs; +use crate::command::args::FindArg; use crate::command::args::entities::EntitiesArgumentConsumer; use crate::command::args::entity::EntityArgumentConsumer; use crate::command::args::position_3d::Position3DArgumentConsumer; use crate::command::args::rotation::RotationArgumentConsumer; -use crate::command::args::ConsumedArgs; -use crate::command::args::FindArg; -use crate::command::tree::builder::{argument, literal}; use crate::command::tree::CommandTree; -use crate::command::CommandError; +use crate::command::tree::builder::{argument, literal}; use crate::command::{CommandExecutor, CommandSender}; const NAMES: [&str; 2] = ["teleport", "tp"]; @@ -49,10 +49,10 @@ fn yaw_pitch_facing_position( (yaw_degrees as f32, pitch_degrees as f32) } -struct TpEntitiesToEntityExecutor; +struct EntitiesToEntityExecutor; #[async_trait] -impl CommandExecutor for TpEntitiesToEntityExecutor { +impl CommandExecutor for EntitiesToEntityExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, @@ -74,10 +74,10 @@ impl CommandExecutor for TpEntitiesToEntityExecutor { } } -struct TpEntitiesToPosFacingPosExecutor; +struct EntitiesToPosFacingPosExecutor; #[async_trait] -impl CommandExecutor for TpEntitiesToPosFacingPosExecutor { +impl CommandExecutor for EntitiesToPosFacingPosExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, @@ -99,10 +99,10 @@ impl CommandExecutor for TpEntitiesToPosFacingPosExecutor { } } -struct TpEntitiesToPosFacingEntityExecutor; +struct EntitiesToPosFacingEntityExecutor; #[async_trait] -impl CommandExecutor for TpEntitiesToPosFacingEntityExecutor { +impl CommandExecutor for EntitiesToPosFacingEntityExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, @@ -126,10 +126,10 @@ impl CommandExecutor for TpEntitiesToPosFacingEntityExecutor { } } -struct TpEntitiesToPosWithRotationExecutor; +struct EntitiesToPosWithRotationExecutor; #[async_trait] -impl CommandExecutor for TpEntitiesToPosWithRotationExecutor { +impl CommandExecutor for EntitiesToPosWithRotationExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, @@ -150,10 +150,10 @@ impl CommandExecutor for TpEntitiesToPosWithRotationExecutor { } } -struct TpEntitiesToPosExecutor; +struct EntitiesToPosExecutor; #[async_trait] -impl CommandExecutor for TpEntitiesToPosExecutor { +impl CommandExecutor for EntitiesToPosExecutor { async fn execute<'a>( &self, _sender: &mut CommandSender<'a>, @@ -174,10 +174,10 @@ impl CommandExecutor for TpEntitiesToPosExecutor { } } -struct TpSelfToEntityExecutor; +struct SelfToEntityExecutor; #[async_trait] -impl CommandExecutor for TpSelfToEntityExecutor { +impl CommandExecutor for SelfToEntityExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -204,10 +204,10 @@ impl CommandExecutor for TpSelfToEntityExecutor { } } -struct TpSelfToPosExecutor; +struct SelfToPosExecutor; #[async_trait] -impl CommandExecutor for TpSelfToPosExecutor { +impl CommandExecutor for SelfToPosExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -234,34 +234,34 @@ impl CommandExecutor for TpSelfToPosExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) - .then(argument(ARG_LOCATION, Position3DArgumentConsumer).execute(TpSelfToPosExecutor)) - .then(argument(ARG_DESTINATION, EntityArgumentConsumer).execute(TpSelfToEntityExecutor)) + .then(argument(ARG_LOCATION, Position3DArgumentConsumer).execute(SelfToPosExecutor)) + .then(argument(ARG_DESTINATION, EntityArgumentConsumer).execute(SelfToEntityExecutor)) .then( argument(ARG_TARGETS, EntitiesArgumentConsumer) .then( argument(ARG_LOCATION, Position3DArgumentConsumer) - .execute(TpEntitiesToPosExecutor) + .execute(EntitiesToPosExecutor) .then( argument(ARG_ROTATION, RotationArgumentConsumer) - .execute(TpEntitiesToPosWithRotationExecutor), + .execute(EntitiesToPosWithRotationExecutor), ) .then( literal("facing") .then( literal("entity").then( argument(ARG_FACING_ENTITY, EntityArgumentConsumer) - .execute(TpEntitiesToPosFacingEntityExecutor), + .execute(EntitiesToPosFacingEntityExecutor), ), ) .then( argument(ARG_FACING_LOCATION, Position3DArgumentConsumer) - .execute(TpEntitiesToPosFacingPosExecutor), + .execute(EntitiesToPosFacingPosExecutor), ), ), ) .then( argument(ARG_DESTINATION, EntityArgumentConsumer) - .execute(TpEntitiesToEntityExecutor), + .execute(EntitiesToEntityExecutor), ), ) } diff --git a/pumpkin/src/command/commands/time.rs b/pumpkin/src/command/commands/time.rs index e2e5b8658..7f2c2b3a6 100644 --- a/pumpkin/src/command/commands/time.rs +++ b/pumpkin/src/command/commands/time.rs @@ -1,11 +1,11 @@ use async_trait::async_trait; -use pumpkin_util::text::color::{Color, NamedColor}; use pumpkin_util::text::TextComponent; +use pumpkin_util::text::color::{Color, NamedColor}; -use crate::command::args::{time::TimeArgumentConsumer, FindArg}; +use crate::command::args::{FindArg, time::TimeArgumentConsumer}; use crate::command::tree::builder::{argument, literal}; use crate::command::{ - tree::CommandTree, CommandError, CommandExecutor, CommandSender, ConsumedArgs, + CommandError, CommandExecutor, CommandSender, ConsumedArgs, tree::CommandTree, }; const NAMES: [&str; 1] = ["time"]; @@ -44,10 +44,10 @@ enum QueryMode { Day, } -struct TimeQueryExecutor(QueryMode); +struct QueryExecutor(QueryMode); #[async_trait] -impl CommandExecutor for TimeQueryExecutor { +impl CommandExecutor for QueryExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -91,10 +91,10 @@ impl CommandExecutor for TimeQueryExecutor { } } -struct TimeChangeExecutor(Mode); +struct ChangeExecutor(Mode); #[async_trait] -impl CommandExecutor for TimeChangeExecutor { +impl CommandExecutor for ChangeExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -153,33 +153,27 @@ impl CommandExecutor for TimeChangeExecutor { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION) .then( - literal("add").then( - argument(ARG_TIME, TimeArgumentConsumer).execute(TimeChangeExecutor(Mode::Add)), - ), + literal("add") + .then(argument(ARG_TIME, TimeArgumentConsumer).execute(ChangeExecutor(Mode::Add))), ) .then( literal("query") - .then(literal("daytime").execute(TimeQueryExecutor(QueryMode::DayTime))) - .then(literal("gametime").execute(TimeQueryExecutor(QueryMode::GameTime))) - .then(literal("day").execute(TimeQueryExecutor(QueryMode::Day))), + .then(literal("daytime").execute(QueryExecutor(QueryMode::DayTime))) + .then(literal("gametime").execute(QueryExecutor(QueryMode::GameTime))) + .then(literal("day").execute(QueryExecutor(QueryMode::Day))), ) .then( literal("set") - .then(literal("day").execute(TimeChangeExecutor(Mode::Set(Some(PresetTime::Day))))) - .then( - literal("noon").execute(TimeChangeExecutor(Mode::Set(Some(PresetTime::Noon)))), - ) - .then( - literal("night") - .execute(TimeChangeExecutor(Mode::Set(Some(PresetTime::Night)))), - ) + .then(literal("day").execute(ChangeExecutor(Mode::Set(Some(PresetTime::Day))))) + .then(literal("noon").execute(ChangeExecutor(Mode::Set(Some(PresetTime::Noon))))) + .then(literal("night").execute(ChangeExecutor(Mode::Set(Some(PresetTime::Night))))) .then( literal("midnight") - .execute(TimeChangeExecutor(Mode::Set(Some(PresetTime::Midnight)))), + .execute(ChangeExecutor(Mode::Set(Some(PresetTime::Midnight)))), ) .then( argument(ARG_TIME, TimeArgumentConsumer) - .execute(TimeChangeExecutor(Mode::Set(None))), + .execute(ChangeExecutor(Mode::Set(None))), ), ) } diff --git a/pumpkin/src/command/commands/title.rs b/pumpkin/src/command/commands/title.rs index 751410842..f845c4f83 100644 --- a/pumpkin/src/command/commands/title.rs +++ b/pumpkin/src/command/commands/title.rs @@ -4,13 +4,13 @@ use pumpkin_util::text::TextComponent; use crate::{ command::{ + CommandError, CommandExecutor, CommandSender, args::{ - players::PlayersArgumentConsumer, textcomponent::TextComponentArgConsumer, Arg, - ConsumedArgs, FindArg, + Arg, ConsumedArgs, FindArg, players::PlayersArgumentConsumer, + textcomponent::TextComponentArgConsumer, }, - tree::builder::{argument, literal}, tree::CommandTree, - CommandError, CommandExecutor, CommandSender, + tree::builder::{argument, literal}, }, entity::player::TitleMode, }; diff --git a/pumpkin/src/command/commands/transfer.rs b/pumpkin/src/command/commands/transfer.rs index e456c9d74..1d78a671f 100644 --- a/pumpkin/src/command/commands/transfer.rs +++ b/pumpkin/src/command/commands/transfer.rs @@ -1,8 +1,8 @@ use async_trait::async_trait; use pumpkin_protocol::client::play::CTransfer; use pumpkin_protocol::codec::var_int::VarInt; -use pumpkin_util::text::color::{Color, NamedColor}; use pumpkin_util::text::TextComponent; +use pumpkin_util::text::color::{Color, NamedColor}; use crate::command::args::bounded_num::BoundedNumArgumentConsumer; use crate::command::args::players::PlayersArgumentConsumer; @@ -11,7 +11,7 @@ use crate::command::args::{Arg, FindArgDefaultName}; use crate::command::dispatcher::CommandError::{InvalidConsumption, InvalidRequirement}; use crate::command::tree::builder::{argument, argument_default_name, require}; use crate::command::{ - args::ConsumedArgs, tree::CommandTree, CommandError, CommandExecutor, CommandSender, + CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree, }; const NAMES: [&str; 1] = ["transfer"]; @@ -29,10 +29,10 @@ fn port_consumer() -> BoundedNumArgumentConsumer { .max(65535) } -struct TransferTargetSelf; +struct TargetSelfExecutor; #[async_trait] -impl CommandExecutor for TransferTargetSelf { +impl CommandExecutor for TargetSelfExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -62,7 +62,7 @@ impl CommandExecutor for TransferTargetSelf { log::info!("[{name}: Transferring {name} to {hostname}:{port}]"); player .client - .send_packet(&CTransfer::new(hostname, &VarInt(port))) + .send_packet(&CTransfer::new(hostname, VarInt(port))) .await; Ok(()) } else { @@ -71,10 +71,10 @@ impl CommandExecutor for TransferTargetSelf { } } -struct TransferTargetPlayer; +struct TargetPlayerExecutor; #[async_trait] -impl CommandExecutor for TransferTargetPlayer { +impl CommandExecutor for TargetPlayerExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -105,7 +105,7 @@ impl CommandExecutor for TransferTargetPlayer { for p in players { p.client - .send_packet(&CTransfer::new(hostname, &VarInt(port))) + .send_packet(&CTransfer::new(hostname, VarInt(port))) .await; log::info!( "[{sender}: Transferring {} to {hostname}:{port}]", @@ -121,13 +121,13 @@ impl CommandExecutor for TransferTargetPlayer { pub fn init_command_tree() -> CommandTree { CommandTree::new(NAMES, DESCRIPTION).then( argument(ARG_HOSTNAME, SimpleArgConsumer) - .then(require(|sender| sender.is_player()).execute(TransferTargetSelf)) + .then(require(|sender| sender.is_player()).execute(TargetSelfExecutor)) .then( argument_default_name(port_consumer()) - .then(require(|sender| sender.is_player()).execute(TransferTargetSelf)) + .then(require(|sender| sender.is_player()).execute(TargetSelfExecutor)) .then( argument(ARG_PLAYERS, PlayersArgumentConsumer) - .execute(TransferTargetPlayer), + .execute(TargetPlayerExecutor), ), ), ) diff --git a/pumpkin/src/command/commands/weather.rs b/pumpkin/src/command/commands/weather.rs index e66241852..841f0beaf 100644 --- a/pumpkin/src/command/commands/weather.rs +++ b/pumpkin/src/command/commands/weather.rs @@ -2,17 +2,17 @@ use async_trait::async_trait; use pumpkin_util::text::TextComponent; use crate::command::{ - args::{time::TimeArgumentConsumer, ConsumedArgs, FindArg}, - tree::builder::{argument, literal}, - tree::CommandTree, CommandError, CommandExecutor, CommandSender, + args::{ConsumedArgs, FindArg, time::TimeArgumentConsumer}, + tree::CommandTree, + tree::builder::{argument, literal}, }; const NAMES: [&str; 1] = ["weather"]; const DESCRIPTION: &str = "Changes the weather."; const ARG_DURATION: &str = "duration"; -struct WeatherExecutor { +struct Executor { mode: WeatherMode, } @@ -23,7 +23,7 @@ enum WeatherMode { } #[async_trait] -impl CommandExecutor for WeatherExecutor { +impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -73,33 +73,33 @@ pub fn init_command_tree() -> CommandTree { .then( literal("clear") .then( - argument(ARG_DURATION, TimeArgumentConsumer).execute(WeatherExecutor { + argument(ARG_DURATION, TimeArgumentConsumer).execute(Executor { mode: WeatherMode::Clear, }), ) - .execute(WeatherExecutor { + .execute(Executor { mode: WeatherMode::Clear, }), ) .then( literal("rain") .then( - argument(ARG_DURATION, TimeArgumentConsumer).execute(WeatherExecutor { + argument(ARG_DURATION, TimeArgumentConsumer).execute(Executor { mode: WeatherMode::Rain, }), ) - .execute(WeatherExecutor { + .execute(Executor { mode: WeatherMode::Rain, }), ) .then( literal("thunder") .then( - argument(ARG_DURATION, TimeArgumentConsumer).execute(WeatherExecutor { + argument(ARG_DURATION, TimeArgumentConsumer).execute(Executor { mode: WeatherMode::Thunder, }), ) - .execute(WeatherExecutor { + .execute(Executor { mode: WeatherMode::Thunder, }), ) diff --git a/pumpkin/src/command/commands/worldborder.rs b/pumpkin/src/command/commands/worldborder.rs index 9f454c67a..13435fffd 100644 --- a/pumpkin/src/command/commands/worldborder.rs +++ b/pumpkin/src/command/commands/worldborder.rs @@ -2,20 +2,20 @@ use async_trait::async_trait; use pumpkin_util::{ math::vector2::Vector2, text::{ - color::{Color, NamedColor}, TextComponent, + color::{Color, NamedColor}, }, }; use crate::{ command::{ + CommandError, CommandExecutor, CommandSender, args::{ - bounded_num::BoundedNumArgumentConsumer, position_2d::Position2DArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArgDefaultName, + bounded_num::BoundedNumArgumentConsumer, position_2d::Position2DArgumentConsumer, }, - tree::builder::{argument_default_name, literal}, tree::CommandTree, - CommandError, CommandExecutor, CommandSender, + tree::builder::{argument_default_name, literal}, }, server::Server, }; @@ -48,10 +48,10 @@ fn warning_distance_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0).name("distance") } -struct WorldborderGetExecutor; +struct GetExecutor; #[async_trait] -impl CommandExecutor for WorldborderGetExecutor { +impl CommandExecutor for GetExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -76,10 +76,10 @@ impl CommandExecutor for WorldborderGetExecutor { } } -struct WorldborderSetExecutor; +struct SetExecutor; #[async_trait] -impl CommandExecutor for WorldborderSetExecutor { +impl CommandExecutor for SetExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -128,10 +128,10 @@ impl CommandExecutor for WorldborderSetExecutor { } } -struct WorldborderSetTimeExecutor; +struct SetTimeExecutor; #[async_trait] -impl CommandExecutor for WorldborderSetTimeExecutor { +impl CommandExecutor for SetTimeExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -213,10 +213,10 @@ impl CommandExecutor for WorldborderSetTimeExecutor { } } -struct WorldborderAddExecutor; +struct AddExecutor; #[async_trait] -impl CommandExecutor for WorldborderAddExecutor { +impl CommandExecutor for AddExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -267,10 +267,10 @@ impl CommandExecutor for WorldborderAddExecutor { } } -struct WorldborderAddTimeExecutor; +struct AddTimeExecutor; #[async_trait] -impl CommandExecutor for WorldborderAddTimeExecutor { +impl CommandExecutor for AddTimeExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -354,10 +354,10 @@ impl CommandExecutor for WorldborderAddTimeExecutor { } } -struct WorldborderCenterExecutor; +struct CenterExecutor; #[async_trait] -impl CommandExecutor for WorldborderCenterExecutor { +impl CommandExecutor for CenterExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -387,10 +387,10 @@ impl CommandExecutor for WorldborderCenterExecutor { } } -struct WorldborderDamageAmountExecutor; +struct DamageAmountExecutor; #[async_trait] -impl CommandExecutor for WorldborderDamageAmountExecutor { +impl CommandExecutor for DamageAmountExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -439,10 +439,10 @@ impl CommandExecutor for WorldborderDamageAmountExecutor { } } -struct WorldborderDamageBufferExecutor; +struct DamageBufferExecutor; #[async_trait] -impl CommandExecutor for WorldborderDamageBufferExecutor { +impl CommandExecutor for DamageBufferExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -491,10 +491,10 @@ impl CommandExecutor for WorldborderDamageBufferExecutor { } } -struct WorldborderWarningDistanceExecutor; +struct WarningDistanceExecutor; #[async_trait] -impl CommandExecutor for WorldborderWarningDistanceExecutor { +impl CommandExecutor for WarningDistanceExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -542,10 +542,10 @@ impl CommandExecutor for WorldborderWarningDistanceExecutor { } } -struct WorldborderWarningTimeExecutor; +struct WarningTimeExecutor; #[async_trait] -impl CommandExecutor for WorldborderWarningTimeExecutor { +impl CommandExecutor for WarningTimeExecutor { async fn execute<'a>( &self, sender: &mut CommandSender<'a>, @@ -598,38 +598,32 @@ pub fn init_command_tree() -> CommandTree { .then( literal("add").then( argument_default_name(distance_consumer()) - .execute(WorldborderAddExecutor) - .then( - argument_default_name(time_consumer()).execute(WorldborderAddTimeExecutor), - ), + .execute(AddExecutor) + .then(argument_default_name(time_consumer()).execute(AddTimeExecutor)), ), ) - .then(literal("center").then( - argument_default_name(Position2DArgumentConsumer).execute(WorldborderCenterExecutor), - )) + .then( + literal("center") + .then(argument_default_name(Position2DArgumentConsumer).execute(CenterExecutor)), + ) .then( literal("damage") .then( literal("amount").then( argument_default_name(damage_per_block_consumer()) - .execute(WorldborderDamageAmountExecutor), + .execute(DamageAmountExecutor), ), ) - .then( - literal("buffer").then( - argument_default_name(damage_buffer_consumer()) - .execute(WorldborderDamageBufferExecutor), - ), - ), + .then(literal("buffer").then( + argument_default_name(damage_buffer_consumer()).execute(DamageBufferExecutor), + )), ) - .then(literal("get").execute(WorldborderGetExecutor)) + .then(literal("get").execute(GetExecutor)) .then( literal("set").then( argument_default_name(distance_consumer()) - .execute(WorldborderSetExecutor) - .then( - argument_default_name(time_consumer()).execute(WorldborderSetTimeExecutor), - ), + .execute(SetExecutor) + .then(argument_default_name(time_consumer()).execute(SetTimeExecutor)), ), ) .then( @@ -637,11 +631,12 @@ pub fn init_command_tree() -> CommandTree { .then( literal("distance").then( argument_default_name(warning_distance_consumer()) - .execute(WorldborderWarningDistanceExecutor), + .execute(WarningDistanceExecutor), ), ) - .then(literal("time").then( - argument_default_name(time_consumer()).execute(WorldborderWarningTimeExecutor), - )), + .then( + literal("time") + .then(argument_default_name(time_consumer()).execute(WarningTimeExecutor)), + ), ) } diff --git a/pumpkin/src/command/dispatcher.rs b/pumpkin/src/command/dispatcher.rs index e89522523..5359d2c5e 100644 --- a/pumpkin/src/command/dispatcher.rs +++ b/pumpkin/src/command/dispatcher.rs @@ -4,11 +4,11 @@ use pumpkin_util::text::TextComponent; use super::args::ConsumedArgs; +use crate::command::CommandSender; use crate::command::dispatcher::CommandError::{ GeneralCommandIssue, InvalidConsumption, InvalidRequirement, OtherPumpkin, PermissionDenied, }; use crate::command::tree::{Command, CommandTree, NodeType, RawArgs}; -use crate::command::CommandSender; use crate::error::PumpkinError; use crate::server::Server; use pumpkin_util::text::color::{Color, NamedColor}; @@ -35,11 +35,15 @@ impl CommandError { pub fn into_string_or_pumpkin_error(self, cmd: &str) -> Result> { match self { InvalidConsumption(s) => { - log::error!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed"); + log::error!( + "Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed" + ); Ok("Internal Error (See logs for details)".into()) } InvalidRequirement => { - log::error!("Error while parsing command \"{cmd}\": a requirement that was expected was not met."); + log::error!( + "Error while parsing command \"{cmd}\": a requirement that was expected was not met." + ); Ok("Internal Error (See logs for details)".into()) } PermissionDenied => { @@ -114,11 +118,15 @@ impl CommandDispatcher { .await { Err(InvalidConsumption(s)) => { - log::error!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed"); + log::error!( + "Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed" + ); return Vec::new(); } Err(InvalidRequirement) => { - log::error!("Error while parsing command \"{cmd}\": a requirement that was expected was not met."); + log::error!( + "Error while parsing command \"{cmd}\": a requirement that was expected was not met." + ); return Vec::new(); } Err(PermissionDenied) => { @@ -196,7 +204,9 @@ impl CommandDispatcher { Command::Tree(tree) => Ok(tree), Command::Alias(target) => { let Some(Command::Tree(tree)) = self.commands.get(target) else { - log::error!("Error while parsing command alias \"{key}\": pointing to \"{target}\" which is not a valid tree"); + log::error!( + "Error while parsing command alias \"{key}\": pointing to \"{target}\" which is not a valid tree" + ); return Err(GeneralCommandIssue( "Internal Error (See logs for details)".into(), )); @@ -339,7 +349,7 @@ impl CommandDispatcher { #[cfg(test)] mod test { - use crate::command::{default_dispatcher, tree::CommandTree}; + use crate::command::{commands::default_dispatcher, tree::CommandTree}; use pumpkin_util::permission::PermissionLvl; #[test] fn test_dynamic_command() { diff --git a/pumpkin/src/command/mod.rs b/pumpkin/src/command/mod.rs index d39f722d5..d960d292f 100644 --- a/pumpkin/src/command/mod.rs +++ b/pumpkin/src/command/mod.rs @@ -1,19 +1,12 @@ use std::fmt; use std::sync::Arc; -use crate::command::commands::seed; -use crate::command::commands::{bossbar, transfer}; -use crate::command::dispatcher::CommandDispatcher; use crate::entity::player::Player; use crate::server::Server; use crate::world::World; use args::ConsumedArgs; use async_trait::async_trait; -use commands::{ - ban, banip, banlist, clear, damage, deop, experience, fill, gamemode, give, help, kick, kill, - list, me, msg, op, pardon, pardonip, particle, playsound, plugin, plugins, pumpkin, say, - setblock, stop, summon, teleport, time, title, weather, worldborder, -}; + use dispatcher::CommandError; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::permission::PermissionLvl; @@ -21,7 +14,7 @@ use pumpkin_util::text::TextComponent; pub mod args; pub mod client_suggestions; -mod commands; +pub mod commands; pub mod dispatcher; pub mod tree; @@ -106,54 +99,6 @@ impl CommandSender<'_> { } } -#[must_use] -pub fn default_dispatcher() -> CommandDispatcher { - let mut dispatcher = CommandDispatcher::default(); - - // Zero - dispatcher.register(pumpkin::init_command_tree(), PermissionLvl::Zero); - dispatcher.register(help::init_command_tree(), PermissionLvl::Zero); - dispatcher.register(list::init_command_tree(), PermissionLvl::Zero); - dispatcher.register(transfer::init_command_tree(), PermissionLvl::Zero); - dispatcher.register(me::init_command_tree(), PermissionLvl::Zero); - dispatcher.register(msg::init_command_tree(), PermissionLvl::Zero); - // Two - dispatcher.register(kill::init_command_tree(), PermissionLvl::Two); - dispatcher.register(worldborder::init_command_tree(), PermissionLvl::Two); - dispatcher.register(teleport::init_command_tree(), PermissionLvl::Two); - dispatcher.register(time::init_command_tree(), PermissionLvl::Two); - dispatcher.register(give::init_command_tree(), PermissionLvl::Two); - dispatcher.register(clear::init_command_tree(), PermissionLvl::Two); - dispatcher.register(setblock::init_command_tree(), PermissionLvl::Two); - dispatcher.register(seed::init_command_tree(), PermissionLvl::Two); - dispatcher.register(fill::init_command_tree(), PermissionLvl::Two); - dispatcher.register(playsound::init_command_tree(), PermissionLvl::Two); - dispatcher.register(title::init_command_tree(), PermissionLvl::Two); - dispatcher.register(summon::init_command_tree(), PermissionLvl::Two); - dispatcher.register(experience::init_command_tree(), PermissionLvl::Two); - dispatcher.register(weather::init_command_tree(), PermissionLvl::Two); - dispatcher.register(particle::init_command_tree(), PermissionLvl::Two); - dispatcher.register(damage::init_command_tree(), PermissionLvl::Two); - dispatcher.register(bossbar::init_command_tree(), PermissionLvl::Two); - dispatcher.register(say::init_command_tree(), PermissionLvl::Two); - dispatcher.register(gamemode::init_command_tree(), PermissionLvl::Two); - // Three - dispatcher.register(op::init_command_tree(), PermissionLvl::Three); - dispatcher.register(deop::init_command_tree(), PermissionLvl::Three); - dispatcher.register(kick::init_command_tree(), PermissionLvl::Three); - dispatcher.register(plugin::init_command_tree(), PermissionLvl::Three); - dispatcher.register(plugins::init_command_tree(), PermissionLvl::Three); - dispatcher.register(ban::init_command_tree(), PermissionLvl::Three); - dispatcher.register(banip::init_command_tree(), PermissionLvl::Three); - dispatcher.register(banlist::init_command_tree(), PermissionLvl::Three); - dispatcher.register(pardon::init_command_tree(), PermissionLvl::Three); - dispatcher.register(pardonip::init_command_tree(), PermissionLvl::Three); - // Four - dispatcher.register(stop::init_command_tree(), PermissionLvl::Four); - - dispatcher -} - #[async_trait] pub trait CommandExecutor: Sync { async fn execute<'a>( diff --git a/pumpkin/src/command/tree/builder.rs b/pumpkin/src/command/tree/builder.rs index fe4149734..4682d60fe 100644 --- a/pumpkin/src/command/tree/builder.rs +++ b/pumpkin/src/command/tree/builder.rs @@ -1,9 +1,9 @@ use std::sync::Arc; use super::CommandExecutor; +use crate::command::CommandSender; use crate::command::args::{ArgumentConsumer, DefaultNameArgConsumer}; use crate::command::tree::{CommandTree, Node, NodeType}; -use crate::command::CommandSender; impl CommandTree { /// Add a child [Node] to the root of this [`CommandTree`]. diff --git a/pumpkin/src/command/tree/mod.rs b/pumpkin/src/command/tree/mod.rs index e56811f47..4c47f66cb 100644 --- a/pumpkin/src/command/tree/mod.rs +++ b/pumpkin/src/command/tree/mod.rs @@ -1,4 +1,4 @@ -use super::{args::ArgumentConsumer, CommandExecutor}; +use super::{CommandExecutor, args::ArgumentConsumer}; use crate::command::CommandSender; use std::{collections::VecDeque, fmt::Debug, sync::Arc}; diff --git a/pumpkin/src/data/banned_ip_data.rs b/pumpkin/src/data/banned_ip_data.rs index f524530cc..4e7c9acd6 100644 --- a/pumpkin/src/data/banned_ip_data.rs +++ b/pumpkin/src/data/banned_ip_data.rs @@ -3,7 +3,7 @@ use std::{net::IpAddr, path::Path, sync::LazyLock}; use chrono::Local; use serde::{Deserialize, Serialize}; -use super::{banlist_serializer::BannedIpEntry, LoadJSONConfiguration, SaveJSONConfiguration}; +use super::{LoadJSONConfiguration, SaveJSONConfiguration, banlist_serializer::BannedIpEntry}; pub static BANNED_IP_LIST: LazyLock> = LazyLock::new(|| tokio::sync::RwLock::new(BannedIpList::load())); diff --git a/pumpkin/src/data/banned_player_data.rs b/pumpkin/src/data/banned_player_data.rs index ceb62cab5..b847ade58 100644 --- a/pumpkin/src/data/banned_player_data.rs +++ b/pumpkin/src/data/banned_player_data.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::net::GameProfile; -use super::{banlist_serializer::BannedPlayerEntry, LoadJSONConfiguration, SaveJSONConfiguration}; +use super::{LoadJSONConfiguration, SaveJSONConfiguration, banlist_serializer::BannedPlayerEntry}; pub static BANNED_PLAYER_LIST: LazyLock> = LazyLock::new(|| tokio::sync::RwLock::new(BannedPlayerList::load())); diff --git a/pumpkin/src/data/mod.rs b/pumpkin/src/data/mod.rs index f8093426c..2a0f20c6c 100644 --- a/pumpkin/src/data/mod.rs +++ b/pumpkin/src/data/mod.rs @@ -38,7 +38,7 @@ pub trait LoadJSONConfiguration { if let Err(err) = fs::write(&path, serde_json::to_string_pretty(&content).unwrap()) { log::error!( - "Couldn't write default data config to {path:?}. Reason: {err}. This is probably caused by a config update. Just delete the old data config and restart.", + "Couldn't write default data config to {path:?}. Reason: {err}. This is probably caused by a config update. Just delete the old data config and restart.", ); } diff --git a/pumpkin/src/entity/combat.rs b/pumpkin/src/entity/combat.rs index a11401124..7f566b6c5 100644 --- a/pumpkin/src/entity/combat.rs +++ b/pumpkin/src/entity/combat.rs @@ -7,7 +7,7 @@ use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use crate::{ - entity::{player::Player, Entity}, + entity::{Entity, player::Player}, world::World, }; @@ -50,11 +50,7 @@ impl AttackType { return Self::Sweeping; } - if is_strong { - Self::Strong - } else { - Self::Weak - } + if is_strong { Self::Strong } else { Self::Weak } } } @@ -71,12 +67,7 @@ pub async fn handle_knockback(attacker: &Entity, world: &World, victim: &Entity, let entity_id = VarInt(victim.entity_id); let victim_velocity = victim.velocity.load(); - let packet = &CEntityVelocity::new( - &entity_id, - victim_velocity.x, - victim_velocity.y, - victim_velocity.z, - ); + let packet = &CEntityVelocity::new(entity_id, victim_velocity); let velocity = attacker.velocity.load(); attacker.velocity.store(velocity.multiply(0.6, 1.0, 0.6)); diff --git a/pumpkin/src/entity/effect/mod.rs b/pumpkin/src/entity/effect/mod.rs new file mode 100644 index 000000000..e88df8258 --- /dev/null +++ b/pumpkin/src/entity/effect/mod.rs @@ -0,0 +1,11 @@ +use pumpkin_data::entity::EffectType; + +#[derive(PartialEq, Eq, Hash, Clone)] +pub struct Effect { + pub r#type: EffectType, + pub duration: i32, + pub amplifier: u8, + pub ambient: bool, + pub show_particles: bool, + pub show_icon: bool, +} diff --git a/pumpkin/src/entity/experience_orb.rs b/pumpkin/src/entity/experience_orb.rs new file mode 100644 index 000000000..f8af8c677 --- /dev/null +++ b/pumpkin/src/entity/experience_orb.rs @@ -0,0 +1,98 @@ +use std::sync::{Arc, atomic::AtomicU32}; + +use async_trait::async_trait; +use pumpkin_data::{damage::DamageType, entity::EntityType}; +use pumpkin_util::math::vector3::Vector3; + +use crate::{server::Server, world::World}; + +use super::{Entity, EntityBase, living::LivingEntity, player::Player}; + +pub struct ExperienceOrbEntity { + entity: Entity, + amount: u32, + orb_age: AtomicU32, +} + +impl ExperienceOrbEntity { + pub fn new(entity: Entity, amount: u32) -> Self { + entity.yaw.store(rand::random::() * 360.0); + Self { + entity, + amount, + orb_age: AtomicU32::new(0), + } + } + + pub async fn spawn(world: &Arc, server: &Server, position: Vector3, amount: u32) { + let mut amount = amount; + while amount > 0 { + let i = Self::round_to_orb_size(amount); + amount -= i; + let entity = server.add_entity(position, EntityType::EXPERIENCE_ORB, world); + let orb = Arc::new(Self::new(entity, i)); + world.spawn_entity(orb).await; + } + } + + fn round_to_orb_size(value: u32) -> u32 { + if value >= 2477 { + 2477 + } else if value >= 1237 { + 1237 + } else if value >= 617 { + 617 + } else if value >= 307 { + 307 + } else if value >= 149 { + 149 + } else if value >= 73 { + 73 + } else if value >= 37 { + 37 + } else if value >= 17 { + 17 + } else if value >= 7 { + 7 + } else if value >= 3 { + 3 + } else { + 1 + } + } +} + +#[async_trait] +impl EntityBase for ExperienceOrbEntity { + async fn tick(&self, _: &Server) { + let age = self + .orb_age + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + if age >= 6000 { + self.entity.remove().await; + } + } + + fn get_entity(&self) -> &Entity { + &self.entity + } + + async fn on_player_collision(&self, player: Arc) { + let mut delay = player.experience_pick_up_delay.lock().await; + if *delay == 0 { + *delay = 2; + player.living_entity.pickup(&self.entity, 1).await; + player.add_experience_points(self.amount as i32).await; + // TODO: pickingCount for merging + self.entity.remove().await; + } + } + + async fn damage(&self, _amount: f32, _damage_type: DamageType) -> bool { + false + } + + fn get_living_entity(&self) -> Option<&LivingEntity> { + None + } +} diff --git a/pumpkin/src/entity/hunger.rs b/pumpkin/src/entity/hunger.rs index 5fb9d68bb..e1810f5b2 100644 --- a/pumpkin/src/entity/hunger.rs +++ b/pumpkin/src/entity/hunger.rs @@ -1,7 +1,7 @@ use crossbeam::atomic::AtomicCell; use pumpkin_data::damage::DamageType; -use super::player::Player; +use super::{EntityBase, player::Player}; pub struct HungerManager { /// The current hunger level. @@ -50,7 +50,7 @@ impl HungerManager { } else if level == 0 { self.tick_timer.fetch_add(1); if self.tick_timer.load() >= 80 { - player.living_entity.damage(1.0, DamageType::STARVE).await; + player.damage(1.0, DamageType::STARVE).await; self.tick_timer.store(0); } } else { diff --git a/pumpkin/src/entity/item.rs b/pumpkin/src/entity/item.rs index 87a0bc6eb..558e8ff22 100644 --- a/pumpkin/src/entity/item.rs +++ b/pumpkin/src/entity/item.rs @@ -1,71 +1,155 @@ -use std::sync::{atomic::AtomicI8, Arc}; +use std::sync::{Arc, atomic::AtomicU32}; use async_trait::async_trait; +use pumpkin_data::{damage::DamageType, item::Item}; use pumpkin_protocol::{ client::play::{CTakeItemEntity, MetaDataType, Metadata}, - codec::{slot::Slot, var_int::VarInt}, + codec::slot::Slot, }; use pumpkin_world::item::ItemStack; +use tokio::sync::Mutex; -use super::{living::LivingEntity, player::Player, Entity, EntityBase}; +use crate::server::Server; + +use super::{Entity, EntityBase, living::LivingEntity, player::Player}; pub struct ItemEntity { entity: Entity, - item: Slot, - id: u16, - count: u8, - pickup_delay: AtomicI8, + item: Item, + item_age: AtomicU32, + // These cannot be atomic values because we mutate their state based on what they are; we run + // into the ABA problem + item_count: Mutex, + pickup_delay: Mutex, } impl ItemEntity { - pub fn new(entity: Entity, stack: &ItemStack) -> Self { - let slot = Slot::from(stack); + pub fn new(entity: Entity, item_id: u16, count: u32) -> Self { + entity.yaw.store(rand::random::() * 360.0); Self { entity, - id: stack.item.id, - count: stack.item_count, - item: slot, - pickup_delay: AtomicI8::new(10), // Vanilla + item: Item::from_id(item_id).expect("We passed a bad item id into ItemEntity"), + item_age: AtomicU32::new(0), + item_count: Mutex::new(count), + pickup_delay: Mutex::new(10), // Vanilla pickup delay is 10 ticks } } pub async fn send_meta_packet(&self) { + let slot = Slot::new(self.item.id, *self.item_count.lock().await); self.entity - .send_meta_data(Metadata::new(8, MetaDataType::ItemStack, &self.item)) + .send_meta_data(&[Metadata::new(8, MetaDataType::ItemStack, &slot)]) .await; } } #[async_trait] impl EntityBase for ItemEntity { - async fn tick(&self) { - if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) > 0 { - self.pickup_delay - .fetch_sub(1, std::sync::atomic::Ordering::Relaxed); + async fn tick(&self, _server: &Server) { + { + let mut delay = self.pickup_delay.lock().await; + *delay = delay.saturating_sub(1); + }; + + let age = self + .item_age + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + if age >= 6000 { + self.entity.remove().await; } } + async fn damage(&self, _amount: f32, _damage_type: DamageType) -> bool { + false + } + async fn on_player_collision(&self, player: Arc) { - if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) == 0 { + let can_pickup = { + let delay = self.pickup_delay.lock().await; + *delay == 0 + }; + + if can_pickup { let mut inv = player.inventory.lock().await; - // Check if we have space in inv - if let Some(slot) = inv.collect_item_slot(self.id) { - let mut item = self.item.clone(); - if let Some(stack) = inv.get_slot(slot).unwrap() { - // If we merge into an existing stack lets increase its count - stack.item_count += self.count; - // Since we set the slot with the item, we need to also have the new item count, - // So existing count + self.count - item.item_count = VarInt(i32::from(stack.item_count)); + let mut total_pick_up = 0; + let mut slot_updates = Vec::new(); + let remove_entity = { + let mut stack_size = self.item_count.lock().await; + let max_stack = self.item.components.max_stack_size; + while *stack_size > 0 { + if let Some(slot) = inv.get_pickup_item_slot(self.item.id) { + // Fill the inventory while there are items in the stack and space in the inventory + let maybe_stack = inv + .get_slot(slot) + .expect("collect item slot returned an invalid slot"); + + if let Some(existing_stack) = maybe_stack { + // We have the item in this stack already + + // This is bounded to u8::MAX + let amount_to_fill = u32::from(max_stack - existing_stack.item_count); + // This is also bounded to u8::MAX since amount_to_fill is max u8::MAX + let amount_to_add = amount_to_fill.min(*stack_size); + // Therefore this is safe + + // Update referenced stack so next call to get_pickup_item_slot is + // correct + existing_stack.item_count += amount_to_add as u8; + total_pick_up += amount_to_add; + + debug_assert!(amount_to_add > 0); + *stack_size -= amount_to_add; + + slot_updates.push((slot, existing_stack.clone())); + } else { + // A new stack + + // This is bounded to u8::MAX + let amount_to_fill = u32::from(max_stack); + // This is also bounded to u8::MAX since amount_to_fill is max u8::MAX + let amount_to_add = amount_to_fill.min(*stack_size); + total_pick_up += amount_to_add; + + debug_assert!(amount_to_add > 0); + *stack_size -= amount_to_add; + + // Therefore this is safe + let item_stack = ItemStack::new(amount_to_add as u8, self.item.clone()); + + // Update referenced stack so next call to get_pickup_item_slot is + // correct + *maybe_stack = Some(item_stack.clone()); + + slot_updates.push((slot, item_stack)); + } + } else { + // We can't pick anything else up + break; + } } - player.update_single_slot(&mut inv, slot as i16, item).await; + + *stack_size == 0 + }; + + if total_pick_up > 0 { player .client .send_packet(&CTakeItemEntity::new( self.entity.entity_id.into(), player.entity_id().into(), - 1.into(), + total_pick_up.into(), )) .await; + } + + // TODO: Can we batch slot updates? + for (slot, stack) in slot_updates { + player.update_single_slot(&mut inv, slot, stack).await; + } + + if remove_entity { self.entity.remove().await; + } else { + // Update entity + self.send_meta_packet().await; } } } diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index 6a64286be..da9847337 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -1,19 +1,25 @@ -use std::sync::atomic::AtomicI32; +use std::sync::atomic::AtomicU8; +use std::{collections::HashMap, sync::atomic::AtomicI32}; +use crate::server::Server; use async_trait::async_trait; use crossbeam::atomic::AtomicCell; +use pumpkin_config::ADVANCED_CONFIG; +use pumpkin_data::entity::{EffectType, EntityStatus}; use pumpkin_data::{damage::DamageType, sound::Sound}; use pumpkin_nbt::tag::NbtTag; +use pumpkin_protocol::client::play::{CHurtAnimation, CTakeItemEntity}; +use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::{ - client::play::{ - CDamageEvent, CEntityStatus, CSetEquipment, EquipmentSlot, MetaDataType, Metadata, - }, + client::play::{CDamageEvent, CSetEquipment, EquipmentSlot, MetaDataType, Metadata}, codec::slot::Slot, }; use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; +use tokio::sync::Mutex; -use super::{Entity, EntityId, NBTStorage}; +use super::EntityBase; +use super::{Entity, EntityId, NBTStorage, effect::Effect}; /// Represents a living entity within the game world. /// @@ -29,11 +35,13 @@ pub struct LivingEntity { pub last_damage_taken: AtomicCell, /// The current health level of the entity. pub health: AtomicCell, + pub death_time: AtomicU8, /// The distance the entity has been falling pub fall_distance: AtomicCell, + pub active_effects: Mutex>, } impl LivingEntity { - pub const fn new(entity: Entity) -> Self { + pub fn new(entity: Entity) -> Self { Self { entity, last_pos: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)), @@ -41,17 +49,8 @@ impl LivingEntity { last_damage_taken: AtomicCell::new(0.0), health: AtomicCell::new(20.0), fall_distance: AtomicCell::new(0.0), - } - } - - pub fn tick(&self) { - if self - .time_until_regen - .load(std::sync::atomic::Ordering::Relaxed) - > 0 - { - self.time_until_regen - .fetch_sub(1, std::sync::atomic::Ordering::Relaxed); + death_time: AtomicU8::new(0), + active_effects: Mutex::new(HashMap::new()), } } @@ -71,6 +70,21 @@ impl LivingEntity { .await; } + /// Picks up and Item entity or XP Orb + pub async fn pickup(&self, item: &Entity, stack_amount: u32) { + // TODO: Only nearby + self.entity + .world + .read() + .await + .broadcast_packet_all(&CTakeItemEntity::new( + item.entity_id.into(), + self.entity.entity_id.into(), + stack_amount.into(), + )) + .await; + } + pub fn set_pos(&self, position: Vector3) { self.last_pos.store(self.entity.pos.load()); self.entity.set_pos(position); @@ -86,7 +100,7 @@ impl LivingEntity { self.health.store(health); // tell everyone entities health changed self.entity - .send_meta_data(Metadata::new(9, MetaDataType::Float, health)) + .send_meta_data(&[Metadata::new(9, MetaDataType::Float, health)]) .await; } @@ -131,9 +145,20 @@ impl LivingEntity { true } - pub async fn damage(&self, amount: f32, damage_type: DamageType) -> bool { - self.damage_with_context(amount, damage_type, None, None, None) - .await + pub async fn add_effect(&self, effect: Effect) { + let mut effects = self.active_effects.lock().await; + effects.insert(effect.r#type, effect); + // TODO broadcast metadata + } + + pub async fn has_effect(&self, effect: EffectType) -> bool { + let effects = self.active_effects.lock().await; + effects.contains_key(&effect) + } + + pub async fn get_effect(&self, effect: EffectType) -> Option { + let effects = self.active_effects.lock().await; + effects.get(&effect).cloned() } /// Returns if the entity was damaged or not @@ -202,22 +227,77 @@ impl LivingEntity { pub async fn kill(&self) { self.set_health(0.0).await; - // Spawns death smoke particles + // Plays the death sound self.entity .world .read() .await - .broadcast_packet_all(&CEntityStatus::new(self.entity.entity_id, 60)) + .send_entity_status( + &self.entity, + EntityStatus::PlayDeathSoundOrAddProjectileHitParticles, + ) .await; - // Plays the death sound and death animation - self.entity - .world - .read() + } +} + +#[async_trait] +impl EntityBase for LivingEntity { + async fn tick(&self, _server: &Server) { + if self + .time_until_regen + .load(std::sync::atomic::Ordering::Relaxed) + > 0 + { + self.time_until_regen + .fetch_sub(1, std::sync::atomic::Ordering::Relaxed); + } + if self.health.load() <= 0.0 { + let time = self + .death_time + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + if time >= 20 { + // Spawn Death particles + self.entity + .world + .read() + .await + .send_entity_status(&self.entity, EntityStatus::AddDeathParticles) + .await; + self.entity.remove().await; + } + } + } + async fn damage(&self, amount: f32, damage_type: DamageType) -> bool { + let world = self.entity.world.read().await; + if !self.check_damage(amount) { + return false; + } + let config = &ADVANCED_CONFIG.pvp; + + if !self + .damage_with_context(amount, damage_type, None, None, None) .await - .broadcast_packet_all(&CEntityStatus::new(self.entity.entity_id, 3)) - .await; + { + return false; + } + + if config.hurt_animation { + let entity_id = VarInt(self.entity.entity_id); + world + .broadcast_packet_all(&CHurtAnimation::new(entity_id, self.entity.yaw.load())) + .await; + } + true + } + fn get_entity(&self) -> &Entity { + &self.entity + } + + fn get_living_entity(&self) -> Option<&LivingEntity> { + Some(self) } } + #[async_trait] impl NBTStorage for LivingEntity { async fn write_nbt(&self, nbt: &mut pumpkin_nbt::compound::NbtCompound) { diff --git a/pumpkin/src/entity/mob/mod.rs b/pumpkin/src/entity/mob/mod.rs index 3b4626f15..bc846de9d 100644 --- a/pumpkin/src/entity/mob/mod.rs +++ b/pumpkin/src/entity/mob/mod.rs @@ -9,9 +9,9 @@ use zombie::Zombie; use crate::{server::Server, world::World}; use super::{ + Entity, EntityBase, ai::{goal::Goal, path::Navigator}, living::LivingEntity, - Entity, EntityBase, }; pub mod zombie; @@ -24,7 +24,8 @@ pub struct MobEntity { #[async_trait] impl EntityBase for MobEntity { - async fn tick(&self) { + async fn tick(&self, server: &Server) { + self.living_entity.tick(server).await; let mut goals = self.goals.lock().await; for (goal, running) in goals.iter_mut() { if *running { @@ -62,7 +63,6 @@ pub async fn from_type( goals: Mutex::new(vec![]), navigator: Mutex::new(Navigator::default()), }; - #[expect(clippy::single_match)] match entity_type { EntityType::ZOMBIE => Zombie::make(&mob).await, // TODO diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 32535a3fa..828faf6b8 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -1,7 +1,7 @@ -use core::f32; -use std::sync::{atomic::AtomicBool, Arc}; - +use crate::server::Server; use async_trait::async_trait; +use bytes::{BufMut, BytesMut}; +use core::f32; use crossbeam::atomic::AtomicCell; use living::LivingEntity; use player::Player; @@ -12,9 +12,10 @@ use pumpkin_data::{ }; use pumpkin_nbt::{compound::NbtCompound, tag::NbtTag}; use pumpkin_protocol::{ + bytebuf::serializer::Serializer, client::play::{ - CHeadRot, CSetEntityMetadata, CSpawnEntity, CTeleportEntity, CUpdateEntityRot, - MetaDataType, Metadata, + CEntityVelocity, CHeadRot, CSetEntityMetadata, CSpawnEntity, CTeleportEntity, + CUpdateEntityRot, MetaDataType, Metadata, }, codec::var_int::VarInt, }; @@ -27,17 +28,21 @@ use pumpkin_util::math::{ wrap_degrees, }; use serde::Serialize; +use std::sync::{Arc, atomic::AtomicBool}; use tokio::sync::RwLock; use crate::world::World; pub mod ai; +pub mod effect; +pub mod experience_orb; pub mod hunger; pub mod item; pub mod living; pub mod mob; pub mod player; pub mod projectile; +pub mod tnt; mod combat; @@ -46,8 +51,24 @@ pub type EntityId = i32; #[async_trait] pub trait EntityBase: Send + Sync { /// Gets Called every tick - async fn tick(&self) {} - /// Called when a player collides with the entity + async fn tick(&self, server: &Server) { + if let Some(living) = self.get_living_entity() { + living.tick(server).await; + } else { + self.get_entity().tick(server).await; + } + } + + /// Returns if damage was successful or not + async fn damage(&self, amount: f32, damage_type: DamageType) -> bool { + if let Some(living) = self.get_living_entity() { + living.damage(amount, damage_type).await + } else { + self.get_entity().damage(amount, damage_type).await + } + } + + /// Called when a player collides with a entity async fn on_player_collision(&self, _player: Arc) {} fn get_entity(&self) -> &Entity; fn get_living_entity(&self) -> Option<&LivingEntity>; @@ -142,6 +163,15 @@ impl Entity { } } + pub async fn set_velocity(&self, velocity: Vector3) { + self.velocity.store(velocity); + self.world + .read() + .await + .broadcast_packet_all(&CEntityVelocity::new(self.entity_id.into(), velocity)) + .await; + } + /// Updates the entity's position, block position, and chunk position. /// /// This function calculates the new position, block position, and chunk position based on the provided coordinates. If any of these values change, the corresponding fields are updated. @@ -344,7 +374,7 @@ impl Entity { } else { b &= !(1 << index); } - self.send_meta_data(Metadata::new(0, MetaDataType::Byte, b)) + self.send_meta_data(&[Metadata::new(0, MetaDataType::Byte, b)]) .await; } @@ -357,21 +387,29 @@ impl Entity { .await; } - pub async fn send_meta_data(&self, meta: Metadata) + pub async fn send_meta_data(&self, meta: &[Metadata]) where T: Serialize, { + let mut buf = Vec::new(); + for meta in meta { + let serializer_buf = BytesMut::new(); + let mut serializer = Serializer::new(serializer_buf); + meta.serialize(&mut serializer).unwrap(); + buf.put(serializer.output); + } + buf.put_u8(255); self.world .read() .await - .broadcast_packet_all(&CSetEntityMetadata::new(self.entity_id.into(), meta)) + .broadcast_packet_all(&CSetEntityMetadata::new(self.entity_id.into(), buf)) .await; } pub async fn set_pose(&self, pose: EntityPose) { self.pose.store(pose); let pose = pose as i32; - self.send_meta_data(Metadata::new(6, MetaDataType::EntityPose, VarInt(pose))) + self.send_meta_data(&[Metadata::new(6, MetaDataType::EntityPose, VarInt(pose))]) .await; } @@ -383,7 +421,11 @@ impl Entity { #[async_trait] impl EntityBase for Entity { - async fn tick(&self) {} + async fn damage(&self, _amount: f32, _damage_type: DamageType) -> bool { + false + } + + async fn tick(&self, _: &Server) {} fn get_entity(&self) -> &Entity { self diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index f05772530..f881967c1 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -2,8 +2,8 @@ use pumpkin_world::block::registry::State; use std::{ num::NonZeroU8, sync::{ - atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU32, Ordering}, Arc, + atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU32, Ordering}, }, time::{Duration, Instant}, }; @@ -13,7 +13,7 @@ use crossbeam::atomic::AtomicCell; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_data::{ damage::DamageType, - entity::EntityType, + entity::{EffectType, EntityStatus, EntityType}, item::Operation, particle::Particle, sound::{Sound, SoundCategory}, @@ -21,12 +21,13 @@ use pumpkin_data::{ use pumpkin_inventory::player::PlayerInventory; use pumpkin_nbt::compound::NbtCompound; use pumpkin_protocol::{ + RawPacket, ServerPacket, bytebuf::packet::Packet, client::play::{ - CAcknowledgeBlockChange, CActionBar, CCombatDeath, CDisguisedChatMessage, CEntityStatus, - CGameEvent, CHurtAnimation, CKeepAlive, CParticle, CPlayDisconnect, CPlayerAbilities, - CPlayerInfoUpdate, CPlayerPosition, CRespawn, CSetExperience, CSetHealth, CSubtitle, - CSystemChatMessage, CTitleText, CUnloadChunk, GameEvent, MetaDataType, PlayerAction, + CAcknowledgeBlockChange, CActionBar, CCombatDeath, CDisguisedChatMessage, CGameEvent, + CKeepAlive, CParticle, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, + CPlayerPosition, CRespawn, CSetExperience, CSetHealth, CSubtitle, CSystemChatMessage, + CTitleText, CUnloadChunk, CUpdateMobEffect, GameEvent, MetaDataType, PlayerAction, }, server::play::{ SChatCommand, SChatMessage, SClientCommand, SClientInformationPlay, SClientTickEnd, @@ -35,7 +36,6 @@ use pumpkin_protocol::{ SPlayerRotation, SSetCreativeSlot, SSetHeldItem, SSetPlayerGround, SSwingArm, SUpdateSign, SUseItem, SUseItemOn, }, - RawPacket, ServerPacket, }; use pumpkin_protocol::{ client::play::CSoundEffect, @@ -49,6 +49,7 @@ use pumpkin_protocol::{ server::play::{SClickContainer, SKeepAlive}, }; use pumpkin_util::{ + GameMode, math::{ boundingbox::{BoundingBox, EntityDimensions}, experience, @@ -58,16 +59,16 @@ use pumpkin_util::{ }, permission::PermissionLvl, text::TextComponent, - GameMode, }; use pumpkin_world::{cylindrical_chunk_iterator::Cylindrical, item::ItemStack}; use tokio::sync::{Mutex, Notify, RwLock}; use super::{ - combat::{self, player_attack_sound, AttackType}, + Entity, EntityBase, EntityId, NBTStorage, + combat::{self, AttackType, player_attack_sound}, + effect::Effect, hunger::HungerManager, item::ItemEntity, - Entity, EntityBase, EntityId, NBTStorage, }; use crate::{ block, @@ -102,7 +103,7 @@ pub struct Player { /// The ID of the currently open container (if any). pub open_container: AtomicCell>, /// The item currently being held by the player. - pub carried_item: AtomicCell>, + pub carried_item: Mutex>, /// send `send_abilities_update` when changed /// The player's abilities and special powers. /// @@ -146,6 +147,7 @@ pub struct Player { pub experience_progress: AtomicCell, /// The player's total experience points pub experience_points: AtomicI32, + pub experience_pick_up_delay: Mutex, } impl Player { @@ -199,7 +201,8 @@ impl Player { tick_counter: AtomicI32::new(0), packet_sequence: AtomicI32::new(-1), start_mining_time: AtomicI32::new(0), - carried_item: AtomicCell::new(None), + carried_item: Mutex::new(None), + experience_pick_up_delay: Mutex::new(0), teleport_id_count: AtomicI32::new(0), mining: AtomicBool::new(false), mining_pos: Mutex::new(BlockPos(Vector3::new(0, 0, 0))), @@ -286,7 +289,6 @@ impl Player { pub async fn attack(&self, victim: Arc) { let world = self.world().await; let victim_entity = victim.get_entity(); - let victim_living_entity = victim.get_living_entity(); let attacker_entity = &self.living_entity.entity; let config = &ADVANCED_CONFIG.pvp; @@ -334,56 +336,45 @@ impl Player { let pos = victim_entity.pos.load(); - if let Some(living) = victim_living_entity { - if !living.check_damage(damage as f32) { - world - .play_sound( - Sound::EntityPlayerAttackNodamage, - SoundCategory::Players, - &pos, - ) - .await; - return; - } - } - - world - .play_sound(Sound::EntityPlayerHurt, SoundCategory::Players, &pos) - .await; - let attack_type = AttackType::new(self, attack_cooldown_progress as f32).await; - player_attack_sound(&pos, &world, attack_type).await; - if matches!(attack_type, AttackType::Critical) { damage *= 1.5; } - if let Some(living) = victim_living_entity { - living - .damage(damage as f32, DamageType::PLAYER_ATTACK) - .await; - } - - let mut knockback_strength = 1.0; - match attack_type { - AttackType::Knockback => knockback_strength += 1.0, - AttackType::Sweeping => { - combat::spawn_sweep_particle(attacker_entity, &world, &pos).await; - } - _ => {} - }; - - if config.knockback { - combat::handle_knockback(attacker_entity, &world, victim_entity, knockback_strength) + if !victim + .damage(damage as f32, DamageType::PLAYER_ATTACK) + .await + { + world + .play_sound( + Sound::EntityPlayerAttackNodamage, + SoundCategory::Players, + &self.living_entity.entity.pos.load(), + ) .await; + return; } - if config.hurt_animation { - let entity_id = VarInt(victim_entity.entity_id); - world - .broadcast_packet_all(&CHurtAnimation::new(&entity_id, attacker_entity.yaw.load())) + if victim.get_living_entity().is_some() { + let mut knockback_strength = 1.0; + player_attack_sound(&pos, &world, attack_type).await; + match attack_type { + AttackType::Knockback => knockback_strength += 1.0, + AttackType::Sweeping => { + combat::spawn_sweep_particle(attacker_entity, &world, &pos).await; + } + _ => {} + }; + if config.knockback { + combat::handle_knockback( + attacker_entity, + &world, + victim_entity, + knockback_strength, + ) .await; + } } if config.swing {} @@ -445,7 +436,7 @@ impl Player { self.cancel_tasks.notified().await; } - pub async fn tick(&self) { + pub async fn tick(&self, server: &Server) { if self .client .closed @@ -460,6 +451,12 @@ impl Player { )) .await; } + { + let mut xp = self.experience_pick_up_delay.lock().await; + if *xp > 0 { + *xp -= 1; + } + } self.tick_counter.fetch_add(1, Ordering::Relaxed); @@ -491,7 +488,7 @@ impl Player { self.last_attacked_ticks .fetch_add(1, std::sync::atomic::Ordering::Relaxed); - self.living_entity.tick(); + self.living_entity.tick(server).await; self.hunger_manager.tick(self).await; // timeout/keep alive handling @@ -624,11 +621,16 @@ impl Player { /// syncs the players permission level with the client pub async fn send_permission_lvl_update(&self) { - self.client - .send_packet(&CEntityStatus::new( - self.entity_id(), - 24 + self.permission_lvl.load() as i8, - )) + let status = match self.permission_lvl.load() { + PermissionLvl::Zero => EntityStatus::SetOpLevel0, + PermissionLvl::One => EntityStatus::SetOpLevel1, + PermissionLvl::Two => EntityStatus::SetOpLevel2, + PermissionLvl::Three => EntityStatus::SetOpLevel3, + PermissionLvl::Four => EntityStatus::SetOpLevel4, + }; + self.world() + .await + .send_entity_status(&self.living_entity.entity, status) .await; } @@ -817,7 +819,7 @@ impl Player { let _ = self .client - .try_send_packet(&CPlayDisconnect::new(&reason)) + .try_send_packet(&CPlayDisconnect::new(reason.clone())) .await; log::info!( @@ -929,15 +931,10 @@ impl Player { let config = self.config.lock().await; self.living_entity .entity - .send_meta_data(Metadata::new(17, MetaDataType::Byte, config.skin_parts)) - .await; - self.living_entity - .entity - .send_meta_data(Metadata::new( - 18, - MetaDataType::Byte, - config.main_hand as u8, - )) + .send_meta_data(&[ + Metadata::new(17, MetaDataType::Byte, config.skin_parts), + Metadata::new(18, MetaDataType::Byte, config.main_hand as u8), + ]) .await; } @@ -958,13 +955,52 @@ impl Player { .await .get_mining_speed(block_name) .await; - // TODO: Handle effects + // Haste + if self.living_entity.has_effect(EffectType::Haste).await + || self + .living_entity + .has_effect(EffectType::ConduitPower) + .await + { + speed *= 1.0 + (self.get_haste_amplifier().await + 1) as f32 * 0.2; + } + // Fatigue + if let Some(fatigue) = self + .living_entity + .get_effect(EffectType::MiningFatigue) + .await + { + let fatigue_speed = match fatigue.amplifier { + 0 => 0.3, + 1 => 0.09, + 2 => 0.0027, + _ => 8.1E-4, + }; + speed *= fatigue_speed; + } + // TODO: Handle when in Water if !self.living_entity.entity.on_ground.load(Ordering::Relaxed) { speed /= 5.0; } speed } + async fn get_haste_amplifier(&self) -> u32 { + let mut i = 0; + let mut j = 0; + if let Some(effect) = self.living_entity.get_effect(EffectType::Haste).await { + i = effect.amplifier; + } + if let Some(effect) = self + .living_entity + .get_effect(EffectType::ConduitPower) + .await + { + j = effect.amplifier; + } + u32::from(i.max(j)) + } + pub async fn send_message( &self, message: &TextComponent, @@ -982,22 +1018,25 @@ impl Player { .await; } - pub async fn drop_item(&self, server: &Server, drop_stack: bool) { + pub async fn drop_item(&self, server: &Server, item_id: u16, count: u32) { + let entity = server.add_entity( + self.living_entity.entity.pos.load(), + EntityType::ITEM, + &self.world().await, + ); + + // TODO: Merge stacks together + let item_entity = Arc::new(ItemEntity::new(entity, item_id, count)); + self.world().await.spawn_entity(item_entity.clone()).await; + item_entity.send_meta_packet().await; + } + + pub async fn drop_held_item(&self, server: &Server, drop_stack: bool) { let mut inv = self.inventory.lock().await; - if let Some(item) = inv.held_item_mut() { - let drop_amount = if drop_stack { item.item_count } else { 1 }; - let entity = server.add_entity( - self.living_entity.entity.pos.load(), - EntityType::ITEM, - &self.world().await, - ); - let item_entity = Arc::new(ItemEntity::new( - entity, - &ItemStack::new(drop_amount, item.item), - )); - self.world().await.spawn_entity(item_entity.clone()).await; - item_entity.send_meta_packet().await; - // decrase item in hotbar + if let Some(item_stack) = inv.held_item_mut() { + let drop_amount = if drop_stack { item_stack.item_count } else { 1 }; + self.drop_item(server, item_stack.item.id, u32::from(drop_amount)) + .await; inv.decrease_current_stack(drop_amount); } } @@ -1021,8 +1060,8 @@ impl Player { self.client .send_packet(&CSetExperience::new( progress.clamp(0.0, 1.0), - level.into(), points.into(), + level.into(), )) .await; } @@ -1048,6 +1087,34 @@ impl Player { self.set_experience(new_level, progress, points).await; } + pub async fn add_effect(&self, effect: Effect, keep_fading: bool) { + let mut flag: i8 = 0; + + if effect.ambient { + flag |= 1; + } + if effect.show_particles { + flag |= 2; + } + if effect.show_icon { + flag |= 4; + } + if keep_fading { + flag |= 8; + } + let effect_id = VarInt(effect.r#type as i32); + self.client + .send_packet(&CUpdateMobEffect::new( + self.entity_id().into(), + effect_id, + effect.amplifier.into(), + effect.duration.into(), + flag, + )) + .await; + self.living_entity.add_effect(effect).await; + } + /// Add experience levels to the player pub async fn add_experience_levels(&self, added_levels: i32) { let current_level = self.experience_level.load(Ordering::Relaxed); @@ -1083,7 +1150,7 @@ impl Player { let total_exp = experience::points_to_level(current_level) + current_points; let new_total_exp = total_exp + added_points; let (new_level, new_points) = experience::total_to_level_and_points(new_total_exp); - let progress = experience::progress_in_level(new_level, new_points); + let progress = experience::progress_in_level(new_points, new_level); self.set_experience(new_level, progress, new_points).await; } } @@ -1106,7 +1173,8 @@ impl NBTStorage for Player { async fn read_nbt(&mut self, nbt: &mut NbtCompound) { self.living_entity.read_nbt(nbt).await; - self.inventory.lock().await.selected = nbt.get_int("SelectedItemSlot").unwrap_or(0) as u32; + self.inventory.lock().await.selected = + nbt.get_int("SelectedItemSlot").unwrap_or(0) as usize; self.abilities.lock().await.read_nbt(nbt).await; // Load from total XP @@ -1121,6 +1189,18 @@ impl NBTStorage for Player { #[async_trait] impl EntityBase for Player { + async fn damage(&self, amount: f32, damage_type: DamageType) -> bool { + self.world() + .await + .play_sound( + Sound::EntityPlayerHurt, + SoundCategory::Players, + &self.living_entity.entity.pos.load(), + ) + .await; + self.living_entity.damage(amount, damage_type).await + } + fn get_entity(&self) -> &Entity { &self.living_entity.entity } @@ -1243,7 +1323,7 @@ impl Player { .await; } SSetCreativeSlot::PACKET_ID => { - self.handle_set_creative_slot(SSetCreativeSlot::read(bytebuf)?) + self.handle_set_creative_slot(server, SSetCreativeSlot::read(bytebuf)?) .await?; } SSwingArm::PACKET_ID => { @@ -1265,7 +1345,7 @@ impl Player { .await; } SPCookieResponse::PACKET_ID => { - self.handle_cookie_response(SPCookieResponse::read(bytebuf)?); + self.handle_cookie_response(&SPCookieResponse::read(bytebuf)?); } SCloseContainer::PACKET_ID => { self.handle_close_container(server, SCloseContainer::read(bytebuf)?) diff --git a/pumpkin/src/entity/projectile/mod.rs b/pumpkin/src/entity/projectile/mod.rs index a316b49a5..092e5cad3 100644 --- a/pumpkin/src/entity/projectile/mod.rs +++ b/pumpkin/src/entity/projectile/mod.rs @@ -1,8 +1,10 @@ use std::f32::{self}; +use async_trait::async_trait; +use pumpkin_data::damage::DamageType; use pumpkin_util::math::vector3::Vector3; -use super::{living::LivingEntity, Entity, EntityBase}; +use super::{Entity, EntityBase, living::LivingEntity}; pub struct ThrownItemEntity { entity: Entity, @@ -73,11 +75,16 @@ impl ThrownItemEntity { } } +#[async_trait] impl EntityBase for ThrownItemEntity { fn get_entity(&self) -> &Entity { &self.entity } + async fn damage(&self, _amount: f32, _damage_type: DamageType) -> bool { + false + } + fn get_living_entity(&self) -> Option<&LivingEntity> { None } diff --git a/pumpkin/src/entity/tnt.rs b/pumpkin/src/entity/tnt.rs new file mode 100644 index 000000000..3e57b7ad9 --- /dev/null +++ b/pumpkin/src/entity/tnt.rs @@ -0,0 +1,77 @@ +use crate::server::Server; +use async_trait::async_trait; +use pumpkin_data::damage::DamageType; +use pumpkin_macros::block_state; +use pumpkin_protocol::{ + client::play::{MetaDataType, Metadata}, + codec::var_int::VarInt, +}; +use pumpkin_util::math::vector3::Vector3; +use std::sync::atomic::AtomicU32; + +use super::{Entity, EntityBase, living::LivingEntity}; + +pub struct TNTEntity { + entity: Entity, + power: f32, + fuse: AtomicU32, +} + +impl TNTEntity { + pub fn new(entity: Entity, power: f32, fuse: u32) -> Self { + Self { + entity, + power, + fuse: AtomicU32::new(fuse), + } + } + pub async fn send_meta_packet(&self) { + // TODO: yes this is the wrong function, but we need to send this after spawning the entity + let pos: f64 = rand::random::() * 6.283_185_482_025_146_5; + self.entity + .set_velocity(Vector3::new(-pos.sin() * 0.02, 0.2, -pos.cos() * 0.02)) + .await; + // We can merge multiple data into one meta packet + self.entity + .send_meta_data(&[ + Metadata::new( + 8, + MetaDataType::Integer, + VarInt(self.fuse.load(std::sync::atomic::Ordering::Relaxed) as i32), + ), + Metadata::new( + 9, + MetaDataType::BlockState, + VarInt(i32::from(block_state!("tnt").state_id)), + ), + ]) + .await; + } +} + +#[async_trait] +impl EntityBase for TNTEntity { + async fn tick(&self, server: &Server) { + let fuse = self.fuse.fetch_sub(1, std::sync::atomic::Ordering::Relaxed); + if fuse == 0 { + self.entity.remove().await; + self.entity + .world + .read() + .await + .explode(server, self.entity.pos.load(), self.power) + .await; + } + } + async fn damage(&self, _amount: f32, _damage_type: DamageType) -> bool { + false + } + + fn get_entity(&self) -> &Entity { + &self.entity + } + + fn get_living_entity(&self) -> Option<&LivingEntity> { + None + } +} diff --git a/pumpkin/src/lib.rs b/pumpkin/src/lib.rs index d30ce5503..867cb61c3 100644 --- a/pumpkin/src/lib.rs +++ b/pumpkin/src/lib.rs @@ -1,9 +1,9 @@ // Not warn event sending macros #![allow(unused_labels)] -use crate::net::{lan_broadcast, query, rcon::RCONServer, Client}; -use crate::server::{ticker::Ticker, Server}; -use log::{logger, Level, LevelFilter, Log}; +use crate::net::{Client, lan_broadcast, query, rcon::RCONServer}; +use crate::server::{Server, ticker::Ticker}; +use log::{Level, LevelFilter, Log}; use net::PacketHandlerState; use plugin::PluginManager; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; @@ -12,7 +12,6 @@ use rustyline_async::{Readline, ReadlineEvent}; use std::collections::HashMap; use std::str::FromStr; use std::sync::atomic::AtomicBool; -use std::sync::OnceLock; use std::{ net::SocketAddr, sync::{Arc, LazyLock}, @@ -22,7 +21,7 @@ use tokio::sync::Notify; use tokio::task::JoinHandle; use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, - net::{tcp::OwnedReadHalf, TcpListener}, + net::{TcpListener, tcp::OwnedReadHalf}, sync::Mutex, }; @@ -42,10 +41,63 @@ const GIT_VERSION: &str = env!("GIT_VERSION"); pub static PLUGIN_MANAGER: LazyLock> = LazyLock::new(|| Mutex::new(PluginManager::new())); -// Yucky, is there a way to do this better? revisit our static LOGGER_IMPL? -static _INPUT_HOLDER: OnceLock>> = OnceLock::new(); +/// A wrapper for our logger to hold the terminal input while no input is expected in order to +/// properly flush logs to output while they happen instead of batched +pub struct ReadlineLogWrapper { + internal: Box, + readline: std::sync::Mutex>, +} + +impl ReadlineLogWrapper { + fn new(log: impl Log + 'static, rl: Option) -> Self { + Self { + internal: Box::new(log), + readline: std::sync::Mutex::new(rl), + } + } + + fn take_readline(&self) -> Option { + if let Ok(mut result) = self.readline.lock() { + result.take() + } else { + None + } + } + + fn return_readline(&self, rl: Readline) { + if let Ok(mut result) = self.readline.lock() { + println!("Returned rl"); + let _ = result.insert(rl); + } + } +} + +// writing to stdout is expensive anyway, so I dont think having a mutex here is a big deal. +impl Log for ReadlineLogWrapper { + fn log(&self, record: &log::Record) { + self.internal.log(record); + if let Ok(mut lock) = self.readline.lock() { + if let Some(rl) = lock.as_mut() { + let _ = rl.flush(); + } + } + } + + fn flush(&self) { + self.internal.flush(); + if let Ok(mut lock) = self.readline.lock() { + if let Some(rl) = lock.as_mut() { + let _ = rl.flush(); + } + } + } -pub static LOGGER_IMPL: LazyLock, LevelFilter)>> = LazyLock::new(|| { + fn enabled(&self, metadata: &log::Metadata) -> bool { + self.internal.enabled(metadata) + } +} + +pub static LOGGER_IMPL: LazyLock> = LazyLock::new(|| { if ADVANCED_CONFIG.logging.enabled { let mut config = simplelog::ConfigBuilder::new(); @@ -62,7 +114,7 @@ pub static LOGGER_IMPL: LazyLock, LevelFilter)>> = LazyLock for level in Level::iter() { config.set_level_color(level, None); } - } else if ADVANCED_CONFIG.commands.use_console { + } else { // We are technically logging to a file like object config.set_write_log_enable_colors(true); } @@ -81,13 +133,23 @@ pub static LOGGER_IMPL: LazyLock, LevelFilter)>> = LazyLock .unwrap_or(LevelFilter::Info); if ADVANCED_CONFIG.commands.use_console { - let (rl, stdout) = Readline::new("$ ".to_owned()).unwrap(); - let logger = simplelog::WriteLogger::new(level, config.build(), stdout); - let _ = _INPUT_HOLDER.set(Mutex::new(Some(rl))); - Some((Box::new(logger), level)) + match Readline::new("$ ".to_owned()) { + Ok((rl, stdout)) => { + let logger = simplelog::WriteLogger::new(level, config.build(), stdout); + Some((ReadlineLogWrapper::new(logger, Some(rl)), level)) + } + Err(e) => { + log::warn!( + "Failed to initialize console input ({}), falling back to simple logger", + e + ); + let logger = simplelog::SimpleLogger::new(level, config.build()); + Some((ReadlineLogWrapper::new(logger, None), level)) + } + } } else { let logger = simplelog::SimpleLogger::new(level, config.build()); - Some((Box::new(logger), level)) + Some((ReadlineLogWrapper::new(logger, None), level)) } } else { None @@ -116,7 +178,6 @@ pub struct PumpkinServer { pub server: Arc, pub listener: TcpListener, pub server_addr: SocketAddr, - readline_handle: Option>, tasks_to_await: Vec>, } @@ -137,12 +198,12 @@ impl PumpkinServer { let mut ticker = Ticker::new(BASIC_CONFIG.tps); - let mut readline = None; - if let Some(rt) = _INPUT_HOLDER.get() { - let mut rt = rt.lock().await; - let rt = rt.take().unwrap(); - let handle = setup_console(rt, server.clone()); - readline = Some(handle); + let mut tasks_to_await = Vec::new(); + if let Some((wrapper, _)) = &*LOGGER_IMPL { + if let Some(rl) = wrapper.take_readline() { + let handle = setup_console(rl, server.clone()); + tasks_to_await.push(handle); + } } if rcon.enabled { @@ -162,7 +223,6 @@ impl PumpkinServer { tokio::spawn(lan_broadcast::start_lan_broadcast(addr)); } - let mut tasks_to_await = Vec::new(); // Ticker { let server = server.clone(); @@ -176,7 +236,6 @@ impl PumpkinServer { server: server.clone(), listener, server_addr: addr, - readline_handle: readline, tasks_to_await, } } @@ -228,23 +287,26 @@ impl PumpkinServer { ); let (tx, mut rx) = tokio::sync::mpsc::channel(64); - let (connection_reader, connection_writer) = connection.into_split(); - let connection_reader = Arc::new(Mutex::new(connection_reader)); - let connection_writer = Arc::new(Mutex::new(connection_writer)); + let (mut connection_reader, connection_writer) = connection.into_split(); let client = Arc::new(Client::new(tx, client_addr, id)); let client_clone = client.clone(); // This task will be cleaned up on its own tokio::spawn(async move { - // We clone ownership of a tx into here thru the client so this will never drop + let mut connection_writer = connection_writer; + + // We clone ownership of `tx` into here thru the client so this will never drop // since there is always a tx in memory. We need to explicitly tell the recv to stop while let Some(notif) = rx.recv().await { match notif { PacketHandlerState::PacketReady => { - let mut enc = client_clone.enc.lock().await; - let buf = enc.take(); - if let Err(e) = connection_writer.lock().await.write_all(&buf).await { + let buf = { + let mut enc = client_clone.enc.lock().await; + enc.take() + }; + + if let Err(e) = connection_writer.write_all(&buf).await { log::warn!("Failed to write packet to client: {e}"); client_clone.close().await; break; @@ -264,7 +326,7 @@ impl PumpkinServer { .make_player .load(std::sync::atomic::Ordering::Relaxed) { - let open = poll(&client, connection_reader.clone()).await; + let open = poll(&client, &mut connection_reader).await; if open { client.process_packets(&server).await; }; @@ -273,7 +335,7 @@ impl PumpkinServer { .make_player .load(std::sync::atomic::Ordering::Relaxed) { - let (player, world) = server.add_player(client).await; + let (player, world) = server.add_player(client.clone()).await; world .spawn_player(&BASIC_CONFIG, player.clone(), &server) .await; @@ -284,7 +346,7 @@ impl PumpkinServer { .closed .load(core::sync::atomic::Ordering::Relaxed) { - let open = poll(&player.client, connection_reader.clone()).await; + let open = poll(&player.client, &mut connection_reader).await; if open { player.process_packets(&server).await; }; @@ -292,16 +354,15 @@ impl PumpkinServer { log::debug!("Cleaning up player for id {}", id); player.remove().await; server.remove_player().await; - tasks_clone.lock().await.remove(&id); } + + // Also handle case of client connects but does not become a player (like a server + // ping) + client.close().await; + tasks_clone.lock().await.remove(&id); }); tasks.lock().await.insert(id, Some(handle)); } - // Keep it in scope for logging - let rl = match self.readline_handle { - Some(rl) => Some(rl.await.unwrap()), - None => None, - }; log::info!("Stopped accepting incoming connections"); @@ -336,14 +397,17 @@ impl PumpkinServer { self.server.save().await; log::info!("Completed save!"); - logger().flush(); - if let Some(mut rl) = rl { - let _ = rl.flush(); + + // Explicitly drop the line reader to return the terminal to the original state + if let Some((wrapper, _)) = &*LOGGER_IMPL { + if let Some(rl) = wrapper.take_readline() { + let _ = rl; + } } } } -fn setup_console(rl: Readline, server: Arc) -> JoinHandle { +fn setup_console(rl: Readline, server: Arc) -> JoinHandle<()> { // This needs to be async or it will hog a thread tokio::spawn(async move { let mut rl = rl; @@ -378,13 +442,15 @@ fn setup_console(rl: Readline, server: Arc) -> JoinHandle { } } } + if let Some((wrapper, _)) = &*LOGGER_IMPL { + wrapper.return_readline(rl); + } + log::debug!("Stopped console commands task"); - let _ = rl.flush(); - rl }) } -async fn poll(client: &Client, connection_reader: Arc>) -> bool { +async fn poll(client: &Client, connection_reader: &mut OwnedReadHalf) -> bool { loop { if client.closed.load(std::sync::atomic::Ordering::Relaxed) { // If we manually close (like a kick) we dont want to keep reading bytes @@ -409,7 +475,7 @@ async fn poll(client: &Client, connection_reader: Arc>) -> dec.reserve(4096); let mut buf = dec.take_capacity(); - let bytes_read = connection_reader.lock().await.read_buf(&mut buf).await; + let bytes_read = connection_reader.read_buf(&mut buf).await; match bytes_read { Ok(cnt) => { //log::debug!("Read {} bytes", cnt); diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index e302bc749..ed4f34fbe 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -44,13 +44,13 @@ use std::{ #[cfg(not(unix))] use tokio::signal::ctrl_c; #[cfg(unix)] -use tokio::signal::unix::{signal, SignalKind}; +use tokio::signal::unix::{SignalKind, signal}; use tokio::sync::Mutex; use crate::server::CURRENT_MC_VERSION; -use pumpkin::{init_log, stop_server, PumpkinServer, SHOULD_STOP}; +use pumpkin::{PumpkinServer, SHOULD_STOP, init_log, stop_server}; use pumpkin_protocol::CURRENT_MC_PROTOCOL; -use pumpkin_util::text::{color::NamedColor, TextComponent}; +use pumpkin_util::text::{TextComponent, color::NamedColor}; use std::time::Instant; // Setup some tokens to allow us to identify which event is for which socket. @@ -88,7 +88,9 @@ async fn main() { std::process::exit(1); })); - log::info!("Starting Pumpkin {CARGO_PKG_VERSION} ({GIT_VERSION}) for Minecraft {CURRENT_MC_VERSION} (Protocol {CURRENT_MC_PROTOCOL})",); + log::info!( + "Starting Pumpkin {CARGO_PKG_VERSION} ({GIT_VERSION}) for Minecraft {CURRENT_MC_VERSION} (Protocol {CURRENT_MC_PROTOCOL})", + ); log::debug!( "Build info: FAMILY: \"{}\", OS: \"{}\", ARCH: \"{}\", BUILD: \"{}\"", diff --git a/pumpkin/src/net/authentication.rs b/pumpkin/src/net/authentication.rs index ba871c9c1..7623d2019 100644 --- a/pumpkin/src/net/authentication.rs +++ b/pumpkin/src/net/authentication.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, net::IpAddr}; -use base64::{engine::general_purpose, Engine}; -use pumpkin_config::{networking::auth::TextureConfig, ADVANCED_CONFIG}; +use base64::{Engine, engine::general_purpose}; +use pumpkin_config::{ADVANCED_CONFIG, networking::auth::TextureConfig}; use pumpkin_protocol::Property; use reqwest::{StatusCode, Url}; use serde::Deserialize; diff --git a/pumpkin/src/net/container.rs b/pumpkin/src/net/container.rs index 2746642e4..ebe339bb0 100644 --- a/pumpkin/src/net/container.rs +++ b/pumpkin/src/net/container.rs @@ -2,13 +2,14 @@ use crate::entity::player::Player; use crate::server::Server; use pumpkin_data::item::Item; use pumpkin_data::screen::WindowType; +use pumpkin_inventory::Container; use pumpkin_inventory::container_click::{ - Click, ClickType, KeyClick, MouseClick, MouseDragState, MouseDragType, + Click, ClickType, DropType, KeyClick, MouseClick, MouseDragState, MouseDragType, }; use pumpkin_inventory::drag_handler::DragHandler; +use pumpkin_inventory::player::{SLOT_BOOT, SLOT_CHEST, SLOT_HELM, SLOT_HOTBAR_START, SLOT_LEG}; use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait}; -use pumpkin_inventory::Container; -use pumpkin_inventory::{container_click, InventoryError, OptionallyCombinedContainer}; +use pumpkin_inventory::{InventoryError, OptionallyCombinedContainer, container_click}; use pumpkin_protocol::client::play::{ CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot, }; @@ -16,14 +17,15 @@ use pumpkin_protocol::codec::slot::Slot; use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::server::play::SClickContainer; use pumpkin_util::text::TextComponent; -use pumpkin_util::GameMode; +use pumpkin_util::{GameMode, MutableSplitSlice}; use pumpkin_world::item::ItemStack; use std::sync::Arc; impl Player { pub async fn open_container(&self, server: &Server, window_type: WindowType) { let mut inventory = self.inventory().lock().await; - inventory.state_id = 0; + //inventory.state_id = 0; + inventory.increment_state_id(); inventory.total_opened_containers += 1; let mut container = self.get_open_container(server).await; let mut container = match container.as_mut() { @@ -65,13 +67,12 @@ impl Player { .map(Slot::from) .collect(); - let carried_item = self - .carried_item - .load() + let carried_item = self.carried_item.lock().await; + let carried_item = carried_item .as_ref() .map_or_else(Slot::empty, std::convert::Into::into); - inventory.state_id += 1; + inventory.increment_state_id(); let packet = CSetContainerContent::new( id.into(), (inventory.state_id).into(), @@ -142,7 +143,7 @@ impl Player { let combined = OptionallyCombinedContainer::new(&mut inventory, opened_container.as_deref_mut()); ( - combined.crafted_item_slot(), + combined.crafted_item_slot().cloned(), combined.crafting_output_slot(), ) }; @@ -157,6 +158,7 @@ impl Player { let click_slot = click.slot; self.match_click_behaviour( + server, opened_container.as_deref_mut(), click, drag_handler, @@ -219,6 +221,7 @@ impl Player { async fn match_click_behaviour( &self, + server: &Server, opened_container: Option<&mut Box>, click: Click, drag_handler: &DragHandler, @@ -228,6 +231,7 @@ impl Player { match click.click_type { ClickType::MouseClick(mouse_click) => { self.mouse_click( + server, opened_container, mouse_click, click.slot, @@ -273,8 +277,34 @@ impl Player { self.mouse_drag(drag_handler, opened_container, drag_state) .await } - ClickType::DropType(_drop_type) => { - log::debug!("todo"); + ClickType::DropType(drop_type) => { + if let container_click::Slot::Normal(slot) = click.slot { + let mut inventory = self.inventory().lock().await; + let mut container = + OptionallyCombinedContainer::new(&mut inventory, opened_container); + let slots = container.all_slots(); + + if let Some(item_stack) = slots[slot].as_mut() { + match drop_type { + DropType::FullStack => { + self.drop_item( + server, + item_stack.item.id, + u32::from(item_stack.item_count), + ) + .await; + *slots[slot] = None; + } + DropType::SingleItem => { + self.drop_item(server, item_stack.item.id, 1).await; + item_stack.item_count -= 1; + if item_stack.item_count == 0 { + *slots[slot] = None; + } + } + } + } + } Ok(()) } } @@ -282,6 +312,7 @@ impl Player { async fn mouse_click( &self, + server: &Server, opened_container: Option<&mut Box>, mouse_click: MouseClick, slot: container_click::Slot, @@ -289,61 +320,154 @@ impl Player { ) -> Result<(), InventoryError> { let mut inventory = self.inventory().lock().await; let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); + let mut carried_item = self.carried_item.lock().await; match slot { container_click::Slot::Normal(slot) => { - let mut carried_item = self.carried_item.load(); - let res = container.handle_item_change( - &mut carried_item, - slot, - mouse_click, - taking_crafted, - ); - self.carried_item.store(carried_item); - res + container.handle_item_change(&mut carried_item, slot, mouse_click, taking_crafted) + } + container_click::Slot::OutsideInventory => { + if let Some(item_stack) = carried_item.as_mut() { + match mouse_click { + MouseClick::Left => { + self.drop_item( + server, + item_stack.item.id, + u32::from(item_stack.item_count), + ) + .await; + *carried_item = None; + } + MouseClick::Right => { + self.drop_item(server, item_stack.item.id, 1).await; + item_stack.item_count -= 1; + if item_stack.item_count == 0 { + *carried_item = None; + } + } + }; + } + Ok(()) } - container_click::Slot::OutsideInventory => Ok(()), } } + /// TODO: Allow equiping/de equiping armor and allow taking items from crafting grid async fn shift_mouse_click( &self, opened_container: Option<&mut Box>, slot: container_click::Slot, - taking_crafted: bool, + _taking_crafted: bool, ) -> Result<(), InventoryError> { let mut inventory = self.inventory().lock().await; + let has_container = opened_container.is_some(); + let container_size = opened_container + .as_ref() + .map_or(0, |c| c.all_slots_ref().len()); let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); match slot { container_click::Slot::Normal(slot) => { - let all_slots = container.all_slots(); - if let Some(item_in_pressed_slot) = all_slots[slot].to_owned() { - let slots = all_slots.into_iter().enumerate(); - // Hotbar - let find_condition = |(slot_number, slot): (usize, &mut Option)| { - // TODO: Check for max item count here - match slot { - Some(item) => (item.item.id == item_in_pressed_slot.item.id - && item.item_count != 64) - .then_some(slot_number), - None => Some(slot_number), - } - }; + let mut all_slots = container.all_slots(); + let (item_stack, mut split_slice) = + MutableSplitSlice::extract_ith(&mut all_slots, slot); + let Some(clicked_item_stack) = item_stack else { + return Ok(()); + }; - let slots = if slot > 35 { - slots.skip(9).find_map(find_condition) + // Define the two inventories and determine which one contains the source slot + let (inv1_range, inv2_range) = if has_container { + // When container is open: + // Inv1 = Container slots (0 to container_size-1) + // Inv2 = Player inventory (container_size to end) + ((0..container_size), (container_size..split_slice.len())) + } else { + // When no container: + // Inv1 = Hotbar (36-45) + // Inv2 = Main inventory (9-36) + ((36..45), (9..36)) + }; + + // Determine which inventory we're moving from and to + let (source_inv, target_inv) = if inv1_range.contains(&slot) { + (&inv1_range, &inv2_range) + } else if inv2_range.contains(&slot) { + (&inv2_range, &inv1_range) + } else { + // When moving from top slots to inventory + (&(0..9), &(9..45)) + }; + + // If moving to hotbar, reverse the order to fill from right to left + let target_slots: Vec = + if has_container && source_inv.contains(&slot) && source_inv == &inv1_range { + target_inv.clone().rev().collect() } else { - slots.skip(36).rev().find_map(find_condition) + target_inv.clone().collect() }; - if let Some(slot) = slots { - let mut item_slot = container.all_slots()[slot].map(|i| i); - container.handle_item_change( - &mut item_slot, - slot, - MouseClick::Left, - taking_crafted, - )?; - *container.all_slots()[slot] = item_slot; + + //Handle armor slots + if !has_container { + let temp_item_stack = ItemStack::new(1, clicked_item_stack.item.clone()); + if slot != SLOT_HELM + && temp_item_stack.is_helmet() + && split_slice[SLOT_HELM].is_none() + { + *split_slice[SLOT_HELM] = Some(temp_item_stack); + **item_stack = None; + return Ok(()); + } else if slot != SLOT_CHEST + && temp_item_stack.is_chestplate() + && split_slice[SLOT_CHEST].is_none() + { + *split_slice[SLOT_CHEST] = Some(temp_item_stack); + **item_stack = None; + return Ok(()); + } else if slot != SLOT_LEG + && temp_item_stack.is_leggings() + && split_slice[SLOT_LEG].is_none() + { + *split_slice[SLOT_LEG] = Some(temp_item_stack); + **item_stack = None; + return Ok(()); + } else if slot != SLOT_BOOT + && temp_item_stack.is_boots() + && split_slice[SLOT_BOOT].is_none() + { + *split_slice[SLOT_BOOT] = Some(temp_item_stack); + **item_stack = None; + return Ok(()); + } + } + + // First try to stack with existing items + let max_stack_size = clicked_item_stack.item.components.max_stack_size; + for target_idx in &target_slots { + if let Some(target_item) = split_slice[*target_idx].as_mut() { + if target_item.item.id == clicked_item_stack.item.id + && target_item.item_count < max_stack_size + { + let space_in_stack = max_stack_size - target_item.item_count; + let amount_to_add = clicked_item_stack.item_count.min(space_in_stack); + target_item.item_count += amount_to_add; + clicked_item_stack.item_count -= amount_to_add; + + if clicked_item_stack.item_count == 0 { + **item_stack = None; + return Ok(()); + } + } + } + } + + // Then try to place in empty slots + for target_idx in target_slots { + if split_slice[target_idx].is_none() + || split_slice[target_idx] + .as_ref() + .is_some_and(|item| item.item_count == 0) + { + std::mem::swap(split_slice[target_idx], *item_stack); + return Ok(()); } } } @@ -360,11 +484,11 @@ impl Player { taking_crafted: bool, ) -> Result<(), InventoryError> { let changing_slot = match key_click { - KeyClick::Slot(slot) => slot, + KeyClick::Slot(slot) => slot as usize + SLOT_HOTBAR_START, KeyClick::Offhand => 45, }; let mut inventory = self.inventory().lock().await; - let mut changing_item_slot = inventory.get_slot(changing_slot as usize)?.to_owned(); + let mut changing_item_slot = inventory.get_slot(changing_slot)?.clone(); let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); container.handle_item_change( @@ -373,7 +497,7 @@ impl Player { MouseClick::Left, taking_crafted, )?; - *inventory.get_slot(changing_slot as usize)? = changing_item_slot; + *inventory.get_slot(changing_slot)? = changing_item_slot; Ok(()) } @@ -388,7 +512,8 @@ impl Player { let mut inventory = self.inventory().lock().await; let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); if let Some(Some(item)) = container.all_slots().get_mut(slot) { - self.carried_item.store(Some(item.to_owned())); + let mut carried_item = self.carried_item.lock().await; + *carried_item = Some(item.clone()); } Ok(()) } @@ -396,38 +521,38 @@ impl Player { async fn double_click( &self, opened_container: Option<&mut Box>, - slot: usize, + _slot: usize, ) -> Result<(), InventoryError> { let mut inventory = self.inventory().lock().await; let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); - let mut slots = container.all_slots(); - - let Some(item) = slots.get_mut(slot) else { - return Ok(()); - }; - let Some(mut carried_item) = **item else { + let mut carried_item = self.carried_item.lock().await; + let Some(carried_item) = carried_item.as_mut() else { return Ok(()); }; - **item = None; - - for slot in slots.iter_mut().filter_map(|slot| slot.as_mut()) { - if slot.item.id == carried_item.item.id { - // TODO: Check for max stack size - if slot.item_count + carried_item.item_count <= 64 { - slot.item_count = 0; - carried_item.item_count = 64; - } else { - let to_remove = slot.item_count - (64 - carried_item.item_count); - slot.item_count -= to_remove; - carried_item.item_count += to_remove; - } - if carried_item.item_count == 64 { - break; + // Iterate directly over container slots to modify them in place' + for slot in container.all_slots() { + if let Some(itemstack) = slot { + if itemstack.item.id == carried_item.item.id { + if itemstack.item_count + carried_item.item_count + <= carried_item.item.components.max_stack_size + { + carried_item.item_count += itemstack.item_count; + *slot = None; + } else { + let overflow = itemstack.item_count + - (carried_item.item.components.max_stack_size + - carried_item.item_count); + carried_item.item_count = carried_item.item.components.max_stack_size; + itemstack.item_count = overflow; + } + + if carried_item.item_count == carried_item.item.components.max_stack_size { + break; + } } } } - self.carried_item.store(Some(carried_item)); Ok(()) } @@ -460,12 +585,10 @@ impl Player { let mut inventory = self.inventory().lock().await; let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container); - let mut carried_item = self.carried_item.load(); - let res = drag_handler + let mut carried_item = self.carried_item.lock().await; + drag_handler .apply_drag(&mut carried_item, &mut container, &container_id, player_id) - .await; - self.carried_item.store(carried_item); - res + .await } } } @@ -519,7 +642,7 @@ impl Player { let total_opened_containers = inventory.total_opened_containers; // Returns previous value - inventory.state_id += 1; + inventory.increment_state_id(); let packet = CSetContainerSlot::new( total_opened_containers as i8, (inventory.state_id) as i32, @@ -555,63 +678,47 @@ impl Player { } } - async fn pickup_items(&self, item: Item, mut amount: u32) { + // TODO: Use this method when actually picking up items instead of just the command + async fn pickup_items(&self, item: Item, amount: u32) { + let mut amount_left = amount; let max_stack = item.components.max_stack_size; let mut inventory = self.inventory().lock().await; - let slots = inventory.slots_with_hotbar_first(); - - let matching_slots = slots.filter_map(|slot| { - if let Some(item_slot) = slot.as_mut() { - (item_slot.item.id == item.id && item_slot.item_count < max_stack).then(|| { - let item_count = item_slot.item_count; - (item_slot, item_count) - }) - } else { - None - } - }); - for (slot, item_count) in matching_slots { - if amount == 0 { - return; - } - let amount_to_add = max_stack - item_count; - if let Some(amount_left) = amount.checked_sub(u32::from(amount_to_add)) { - amount = amount_left; - *slot = ItemStack { - item, - item_count: item.components.max_stack_size, - }; - } else { - *slot = ItemStack { - item, - item_count: max_stack - (amount_to_add - amount as u8), - }; - return; - } - } + while let Some(slot) = inventory.get_pickup_item_slot(item.id) { + let item_stack = inventory + .get_slot(slot) + .expect("We just called a method that said this was a valid slot"); - let empty_slots = inventory - .slots_with_hotbar_first() - .filter(|slot| slot.is_none()); - for slot in empty_slots { - if amount == 0 { - return; - } - if let Some(remaining_amount) = amount.checked_sub(u32::from(max_stack)) { - amount = remaining_amount; - *slot = Some(ItemStack { - item, + if let Some(item_stack) = item_stack { + let amount_to_add = max_stack - item_stack.item_count; + if let Some(new_amount_left) = amount_left.checked_sub(u32::from(amount_to_add)) { + item_stack.item_count = max_stack; + amount_left = new_amount_left; + } else { + // This is safe because amount left is less than amount_to_add which is a u8 + item_stack.item_count = max_stack - (amount_to_add - amount_left as u8); + // Return here because if we have less than the max amount left then the whole + // stack will be moved + return; + } + } else if let Some(new_amount_left) = amount_left.checked_sub(u32::from(max_stack)) { + *item_stack = Some(ItemStack { + item: item.clone(), item_count: max_stack, }); + amount_left = new_amount_left; } else { - *slot = Some(ItemStack { - item, - item_count: amount as u8, + *item_stack = Some(ItemStack { + item: item.clone(), + // This is safe because amount left is less than max_stack which is a u8 + item_count: amount_left as u8, }); + // Return here because if we have less than the max amount left then the whole + // stack will be moved return; } } + log::warn!( "{amount} items were discarded because dropping them to the ground is not implemented" ); diff --git a/pumpkin/src/net/lan_broadcast.rs b/pumpkin/src/net/lan_broadcast.rs index 187fd4313..9f02635f8 100644 --- a/pumpkin/src/net/lan_broadcast.rs +++ b/pumpkin/src/net/lan_broadcast.rs @@ -30,7 +30,9 @@ pub async fn start_lan_broadcast(bound_addr: SocketAddr) { if advanced_motd.is_empty() { motd = BASIC_CONFIG.motd.replace('\n', " "); - log::warn!("Using the server MOTD as the LAN broadcast MOTD. Note that the LAN broadcast MOTD does not support multiple lines, RGB colors, or gradients so consider defining it accordingly."); + log::warn!( + "Using the server MOTD as the LAN broadcast MOTD. Note that the LAN broadcast MOTD does not support multiple lines, RGB colors, or gradients so consider defining it accordingly." + ); } else { motd = advanced_motd.clone(); }; diff --git a/pumpkin/src/net/mod.rs b/pumpkin/src/net/mod.rs index 6ad287e42..fc3641846 100644 --- a/pumpkin/src/net/mod.rs +++ b/pumpkin/src/net/mod.rs @@ -3,8 +3,8 @@ use std::{ net::SocketAddr, num::NonZeroU8, sync::{ - atomic::{AtomicBool, AtomicI32}, Arc, + atomic::{AtomicBool, AtomicI32}, }, }; @@ -17,14 +17,16 @@ use crate::{ use crossbeam::atomic::AtomicCell; use pumpkin_config::networking::compression::CompressionInfo; use pumpkin_protocol::{ - bytebuf::{packet::Packet, ReadingError}, + ClientPacket, CompressionLevel, CompressionThreshold, ConnectionState, Property, RawPacket, + ServerPacket, + bytebuf::{ReadingError, packet::Packet}, client::{config::CConfigDisconnect, login::CLoginDisconnect, play::CPlayDisconnect}, packet_decoder::PacketDecoder, packet_encoder::{PacketEncodeError, PacketEncoder}, server::{ config::{ - SAcknowledgeFinishConfig, SClientInformationConfig, SConfigCookieResponse, SKnownPacks, - SPluginMessage, + SAcknowledgeFinishConfig, SClientInformationConfig, SConfigCookieResponse, + SConfigResourcePack, SKnownPacks, SPluginMessage, }, handshake::SHandShake, login::{ @@ -33,15 +35,13 @@ use pumpkin_protocol::{ }, status::{SStatusPingRequest, SStatusRequest}, }, - ClientPacket, CompressionLevel, CompressionThreshold, ConnectionState, Property, RawPacket, - ServerPacket, }; -use pumpkin_util::{text::TextComponent, ProfileAction}; +use pumpkin_util::{ProfileAction, text::TextComponent}; use serde::Deserialize; use sha1::Digest; use sha2::Sha256; -use tokio::sync::mpsc; use tokio::sync::Mutex; +use tokio::sync::mpsc; use thiserror::Error; use uuid::Uuid; @@ -252,10 +252,12 @@ impl Client { return; } - let mut enc = self.enc.lock().await; - if let Err(error) = enc.append_packet(packet) { - self.kick(&TextComponent::text(error.to_string())).await; - return; + { + let mut enc = self.enc.lock().await; + if let Err(error) = enc.append_packet(packet) { + self.kick(TextComponent::text(error.to_string())).await; + return; + } } let _ = self @@ -352,7 +354,7 @@ impl Client { i32::from(packet.id), error ); - self.kick(&TextComponent::text(text)).await; + self.kick(TextComponent::text(text)).await; }; } } @@ -475,7 +477,7 @@ impl Client { self.handle_login_acknowledged(server).await; } SLoginCookieResponse::PACKET_ID => { - self.handle_login_cookie_response(SLoginCookieResponse::read(bytebuf)?); + self.handle_login_cookie_response(&SLoginCookieResponse::read(bytebuf)?); } _ => { log::error!( @@ -511,7 +513,11 @@ impl Client { .await; } SConfigCookieResponse::PACKET_ID => { - self.handle_config_cookie_response(SConfigCookieResponse::read(bytebuf)?); + self.handle_config_cookie_response(&SConfigCookieResponse::read(bytebuf)?); + } + SConfigResourcePack::PACKET_ID => { + self.handle_resource_pack_response(SConfigResourcePack::read(bytebuf)?) + .await; } _ => { log::error!( @@ -530,9 +536,7 @@ impl Client { /// # Arguments /// /// * `reason`: A string describing the reason for kicking the client. - pub async fn kick(&self, reason: &TextComponent) { - let text = reason.clone().get_text(); - log::info!("Kicking Client id {} for {}", self.id, &text); + pub async fn kick(&self, reason: TextComponent) { let result = match self.connection_state.load() { ConnectionState::Login => { // TextComponent implements Serialze and writes in bytes instead of String, thats the reasib we only use content @@ -541,7 +545,10 @@ impl Client { )) .await } - ConnectionState::Config => self.try_send_packet(&CConfigDisconnect::new(&text)).await, + ConnectionState::Config => { + self.try_send_packet(&CConfigDisconnect::new(&reason.get_text())) + .await + } // This way players get kicked when players using client functions (e.g. poll, send_packet) ConnectionState::Play => self.try_send_packet(&CPlayDisconnect::new(reason)).await, _ => { diff --git a/pumpkin/src/net/packet/config.rs b/pumpkin/src/net/packet/config.rs index 4e1817aa5..ec50d1aa2 100644 --- a/pumpkin/src/net/packet/config.rs +++ b/pumpkin/src/net/packet/config.rs @@ -6,13 +6,15 @@ use crate::{ server::Server, }; use core::str; +use pumpkin_config::ADVANCED_CONFIG; use pumpkin_protocol::{ + ConnectionState, client::config::{CFinishConfig, CRegistryData}, codec::var_int::VarInt, server::config::{ - SClientInformationConfig, SConfigCookieResponse, SKnownPacks, SPluginMessage, + ResourcePackResponseResult, SClientInformationConfig, SConfigCookieResponse, + SConfigResourcePack, SKnownPacks, SPluginMessage, }, - ConnectionState, }; use pumpkin_util::text::TextComponent; @@ -23,7 +25,7 @@ impl Client { ) { log::debug!("Handling client settings"); if client_information.view_distance <= 0 { - self.kick(&TextComponent::text( + self.kick(TextComponent::text( "Cannot have zero or negative view distance!", )) .await; @@ -47,7 +49,7 @@ impl Client { server_listing: client_information.server_listing, }); } else { - self.kick(&TextComponent::text("Invalid hand or chat type")) + self.kick(TextComponent::text("Invalid hand or chat type")) .await; } } @@ -62,12 +64,79 @@ impl Client { log::debug!("got a client brand"); match str::from_utf8(&plugin_message.data) { Ok(brand) => *self.brand.lock().await = Some(brand.to_string()), - Err(e) => self.kick(&TextComponent::text(e.to_string())).await, + Err(e) => self.kick(TextComponent::text(e.to_string())).await, } } } - pub fn handle_config_cookie_response(&self, packet: SConfigCookieResponse) { + pub async fn handle_resource_pack_response(&self, packet: SConfigResourcePack) { + let resource_config = &ADVANCED_CONFIG.resource_pack; + if resource_config.enabled { + let expected_uuid = + uuid::Uuid::new_v3(&uuid::Uuid::NAMESPACE_DNS, resource_config.url.as_bytes()); + + if packet.uuid == expected_uuid { + match packet.response_result() { + ResourcePackResponseResult::DownloadSuccess => { + log::trace!( + "Client {} successfully downloaded the resource pack", + self.id + ); + } + ResourcePackResponseResult::DownloadFail => { + log::warn!( + "Client {} failed to downloaded the resource pack. Is it available on the internet?", + self.id + ); + } + ResourcePackResponseResult::Downloaded => { + log::trace!("Client {} already has the resource pack", self.id); + } + ResourcePackResponseResult::Accepted => { + log::trace!("Client {} accepted the resource pack", self.id); + + // Return here to wait for the next response update + return; + } + ResourcePackResponseResult::Declined => { + log::trace!("Client {} declined the resource pack", self.id); + } + ResourcePackResponseResult::InvalidUrl => { + log::warn!( + "Client {} reported that the resource pack url is invalid!", + self.id + ); + } + ResourcePackResponseResult::ReloadFailed => { + log::trace!("Client {} failed to reload the resource pack", self.id); + } + ResourcePackResponseResult::Discarded => { + log::trace!("Client {} discarded the resource pack", self.id); + } + ResourcePackResponseResult::Unknown(result) => { + log::warn!( + "Client {} responded with a bad result: {}!", + self.id, + result + ); + } + } + } else { + log::warn!( + "Client {} returned a response for a resource pack we did not set!", + self.id + ); + } + } else { + log::warn!( + "Client {} returned a response for a resource pack that was not enabled!", + self.id + ); + } + self.send_known_packs().await; + } + + pub fn handle_config_cookie_response(&self, packet: &SConfigCookieResponse) { // TODO: allow plugins to access this log::debug!( "Received cookie_response[config]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", @@ -89,7 +158,7 @@ impl Client { // We are done with configuring log::debug!("finished config"); - self.send_packet(&CFinishConfig::new()).await; + self.send_packet(&CFinishConfig).await; } pub async fn handle_config_acknowledged(&self) { @@ -97,7 +166,7 @@ impl Client { self.connection_state.store(ConnectionState::Play); if let Some(reason) = self.can_not_join().await { - self.kick(&reason).await; + self.kick(reason).await; return; } diff --git a/pumpkin/src/net/packet/handshake.rs b/pumpkin/src/net/packet/handshake.rs index a49a4ed55..569ae362b 100644 --- a/pumpkin/src/net/packet/handshake.rs +++ b/pumpkin/src/net/packet/handshake.rs @@ -1,6 +1,6 @@ use std::num::NonZeroI32; -use pumpkin_protocol::{server::handshake::SHandShake, ConnectionState, CURRENT_MC_PROTOCOL}; +use pumpkin_protocol::{CURRENT_MC_PROTOCOL, ConnectionState, server::handshake::SHandShake}; use pumpkin_util::text::TextComponent; use crate::{net::Client, server::CURRENT_MC_VERSION}; @@ -18,7 +18,7 @@ impl Client { let protocol = version; match protocol.cmp(&NonZeroI32::from(CURRENT_MC_PROTOCOL).get()) { std::cmp::Ordering::Less => { - self.kick(&TextComponent::translate( + self.kick(TextComponent::translate( "multiplayer.disconnect.outdated_client", [TextComponent::text(CURRENT_MC_VERSION.to_string())], )) @@ -26,7 +26,7 @@ impl Client { } std::cmp::Ordering::Equal => {} std::cmp::Ordering::Greater => { - self.kick(&TextComponent::translate( + self.kick(TextComponent::translate( "multiplayer.disconnect.incompatible", [TextComponent::text(CURRENT_MC_VERSION.to_string())], )) diff --git a/pumpkin/src/net/packet/login.rs b/pumpkin/src/net/packet/login.rs index 511a8e9c0..34535b3ba 100644 --- a/pumpkin/src/net/packet/login.rs +++ b/pumpkin/src/net/packet/login.rs @@ -2,24 +2,24 @@ use std::sync::LazyLock; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_protocol::{ + ConnectionState, KnownPack, Label, Link, LinkType, client::{ config::{CConfigAddResourcePack, CConfigServerLinks, CKnownPacks, CUpdateTags}, login::{CLoginSuccess, CSetCompression}, }, codec::var_int::VarInt, server::login::{SEncryptionResponse, SLoginCookieResponse, SLoginPluginResponse, SLoginStart}, - ConnectionState, KnownPack, Label, Link, LinkType, }; use pumpkin_util::text::TextComponent; use uuid::Uuid; use crate::{ net::{ + Client, GameProfile, authentication::{self, AuthError}, offline_uuid, packet::is_valid_player_name, proxy::{bungeecord, velocity}, - Client, GameProfile, }, server::Server, }; @@ -93,7 +93,7 @@ impl Client { // TODO: If client is an operator or otherwise suitable elevated permissions, allow client to bypass this requirement. let max_players = BASIC_CONFIG.max_players; if max_players > 0 && server.get_player_count().await >= max_players as usize { - self.kick(&TextComponent::translate( + self.kick(TextComponent::translate( "multiplayer.disconnect.server_full", [], )) @@ -102,7 +102,7 @@ impl Client { } if !is_valid_player_name(&login_start.name) { - self.kick(&TextComponent::text("Invalid characters in username")) + self.kick(TextComponent::text("Invalid characters in username")) .await; return; } @@ -126,7 +126,7 @@ impl Client { self.finish_login(&profile).await; *gameprofile = Some(profile); } - Err(error) => self.kick(&TextComponent::text(error.to_string())).await, + Err(error) => self.kick(TextComponent::text(error.to_string())).await, } } } else { @@ -169,14 +169,14 @@ impl Client { let shared_secret = server.decrypt(&encryption_response.shared_secret).unwrap(); if let Err(error) = self.set_encryption(Some(&shared_secret)).await { - self.kick(&TextComponent::text(error.to_string())).await; + self.kick(TextComponent::text(error.to_string())).await; return; } let mut gameprofile = self.gameprofile.lock().await; let Some(profile) = gameprofile.as_mut() else { - self.kick(&TextComponent::text("No Game profile")).await; + self.kick(TextComponent::text("No Game profile")).await; return; }; @@ -188,7 +188,7 @@ impl Client { { Ok(new_profile) => *profile = new_profile, Err(error) => { - self.kick(&match error { + self.kick(match error { AuthError::FailedResponse => { TextComponent::translate("multiplayer.disconnect.authservers_down", []) } @@ -205,8 +205,15 @@ impl Client { // Don't allow duplicate UUIDs if let Some(online_player) = &server.get_player_by_uuid(profile.id).await { - log::debug!("Player (IP '{}', username '{}') tried to log in with the same UUID ('{}') as an online player (IP '{}', username '{}')", &self.address.lock().await, &profile.name, &profile.id, &online_player.client.address.lock().await, &online_player.gameprofile.name); - self.kick(&TextComponent::translate( + log::debug!( + "Player (IP '{}', username '{}') tried to log in with the same UUID ('{}') as an online player (IP '{}', username '{}')", + &self.address.lock().await, + &profile.name, + &profile.id, + &online_player.client.address.lock().await, + &online_player.gameprofile.name + ); + self.kick(TextComponent::translate( "multiplayer.disconnect.duplicate_login", [], )) @@ -216,8 +223,15 @@ impl Client { // Don't allow a duplicate username if let Some(online_player) = &server.get_player_by_name(&profile.name).await { - log::debug!("A player (IP '{}', attempted username '{}') tried to log in with the same username as an online player (UUID '{}', IP '{}', username '{}')", &self.address.lock().await, &profile.name, &profile.id, &online_player.client.address.lock().await, &online_player.gameprofile.name); - self.kick(&TextComponent::translate( + log::debug!( + "A player (IP '{}', attempted username '{}') tried to log in with the same username as an online player (UUID '{}', IP '{}', username '{}')", + &self.address.lock().await, + &profile.name, + &profile.id, + &online_player.client.address.lock().await, + &online_player.gameprofile.name + ); + self.kick(TextComponent::translate( "multiplayer.disconnect.duplicate_login", [], )) @@ -292,14 +306,14 @@ impl Client { Err(AuthError::MissingAuthClient) } - pub fn handle_login_cookie_response(&self, packet: SLoginCookieResponse) { + pub fn handle_login_cookie_response(&self, packet: &SLoginCookieResponse) { // TODO: allow plugins to access this log::debug!( - "Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", - packet.key.to_string(), - packet.has_payload, - packet.payload_length.unwrap_or(VarInt::from(0)).0 - ); + "Received cookie_response[login]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", + packet.key.to_string(), + packet.has_payload, + packet.payload_length.unwrap_or(VarInt::from(0)).0 + ); } pub async fn handle_plugin_response(&self, plugin_response: SLoginPluginResponse) { log::debug!("Handling plugin"); @@ -316,7 +330,7 @@ impl Client { *self.gameprofile.lock().await = Some(profile); *address = new_address; } - Err(error) => self.kick(&TextComponent::text(error.to_string())).await, + Err(error) => self.kick(TextComponent::text(error.to_string())).await, } } } @@ -326,23 +340,6 @@ impl Client { self.connection_state.store(ConnectionState::Config); self.send_packet(&server.get_branding()).await; - let resource_config = &ADVANCED_CONFIG.resource_pack; - if resource_config.enabled { - let resource_pack = CConfigAddResourcePack::new( - Uuid::new_v3(&uuid::Uuid::NAMESPACE_DNS, resource_config.url.as_bytes()), - &resource_config.url, - &resource_config.sha1, - resource_config.force, - if resource_config.message.is_empty() { - None - } else { - Some(TextComponent::text(&resource_config.message)) - }, - ); - - self.send_packet(&resource_pack).await; - } - if ADVANCED_CONFIG.server_links.enabled { self.send_packet(&CConfigServerLinks::new( &VarInt(LINKS.len() as i32), @@ -359,6 +356,30 @@ impl Client { ])) .await; + let resource_config = &ADVANCED_CONFIG.resource_pack; + if resource_config.enabled { + let uuid = Uuid::new_v3(&uuid::Uuid::NAMESPACE_DNS, resource_config.url.as_bytes()); + let resource_pack = CConfigAddResourcePack::new( + &uuid, + &resource_config.url, + &resource_config.sha1, + resource_config.force, + if resource_config.prompt_message.is_empty() { + None + } else { + Some(TextComponent::text(&resource_config.prompt_message)) + }, + ); + + self.send_packet(&resource_pack).await; + } else { + // This will be invoked by our resource pack handler in the case of the above branch + self.send_known_packs().await; + } + log::debug!("login acknowledged"); + } + + pub async fn send_known_packs(&self) { // known data packs self.send_packet(&CKnownPacks::new(&[KnownPack { namespace: "minecraft", @@ -366,6 +387,5 @@ impl Client { version: "1.21", }])) .await; - log::debug!("login acknowledged"); } } diff --git a/pumpkin/src/net/packet/play.rs b/pumpkin/src/net/packet/play.rs index c71f377e0..19eb946c8 100644 --- a/pumpkin/src/net/packet/play.rs +++ b/pumpkin/src/net/packet/play.rs @@ -14,13 +14,15 @@ use crate::{ world::chunker, }; use pumpkin_config::ADVANCED_CONFIG; -use pumpkin_data::entity::{entity_from_egg, EntityType}; +use pumpkin_data::entity::{EntityType, entity_from_egg}; use pumpkin_data::item::Item; use pumpkin_data::sound::Sound; use pumpkin_data::sound::SoundCategory; use pumpkin_data::world::CHAT; -use pumpkin_inventory::player::PlayerInventory; use pumpkin_inventory::InventoryError; +use pumpkin_inventory::player::{ + PlayerInventory, SLOT_HOTBAR_END, SLOT_HOTBAR_START, SLOT_OFFHAND, +}; use pumpkin_macros::block_entity; use pumpkin_protocol::client::play::{ CBlockEntityData, COpenSignEditor, CSetContainerSlot, CSetHeldItem, EquipmentSlot, @@ -45,14 +47,14 @@ use pumpkin_util::math::boundingbox::BoundingBox; use pumpkin_util::math::position::BlockPos; use pumpkin_util::text::color::NamedColor; use pumpkin_util::{ + GameMode, math::{vector3::Vector3, wrap_degrees}, text::TextComponent, - GameMode, }; use pumpkin_world::block::interactive::sign::Sign; -use pumpkin_world::block::registry::get_block_collision_shapes; use pumpkin_world::block::registry::Block; -use pumpkin_world::block::{registry::get_block_by_item, BlockDirection}; +use pumpkin_world::block::registry::get_block_collision_shapes; +use pumpkin_world::block::{BlockDirection, registry::get_block_by_item}; use pumpkin_world::item::ItemStack; use pumpkin_world::{WORLD_LOWEST_Y, WORLD_MAX_Y}; @@ -395,19 +397,22 @@ impl Player { pub async fn update_single_slot( &self, - inventory: &mut tokio::sync::MutexGuard<'_, PlayerInventory>, - slot: i16, - slot_data: Slot, + inventory: &mut PlayerInventory, + slot: usize, + stack: ItemStack, ) { - inventory.state_id += 1; - let dest_packet = CSetContainerSlot::new(0, inventory.state_id as i32, slot, &slot_data); - self.client.send_packet(&dest_packet).await; - - if inventory - .set_slot(slot as usize, slot_data.to_item(), false) - .is_err() - { - log::error!("Pick item set slot error!"); + inventory.increment_state_id(); + let slot_data = Slot::from(&stack); + if let Err(err) = inventory.set_slot(slot, Some(stack), false) { + log::error!("Pick item set slot error: {}", err); + } else { + let dest_packet = CSetContainerSlot::new( + PlayerInventory::CONTAINER_ID, + inventory.state_id as i32, + slot as i16, + &slot_data, + ); + self.client.send_packet(&dest_packet).await; } } @@ -428,13 +433,12 @@ impl Player { let mut inventory = self.inventory().lock().await; - // TODO: Max stack - let source_slot = inventory.get_slot_with_item(block.item_id, 64); - let mut dest_slot = inventory.get_empty_hotbar_slot() as usize; + let source_slot = inventory.get_slot_with_item(block.item_id); + let mut dest_slot = inventory.get_empty_hotbar_slot(); - let dest_slot_data = match inventory.get_slot(dest_slot + 36) { - Ok(Some(stack)) => Slot::from(&*stack), - _ => Slot::from(None), + let dest_slot_data = match inventory.get_slot(dest_slot + SLOT_HOTBAR_START) { + Ok(Some(stack)) => stack.clone(), + _ => ItemStack::new(0, Item::AIR), }; // Early return if no source slot and not in creative mode @@ -443,36 +447,39 @@ impl Player { } match source_slot { - Some(slot_index) if (36..=44).contains(&slot_index) => { + Some(slot_index) if (SLOT_HOTBAR_START..=SLOT_HOTBAR_END).contains(&slot_index) => { // Case where item is in hotbar - dest_slot = slot_index - 36; + dest_slot = slot_index - SLOT_HOTBAR_START; } Some(slot_index) => { // Case where item is in inventory // Update destination slot let source_slot_data = match inventory.get_slot(slot_index) { - Ok(Some(stack)) => Slot::from(&*stack), + Ok(Some(stack)) => stack.clone(), _ => return, }; - self.update_single_slot(&mut inventory, dest_slot as i16 + 36, source_slot_data) - .await; + self.update_single_slot( + &mut inventory, + dest_slot + SLOT_HOTBAR_START, + source_slot_data, + ) + .await; // Update source slot - self.update_single_slot(&mut inventory, slot_index as i16, dest_slot_data) + self.update_single_slot(&mut inventory, slot_index, dest_slot_data) .await; } None if self.gamemode.load() == GameMode::Creative => { // Case where item is not present, if in creative mode create the item let item_stack = ItemStack::new(1, Item::from_id(block.item_id).unwrap()); - let slot_data = Slot::from(&item_stack); - self.update_single_slot(&mut inventory, dest_slot as i16 + 36, slot_data) + self.update_single_slot(&mut inventory, dest_slot + SLOT_HOTBAR_START, item_stack) .await; // Check if there is any empty slot in the player inventory - if let Some(slot_index) = inventory.get_empty_slot() { - inventory.state_id += 1; - self.update_single_slot(&mut inventory, slot_index as i16, dest_slot_data) + if let Some(slot_index) = inventory.get_empty_slot_no_order() { + inventory.increment_state_id(); + self.update_single_slot(&mut inventory, slot_index, dest_slot_data) .await; } } @@ -480,10 +487,10 @@ impl Player { } // Update held item - inventory.set_selected(dest_slot as u32); + inventory.set_selected(dest_slot); let empty = &ItemStack::new(0, Item::AIR); let stack = inventory.held_item().unwrap_or(empty); - let equipment = &[(EquipmentSlot::MainHand, *stack)]; + let equipment = &[(EquipmentSlot::MainHand, stack.clone())]; self.living_entity.send_equipment_changes(equipment).await; self.client .send_packet(&CSetHeldItem::new(dest_slot as i8)) @@ -929,10 +936,10 @@ impl Player { self.update_sequence(player_action.sequence.0); } Status::DropItem => { - self.drop_item(server, false).await; + self.drop_held_item(server, false).await; } Status::DropItemStack => { - self.drop_item(server, true).await; + self.drop_held_item(server, true).await; } Status::ShootArrowOrFinishEating | Status::SwapItem => { log::debug!("todo"); @@ -1009,19 +1016,18 @@ impl Player { return Err(BlockPlacingError::InvalidBlockFace.into()); }; - let mut inventory = self.inventory().lock().await; - let entity = &self.living_entity.entity; - let world = &entity.world.read().await; - let slot_id = inventory.get_selected(); - let mut state_id = inventory.state_id; - let item_slot = *inventory.held_item_mut(); + let inventory = self.inventory().lock().await; + let slot_id = inventory.get_selected_slot(); + let held_item = inventory.held_item().cloned(); drop(inventory); + let entity = &self.living_entity.entity; + let world = &entity.world.read().await; let Ok(block) = world.get_block(&location).await else { return Err(BlockPlacingError::NoBaseBlock.into()); }; - let Some(stack) = item_slot else { + let Some(stack) = held_item else { if !self .living_entity .entity @@ -1083,6 +1089,7 @@ impl Player { // Decrease Block count if self.gamemode.load() != GameMode::Creative { let mut inventory = self.inventory().lock().await; + if !inventory.decrease_current_stack(1) { return Err(BlockPlacingError::InventoryInvalid.into()); } @@ -1091,8 +1098,8 @@ impl Player { .handle_decrease_item( server, slot_id as i16, - inventory.held_item(), - &mut state_id, + inventory.held_item().cloned().as_ref(), + &mut inventory.state_id, ) .await; } @@ -1141,29 +1148,34 @@ impl Player { return; } let mut inv = self.inventory().lock().await; - inv.set_selected(slot as u32); + inv.set_selected(slot as usize); let empty = &ItemStack::new(0, Item::AIR); let stack = inv.held_item().unwrap_or(empty); - let equipment = &[(EquipmentSlot::MainHand, *stack)]; + let equipment = &[(EquipmentSlot::MainHand, stack.clone())]; self.living_entity.send_equipment_changes(equipment).await; } pub async fn handle_set_creative_slot( &self, + server: &Server, packet: SSetCreativeSlot, ) -> Result<(), InventoryError> { if self.gamemode.load() != GameMode::Creative { return Err(InventoryError::PermissionError); } - let valid_slot = packet.slot >= 0 && packet.slot <= 45; + let valid_slot = packet.slot >= 0 && packet.slot as usize <= SLOT_OFFHAND; + // TODO: Handle error + let item_stack = packet.clicked_item.to_stack().unwrap(); if valid_slot { - self.inventory().lock().await.set_slot( - packet.slot as usize, - packet.clicked_item.to_item(), - true, - )?; + self.inventory() + .lock() + .await + .set_slot(packet.slot as usize, item_stack, true)?; + } else if let Some(item_stack) = item_stack { + // Item drop + self.drop_item(server, item_stack.item.id, u32::from(item_stack.item_count)) + .await; }; - // TODO: The Item was dropped per drag and drop, Ok(()) } @@ -1178,9 +1190,6 @@ impl Player { // return; // }; // window_id 0 represents both 9x1 Generic AND inventory here - let mut inventory = self.inventory().lock().await; - - inventory.state_id = 0; let open_container = self.open_container.load(); if let Some(id) = open_container { let mut open_containers = server.open_containers.write().await; @@ -1196,6 +1205,13 @@ impl Player { } // Remove the player from the container container.remove_player(self.entity_id()); + + let mut inventory = self.inventory().lock().await; + if inventory.state_id >= 2 { + inventory.state_id -= 2; + } else { + inventory.state_id = 0; + } } self.open_container.store(None); } @@ -1229,7 +1245,7 @@ impl Player { self.client.send_packet(&response).await; } - pub fn handle_cookie_response(&self, packet: SPCookieResponse) { + pub fn handle_cookie_response(&self, packet: &SPCookieResponse) { // TODO: allow plugins to access this log::debug!( "Received cookie_response[play]: key: \"{}\", has_payload: \"{}\", payload_length: \"{}\"", diff --git a/pumpkin/src/net/proxy/bungeecord.rs b/pumpkin/src/net/proxy/bungeecord.rs index dc1976713..4fc0580ed 100644 --- a/pumpkin/src/net/proxy/bungeecord.rs +++ b/pumpkin/src/net/proxy/bungeecord.rs @@ -4,7 +4,7 @@ use pumpkin_protocol::Property; use thiserror::Error; use tokio::sync::Mutex; -use crate::net::{offline_uuid, GameProfile}; +use crate::net::{GameProfile, offline_uuid}; #[derive(Error, Debug)] pub enum BungeeCordError { diff --git a/pumpkin/src/net/proxy/velocity.rs b/pumpkin/src/net/proxy/velocity.rs index 4394e1feb..0a0c2461c 100644 --- a/pumpkin/src/net/proxy/velocity.rs +++ b/pumpkin/src/net/proxy/velocity.rs @@ -7,8 +7,8 @@ use bytes::{BufMut, BytesMut}; use hmac::{Hmac, Mac}; use pumpkin_config::networking::proxy::VelocityConfig; use pumpkin_protocol::{ - bytebuf::ByteBuf, client::login::CLoginPluginRequest, server::login::SLoginPluginResponse, - Property, + Property, bytebuf::ByteBuf, client::login::CLoginPluginRequest, + server::login::SLoginPluginResponse, }; use rand::Rng; use sha2::Sha256; @@ -45,7 +45,7 @@ pub enum VelocityError { pub async fn velocity_login(client: &Client) { // TODO: validate packet transaction id from plugin response with this - let velocity_message_id: i32 = rand::thread_rng().gen(); + let velocity_message_id: i32 = rand::thread_rng().r#gen(); let mut buf = BytesMut::new(); buf.put_u8(MAX_SUPPORTED_FORWARDING_VERSION); diff --git a/pumpkin/src/net/query.rs b/pumpkin/src/net/query.rs index 1265135c0..f44a58570 100644 --- a/pumpkin/src/net/query.rs +++ b/pumpkin/src/net/query.rs @@ -13,7 +13,7 @@ use pumpkin_protocol::query::{ use rand::Rng; use tokio::{net::UdpSocket, sync::RwLock, time}; -use crate::server::{Server, CURRENT_MC_VERSION}; +use crate::server::{CURRENT_MC_VERSION, Server}; pub async fn start_query_handler(server: Arc, bound_addr: SocketAddr) { let mut query_addr = bound_addr; diff --git a/pumpkin/src/net/rcon/mod.rs b/pumpkin/src/net/rcon/mod.rs index a4f806216..c89d2bd8e 100644 --- a/pumpkin/src/net/rcon/mod.rs +++ b/pumpkin/src/net/rcon/mod.rs @@ -1,7 +1,7 @@ use std::net::SocketAddr; use packet::{ClientboundPacket, Packet, PacketError, ServerboundPacket}; -use pumpkin_config::{RCONConfig, ADVANCED_CONFIG}; +use pumpkin_config::{ADVANCED_CONFIG, RCONConfig}; use std::sync::Arc; use tokio::io::{AsyncReadExt, AsyncWriteExt}; diff --git a/pumpkin/src/plugin/api/events/block/block_break.rs b/pumpkin/src/plugin/api/events/block/block_break.rs index fbbc63958..b1b3baec5 100644 --- a/pumpkin/src/plugin/api/events/block/block_break.rs +++ b/pumpkin/src/plugin/api/events/block/block_break.rs @@ -1,4 +1,4 @@ -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_world::block::registry::Block; use std::sync::Arc; diff --git a/pumpkin/src/plugin/api/events/block/block_burn.rs b/pumpkin/src/plugin/api/events/block/block_burn.rs index eb73bb1b9..be053afcc 100644 --- a/pumpkin/src/plugin/api/events/block/block_burn.rs +++ b/pumpkin/src/plugin/api/events/block/block_burn.rs @@ -1,4 +1,4 @@ -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_world::block::registry::Block; use super::BlockEvent; diff --git a/pumpkin/src/plugin/api/events/block/block_can_build.rs b/pumpkin/src/plugin/api/events/block/block_can_build.rs index 798dc920c..0d3a28ac7 100644 --- a/pumpkin/src/plugin/api/events/block/block_can_build.rs +++ b/pumpkin/src/plugin/api/events/block/block_can_build.rs @@ -1,4 +1,4 @@ -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_world::block::registry::Block; use std::sync::Arc; diff --git a/pumpkin/src/plugin/api/events/block/block_place.rs b/pumpkin/src/plugin/api/events/block/block_place.rs index a750b4be4..39450bfae 100644 --- a/pumpkin/src/plugin/api/events/block/block_place.rs +++ b/pumpkin/src/plugin/api/events/block/block_place.rs @@ -1,4 +1,4 @@ -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_world::block::registry::Block; use std::sync::Arc; diff --git a/pumpkin/src/plugin/api/events/player/player_join.rs b/pumpkin/src/plugin/api/events/player/player_join.rs index 79a877701..bcee2365a 100644 --- a/pumpkin/src/plugin/api/events/player/player_join.rs +++ b/pumpkin/src/plugin/api/events/player/player_join.rs @@ -1,4 +1,4 @@ -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_util::text::TextComponent; use std::sync::Arc; diff --git a/pumpkin/src/plugin/api/events/player/player_leave.rs b/pumpkin/src/plugin/api/events/player/player_leave.rs index 5e7126479..c66683fd9 100644 --- a/pumpkin/src/plugin/api/events/player/player_leave.rs +++ b/pumpkin/src/plugin/api/events/player/player_leave.rs @@ -1,4 +1,4 @@ -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_util::text::TextComponent; use std::sync::Arc; diff --git a/pumpkin/src/plugin/api/events/world/chunk_load.rs b/pumpkin/src/plugin/api/events/world/chunk_load.rs index fdfc3a123..5bbbc0433 100644 --- a/pumpkin/src/plugin/api/events/world/chunk_load.rs +++ b/pumpkin/src/plugin/api/events/world/chunk_load.rs @@ -1,5 +1,5 @@ use crate::world::World; -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_world::chunk::ChunkData; use std::sync::Arc; use tokio::sync::RwLock; diff --git a/pumpkin/src/plugin/api/events/world/chunk_save.rs b/pumpkin/src/plugin/api/events/world/chunk_save.rs index fda4b4c2c..e9fb38043 100644 --- a/pumpkin/src/plugin/api/events/world/chunk_save.rs +++ b/pumpkin/src/plugin/api/events/world/chunk_save.rs @@ -1,5 +1,5 @@ use crate::world::World; -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_world::chunk::ChunkData; use std::sync::Arc; use tokio::sync::RwLock; diff --git a/pumpkin/src/plugin/api/events/world/chunk_send.rs b/pumpkin/src/plugin/api/events/world/chunk_send.rs index 02645a098..601ceaaae 100644 --- a/pumpkin/src/plugin/api/events/world/chunk_send.rs +++ b/pumpkin/src/plugin/api/events/world/chunk_send.rs @@ -1,5 +1,5 @@ use crate::world::World; -use pumpkin_macros::{cancellable, Event}; +use pumpkin_macros::{Event, cancellable}; use pumpkin_world::chunk::ChunkData; use std::sync::Arc; use tokio::sync::RwLock; diff --git a/pumpkin/src/server/connection_cache.rs b/pumpkin/src/server/connection_cache.rs index e9bac06bf..11977e412 100644 --- a/pumpkin/src/server/connection_cache.rs +++ b/pumpkin/src/server/connection_cache.rs @@ -6,12 +6,12 @@ use std::{ path::Path, }; -use base64::{engine::general_purpose, Engine as _}; -use pumpkin_config::{BasicConfiguration, BASIC_CONFIG}; +use base64::{Engine as _, engine::general_purpose}; +use pumpkin_config::{BASIC_CONFIG, BasicConfiguration}; use pumpkin_protocol::{ + CURRENT_MC_PROTOCOL, Players, StatusResponse, Version, client::{config::CPluginMessage, status::CStatusResponse}, - codec::{var_int::VarInt, Codec}, - Players, StatusResponse, Version, CURRENT_MC_PROTOCOL, + codec::{Codec, var_int::VarInt}, }; use super::CURRENT_MC_VERSION; diff --git a/pumpkin/src/server/key_store.rs b/pumpkin/src/server/key_store.rs index 84d2c0d84..070eb7e1b 100644 --- a/pumpkin/src/server/key_store.rs +++ b/pumpkin/src/server/key_store.rs @@ -1,7 +1,7 @@ use num_bigint::BigInt; use pumpkin_protocol::client::login::CEncryptionRequest; use rand::rngs::OsRng; -use rsa::{traits::PublicKeyParts as _, Pkcs1v15Encrypt, RsaPrivateKey}; +use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, traits::PublicKeyParts as _}; use sha1::Sha1; use sha2::Digest; diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index e22b2163b..88404860f 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -6,7 +6,7 @@ use pumpkin_data::entity::EntityType; use pumpkin_inventory::drag_handler::DragHandler; use pumpkin_inventory::{Container, OpenContainer}; use pumpkin_protocol::client::login::CEncryptionRequest; -use pumpkin_protocol::{client::config::CPluginMessage, ClientPacket}; +use pumpkin_protocol::{ClientPacket, client::config::CPluginMessage}; use pumpkin_registry::{DimensionType, Registry}; use pumpkin_util::math::boundingbox::{BoundingBox, EntityDimensions}; use pumpkin_util::math::position::BlockPos; @@ -21,8 +21,8 @@ use std::net::IpAddr; use std::sync::atomic::AtomicU32; use std::{ sync::{ - atomic::{AtomicI32, Ordering}, Arc, + atomic::{AtomicI32, Ordering}, }, time::Duration, }; @@ -31,15 +31,13 @@ use tokio::sync::{Mutex, RwLock}; use crate::block::default_block_properties_manager; use crate::block::properties::BlockPropertiesManager; use crate::block::registry::BlockRegistry; +use crate::command::commands::default_dispatcher; use crate::entity::{Entity, EntityId}; use crate::item::registry::ItemRegistry; use crate::net::EncryptionError; use crate::world::custom_bossbar::CustomBossbars; use crate::{ - command::{default_dispatcher, dispatcher::CommandDispatcher}, - entity::player::Player, - net::Client, - world::World, + command::dispatcher::CommandDispatcher, entity::player::Player, net::Client, world::World, }; mod connection_cache; @@ -481,7 +479,7 @@ impl Server { async fn tick(&self) { for world in self.worlds.read().await.iter() { - world.tick().await; + world.tick(self).await; } } } diff --git a/pumpkin/src/world/explosion.rs b/pumpkin/src/world/explosion.rs new file mode 100644 index 000000000..f385c0220 --- /dev/null +++ b/pumpkin/src/world/explosion.rs @@ -0,0 +1,92 @@ +use std::sync::Arc; + +use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; + +use crate::{block::drop_loot, server::Server}; + +use super::World; + +pub struct Explosion { + power: f32, + pos: Vector3, +} +impl Explosion { + #[must_use] + pub fn new(power: f32, pos: Vector3) -> Self { + Self { power, pos } + } + async fn get_blocks_to_destroy(&self, world: &World) -> Vec { + let mut set = Vec::new(); + for x in 0..16 { + for z in 0..16 { + 'block2: for y in 0..16 { + if x != 0 && x != 15 && z != 0 && z != 15 && y != 0 && y != 15 { + continue; + } + + let x = f64::from(x) / 15.0 * 2.0 - 1.0; + let y = f64::from(z) / 15.0 * 2.0 - 1.0; + let z = y / 15.0 * 2.0 - 1.0; + + let sqrt = (x * x + y * y + z * z).sqrt(); + let x_div = x / sqrt; + let y_div = y / sqrt; + let z_div = z / sqrt; + + let mut pos_x = self.pos.x; + let mut pos_y = self.pos.y; + let mut pos_z = self.pos.z; + + let mut h = self.power * (0.7 + rand::random::() * 0.6); + while h > 0.0 { + let block_pos = BlockPos::floored(pos_x, pos_y, pos_z); + let block = world.get_block(&block_pos).await.unwrap(); + + // if !world.is_in_build_limit(&block_pos) { + // // Pass by reference + // continue 'block2; + // } + + // TODO: This should only check Air & Fluid + // AIR has blast_resistance of 0 + if block.blast_resistance > 0.0 { + h -= (block.blast_resistance + 0.3) * 0.3; + } + if h > 0.0 { + set.push(block_pos); + } + + pos_x += x_div * 0.3; + pos_y += y_div * 0.3; + pos_z += z_div * 0.3; + h -= 0.225_000_01f32; + } + } + } + } + + set + } + + pub async fn explode(&self, server: &Server, world: &Arc) { + let blocks = self.get_blocks_to_destroy(world).await; + // TODO: Entity damage, fire + for pos in blocks { + let block_state = world.get_block_state(&pos).await.unwrap(); + + if block_state.air { + continue; + } + world.set_block_state(&pos, 0).await; + + let block = world.get_block(&pos).await.unwrap(); + let pumpkin_block = server.block_registry.get_pumpkin_block(block); + if pumpkin_block.is_none_or(|s| s.should_drop_items_on_explosion()) { + drop_loot(server, world, block, &pos, false).await; + } + if let Some(pumpkin_block) = pumpkin_block { + pumpkin_block.explode(block, world, pos, server).await; + } + } + } +} diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index ea652ef4c..1e93cac92 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -1,15 +1,16 @@ use std::{ collections::HashMap, - sync::{atomic::Ordering, Arc}, + sync::{Arc, atomic::Ordering}, }; pub mod chunker; +pub mod explosion; pub mod time; use crate::{ - block, + PLUGIN_MANAGER, block, command::client_suggestions, - entity::{player::Player, Entity, EntityBase, EntityId}, + entity::{Entity, EntityBase, EntityId, player::Player}, error::PumpkinError, plugin::{ block::block_break::BlockBreakEvent, @@ -17,32 +18,36 @@ use crate::{ world::{chunk_load::ChunkLoad, chunk_save::ChunkSave, chunk_send::ChunkSend}, }, server::Server, - PLUGIN_MANAGER, }; use border::Worldborder; +use explosion::Explosion; use pumpkin_config::BasicConfiguration; use pumpkin_data::{ - entity::EntityType, + entity::{EntityStatus, EntityType}, particle::Particle, sound::{Sound, SoundCategory}, world::WorldEvent, }; use pumpkin_macros::send_cancellable; -use pumpkin_protocol::client::play::{ - CBlockUpdate, CDisguisedChatMessage, CRespawn, CSetBlockDestroyStage, CWorldEvent, +use pumpkin_protocol::{ + ClientPacket, + client::play::{ + CChunkData, CEntityStatus, CGameEvent, CLogin, CPlayerInfoUpdate, CRemoveEntities, + CRemovePlayerInfo, CSpawnEntity, GameEvent, PlayerAction, + }, }; use pumpkin_protocol::{client::play::CLevelEvent, codec::identifier::Identifier}; use pumpkin_protocol::{ client::play::{ - CChunkData, CGameEvent, CLogin, CPlayerInfoUpdate, CRemoveEntities, CRemovePlayerInfo, - CSpawnEntity, GameEvent, PlayerAction, + CBlockUpdate, CDisguisedChatMessage, CExplosion, CRespawn, CSetBlockDestroyStage, + CWorldEvent, }, - ClientPacket, + codec::var_int::VarInt, }; use pumpkin_registry::DimensionType; use pumpkin_util::math::vector2::Vector2; use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; -use pumpkin_util::text::{color::NamedColor, TextComponent}; +use pumpkin_util::text::{TextComponent, color::NamedColor}; use pumpkin_world::chunk::ChunkData; use pumpkin_world::level::Level; use pumpkin_world::{ @@ -51,14 +56,14 @@ use pumpkin_world::{ }, coordinates::ChunkRelativeBlockCoordinates, }; -use rand::{thread_rng, Rng}; +use rand::{Rng, thread_rng}; use scoreboard::Scoreboard; use thiserror::Error; use time::LevelTime; -use tokio::sync::{mpsc::Receiver, Mutex}; +use tokio::sync::{Mutex, mpsc::Receiver}; use tokio::{ runtime::Handle, - sync::{mpsc, RwLock}, + sync::{RwLock, mpsc}, }; pub mod border; @@ -144,6 +149,12 @@ impl World { self.level.save().await; } + pub async fn send_entity_status(&self, entity: &Entity, status: EntityStatus) { + // TODO: only nearby + self.broadcast_packet_all(&CEntityStatus::new(entity.entity_id, status as i8)) + .await; + } + /// Broadcasts a packet to all connected players within the world. /// /// Sends the specified packet to every player currently logged in to the world. @@ -219,7 +230,7 @@ impl World { volume: f32, pitch: f32, ) { - let seed = thread_rng().gen::(); + let seed = thread_rng().r#gen::(); let players = self.players.read().await; for (_, player) in players.iter() { player @@ -262,7 +273,7 @@ impl World { .await; } - pub async fn tick(&self) { + pub async fn tick(&self, server: &Server) { // world ticks { let mut level_time = self.level_time.lock().await; @@ -279,14 +290,14 @@ impl World { // player ticks for player in self.players.read().await.values() { - player.tick().await; + player.tick(server).await; } let entities_to_tick: Vec<_> = self.entities.read().await.values().cloned().collect(); // entities tick for entity in entities_to_tick { - entity.tick().await; + entity.tick(server).await; // this boolean thing prevents deadlocks, since we lock players we can't broadcast packets let mut collied_player = None; for player in self.players.read().await.values() { @@ -578,6 +589,34 @@ impl World { player.set_health(20.0).await; } + pub async fn explode(self: &Arc, server: &Server, position: Vector3, power: f32) { + let explosion = Explosion::new(power, position); + explosion.explode(server, self).await; + let particle = if power < 2.0 { + Particle::Explosion + } else { + Particle::ExplosionEmitter + }; + let sound = pumpkin_protocol::IDOrSoundEvent { + id: VarInt(Sound::EntityGenericExplode as i32 + 1), + sound_event: None, + }; + for (_, player) in self.players.read().await.iter() { + if player.position().squared_distance_to_vec(position) > 4096.0 { + continue; + } + player + .client + .send_packet(&CExplosion::new( + position, + None, + VarInt(particle as i32), + sound.clone(), + )) + .await; + } + } + pub async fn respawn_player(&self, player: &Arc, alive: bool) { let last_pos = player.living_entity.last_pos.load(); let death_dimension = player.world().await.dimension_type.name(); @@ -964,15 +1003,7 @@ impl World { } } - /// Adds a living entity to the world. - /// - /// This function takes a living entity's UUID and an `Arc` reference. - /// It inserts the living entity into the world's `current_living_entities` map using the UUID as the key. - /// - /// # Arguments - /// - /// * `uuid`: The unique UUID of the living entity to add. - /// * `living_entity`: A `Arc` reference to the living entity object. + /// Adds a entity to the world. pub async fn spawn_entity(&self, entity: Arc) { let base_entity = entity.get_entity(); self.broadcast_packet_all(&base_entity.create_spawn_packet()) @@ -1081,7 +1112,7 @@ impl World { ); if drop { - block::drop_loot(server, self, block, position).await; + block::drop_loot(server, self, block, position, true).await; } match cause { diff --git a/pumpkin/src/world/scoreboard.rs b/pumpkin/src/world/scoreboard.rs index 45c17e6bb..95db81dd3 100644 --- a/pumpkin/src/world/scoreboard.rs +++ b/pumpkin/src/world/scoreboard.rs @@ -2,9 +2,9 @@ use std::collections::HashMap; use pumpkin_data::scoreboard::ScoreboardDisplaySlot; use pumpkin_protocol::{ + NumberFormat, client::play::{CDisplayObjective, CUpdateObjectives, CUpdateScore, RenderType}, codec::var_int::VarInt, - NumberFormat, }; use pumpkin_util::text::TextComponent;