From 53cef4b05033daa1d7753848354814dfc8364298 Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sun, 17 Aug 2025 22:12:38 +0200 Subject: [PATCH] Add structures this is by far not done and the implementation is not correct in many ways, but it is still something --- Cargo.lock | 71 +- assets/structures.json | 675 ++++++++++++++++++ pumpkin-protocol/Cargo.toml | 2 +- pumpkin-world/Cargo.toml | 2 +- pumpkin-world/src/block/mod.rs | 4 + pumpkin-world/src/block/state.rs | 23 - .../src/generation/block_predicate.rs | 9 +- .../features/netherrack_replace_blobs.rs | 3 +- pumpkin-world/src/generation/proto_chunk.rs | 33 +- .../src/generation/rule/block_state_match.rs | 2 +- pumpkin-world/src/generation/structure/mod.rs | 66 +- .../structure/structures/buried_treasure.rs | 18 +- .../generation/structure/structures/mod.rs | 14 +- .../structure/structures/nether_fortress.rs | 30 + pumpkin/Cargo.toml | 2 +- 15 files changed, 859 insertions(+), 95 deletions(-) create mode 100644 assets/structures.json create mode 100644 pumpkin-world/src/generation/structure/structures/nether_fortress.rs diff --git a/Cargo.lock b/Cargo.lock index efe2d3279..fa4da41d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,9 +269,9 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" [[package]] name = "block-buffer" @@ -317,9 +317,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.27" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "shlex", ] @@ -489,9 +489,9 @@ dependencies = [ [[package]] name = "cookie_store" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +checksum = "3fc4bff745c9b4c7fb1e97b25d13153da2bc7796260141df62378998d070207f" dependencies = [ "cookie", "document-features", @@ -545,9 +545,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -1106,9 +1106,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", @@ -1389,7 +1389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "serde", ] @@ -1485,9 +1485,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libloading" @@ -1519,9 +1519,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" [[package]] name = "lock_api" @@ -1545,7 +1545,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86ea4e65087ff52f3862caff188d489f1fab49a0cb09e01b2e3f1a617b10aaed" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -1981,9 +1981,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0" dependencies = [ "unicode-ident", ] @@ -2459,9 +2459,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.28" +version = "0.23.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" dependencies = [ "log", "once_cell", @@ -2492,9 +2492,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", @@ -2574,9 +2574,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" dependencies = [ "itoa", "memchr", @@ -3229,9 +3229,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.0.12" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f0fde9bc91026e381155f8c67cb354bcd35260b2f4a29bcc84639f762760c39" +checksum = "00432f493971db5d8e47a65aeb3b02f8226b9b11f1450ff86bb772776ebadd70" dependencies = [ "base64 0.22.1", "cookie_store", @@ -3245,14 +3245,14 @@ dependencies = [ "serde_json", "ureq-proto", "utf-8", - "webpki-roots 0.26.11", + "webpki-roots", ] [[package]] name = "ureq-proto" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59db78ad1923f2b1be62b6da81fe80b173605ca0d57f85da2e005382adf693f7" +checksum = "c5b6cabebbecc4c45189ab06b52f956206cea7d8c8a20851c35a85cb169224cc" dependencies = [ "base64 0.22.1", "http", @@ -3408,18 +3408,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.1", -] - -[[package]] -name = "webpki-roots" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] diff --git a/assets/structures.json b/assets/structures.json new file mode 100644 index 000000000..4f6227654 --- /dev/null +++ b/assets/structures.json @@ -0,0 +1,675 @@ +{ + "ancient_city": { + "use_expansion_hack": false, + "max_distance_from_center": 116, + "start_jigsaw_name": "minecraft:city_anchor", + "size": 7, + "start_height": { + "absolute": -27 + }, + "biomes": "#minecraft:has_structure/ancient_city", + "spawn_overrides": { + "ambient": { + "bounding_box": "full", + "spawns": [] + }, + "axolotls": { + "bounding_box": "full", + "spawns": [] + }, + "creature": { + "bounding_box": "full", + "spawns": [] + }, + "misc": { + "bounding_box": "full", + "spawns": [] + }, + "monster": { + "bounding_box": "full", + "spawns": [] + }, + "underground_water_creature": { + "bounding_box": "full", + "spawns": [] + }, + "water_ambient": { + "bounding_box": "full", + "spawns": [] + }, + "water_creature": { + "bounding_box": "full", + "spawns": [] + } + }, + "step": "underground_decoration", + "terrain_adaptation": "beard_box", + "start_pool": "minecraft:ancient_city/city_center", + "type": "minecraft:jigsaw" + }, + "bastion_remnant": { + "use_expansion_hack": false, + "max_distance_from_center": 80, + "size": 6, + "start_height": { + "absolute": 33 + }, + "biomes": "#minecraft:has_structure/bastion_remnant", + "spawn_overrides": {}, + "step": "surface_structures", + "start_pool": "minecraft:bastion/starts", + "type": "minecraft:jigsaw" + }, + "buried_treasure": { + "biomes": "#minecraft:has_structure/buried_treasure", + "spawn_overrides": {}, + "step": "underground_structures", + "type": "minecraft:buried_treasure" + }, + "desert_pyramid": { + "biomes": "#minecraft:has_structure/desert_pyramid", + "spawn_overrides": {}, + "step": "surface_structures", + "type": "minecraft:desert_pyramid" + }, + "end_city": { + "biomes": "#minecraft:has_structure/end_city", + "spawn_overrides": {}, + "step": "surface_structures", + "type": "minecraft:end_city" + }, + "fortress": { + "biomes": "#minecraft:has_structure/nether_fortress", + "spawn_overrides": { + "monster": { + "bounding_box": "piece", + "spawns": [ + { + "type": "minecraft:blaze", + "minCount": 2, + "maxCount": 3, + "weight": 10 + }, + { + "type": "minecraft:zombified_piglin", + "minCount": 4, + "maxCount": 4, + "weight": 5 + }, + { + "type": "minecraft:wither_skeleton", + "minCount": 5, + "maxCount": 5, + "weight": 8 + }, + { + "type": "minecraft:skeleton", + "minCount": 5, + "maxCount": 5, + "weight": 2 + }, + { + "type": "minecraft:magma_cube", + "minCount": 4, + "maxCount": 4, + "weight": 3 + } + ] + } + }, + "step": "underground_decoration", + "type": "minecraft:fortress" + }, + "igloo": { + "biomes": "#minecraft:has_structure/igloo", + "spawn_overrides": {}, + "step": "surface_structures", + "type": "minecraft:igloo" + }, + "jungle_pyramid": { + "biomes": "#minecraft:has_structure/jungle_temple", + "spawn_overrides": {}, + "step": "surface_structures", + "type": "minecraft:jungle_temple" + }, + "mansion": { + "biomes": "#minecraft:has_structure/woodland_mansion", + "spawn_overrides": {}, + "step": "surface_structures", + "type": "minecraft:woodland_mansion" + }, + "mineshaft": { + "biomes": "#minecraft:has_structure/mineshaft", + "spawn_overrides": {}, + "step": "underground_structures", + "mineshaft_type": "normal", + "type": "minecraft:mineshaft" + }, + "mineshaft_mesa": { + "biomes": "#minecraft:has_structure/mineshaft_mesa", + "spawn_overrides": {}, + "step": "underground_structures", + "mineshaft_type": "mesa", + "type": "minecraft:mineshaft" + }, + "monument": { + "biomes": "#minecraft:has_structure/ocean_monument", + "spawn_overrides": { + "axolotls": { + "bounding_box": "full", + "spawns": [] + }, + "monster": { + "bounding_box": "full", + "spawns": [ + { + "type": "minecraft:guardian", + "minCount": 2, + "maxCount": 4, + "weight": 1 + } + ] + }, + "underground_water_creature": { + "bounding_box": "full", + "spawns": [] + } + }, + "step": "surface_structures", + "type": "minecraft:ocean_monument" + }, + "nether_fossil": { + "biomes": "#minecraft:has_structure/nether_fossil", + "spawn_overrides": {}, + "step": "underground_decoration", + "terrain_adaptation": "beard_thin", + "height": { + "min_inclusive": { + "absolute": 32 + }, + "max_inclusive": { + "below_top": 2 + }, + "type": "minecraft:uniform" + }, + "type": "minecraft:nether_fossil" + }, + "ocean_ruin_cold": { + "biomes": "#minecraft:has_structure/ocean_ruin_cold", + "spawn_overrides": {}, + "step": "surface_structures", + "biome_temp": "cold", + "large_probability": 0.3, + "cluster_probability": 0.9, + "type": "minecraft:ocean_ruin" + }, + "ocean_ruin_warm": { + "biomes": "#minecraft:has_structure/ocean_ruin_warm", + "spawn_overrides": {}, + "step": "surface_structures", + "biome_temp": "warm", + "large_probability": 0.3, + "cluster_probability": 0.9, + "type": "minecraft:ocean_ruin" + }, + "pillager_outpost": { + "use_expansion_hack": true, + "project_start_to_heightmap": "WORLD_SURFACE_WG", + "max_distance_from_center": 80, + "size": 7, + "start_height": { + "absolute": 0 + }, + "biomes": "#minecraft:has_structure/pillager_outpost", + "spawn_overrides": { + "monster": { + "bounding_box": "full", + "spawns": [ + { + "type": "minecraft:pillager", + "minCount": 1, + "maxCount": 1, + "weight": 1 + } + ] + } + }, + "step": "surface_structures", + "terrain_adaptation": "beard_thin", + "start_pool": "minecraft:pillager_outpost/base_plates", + "type": "minecraft:jigsaw" + }, + "ruined_portal": { + "biomes": "#minecraft:has_structure/ruined_portal_standard", + "spawn_overrides": {}, + "step": "surface_structures", + "setups": [ + { + "vines": false, + "can_be_cold": true, + "replace_with_blackstone": false, + "weight": 0.5, + "placement": "underground", + "air_pocket_probability": 1.0, + "mossiness": 0.2, + "overgrown": false + }, + { + "vines": false, + "can_be_cold": true, + "replace_with_blackstone": false, + "weight": 0.5, + "placement": "on_land_surface", + "air_pocket_probability": 0.5, + "mossiness": 0.2, + "overgrown": false + } + ], + "type": "minecraft:ruined_portal" + }, + "ruined_portal_desert": { + "biomes": "#minecraft:has_structure/ruined_portal_desert", + "spawn_overrides": {}, + "step": "surface_structures", + "setups": [ + { + "vines": false, + "can_be_cold": false, + "replace_with_blackstone": false, + "weight": 1.0, + "placement": "partly_buried", + "air_pocket_probability": 0.0, + "mossiness": 0.0, + "overgrown": false + } + ], + "type": "minecraft:ruined_portal" + }, + "ruined_portal_jungle": { + "biomes": "#minecraft:has_structure/ruined_portal_jungle", + "spawn_overrides": {}, + "step": "surface_structures", + "setups": [ + { + "vines": true, + "can_be_cold": false, + "replace_with_blackstone": false, + "weight": 1.0, + "placement": "on_land_surface", + "air_pocket_probability": 0.5, + "mossiness": 0.8, + "overgrown": true + } + ], + "type": "minecraft:ruined_portal" + }, + "ruined_portal_mountain": { + "biomes": "#minecraft:has_structure/ruined_portal_mountain", + "spawn_overrides": {}, + "step": "surface_structures", + "setups": [ + { + "vines": false, + "can_be_cold": true, + "replace_with_blackstone": false, + "weight": 0.5, + "placement": "in_mountain", + "air_pocket_probability": 1.0, + "mossiness": 0.2, + "overgrown": false + }, + { + "vines": false, + "can_be_cold": true, + "replace_with_blackstone": false, + "weight": 0.5, + "placement": "on_land_surface", + "air_pocket_probability": 0.5, + "mossiness": 0.2, + "overgrown": false + } + ], + "type": "minecraft:ruined_portal" + }, + "ruined_portal_nether": { + "biomes": "#minecraft:has_structure/ruined_portal_nether", + "spawn_overrides": {}, + "step": "surface_structures", + "setups": [ + { + "vines": false, + "can_be_cold": false, + "replace_with_blackstone": true, + "weight": 1.0, + "placement": "in_nether", + "air_pocket_probability": 0.5, + "mossiness": 0.0, + "overgrown": false + } + ], + "type": "minecraft:ruined_portal" + }, + "ruined_portal_ocean": { + "biomes": "#minecraft:has_structure/ruined_portal_ocean", + "spawn_overrides": {}, + "step": "surface_structures", + "setups": [ + { + "vines": false, + "can_be_cold": true, + "replace_with_blackstone": false, + "weight": 1.0, + "placement": "on_ocean_floor", + "air_pocket_probability": 0.0, + "mossiness": 0.8, + "overgrown": false + } + ], + "type": "minecraft:ruined_portal" + }, + "ruined_portal_swamp": { + "biomes": "#minecraft:has_structure/ruined_portal_swamp", + "spawn_overrides": {}, + "step": "surface_structures", + "setups": [ + { + "vines": true, + "can_be_cold": false, + "replace_with_blackstone": false, + "weight": 1.0, + "placement": "on_ocean_floor", + "air_pocket_probability": 0.0, + "mossiness": 0.5, + "overgrown": false + } + ], + "type": "minecraft:ruined_portal" + }, + "shipwreck": { + "biomes": "#minecraft:has_structure/shipwreck", + "spawn_overrides": {}, + "step": "surface_structures", + "is_beached": false, + "type": "minecraft:shipwreck" + }, + "shipwreck_beached": { + "biomes": "#minecraft:has_structure/shipwreck_beached", + "spawn_overrides": {}, + "step": "surface_structures", + "is_beached": true, + "type": "minecraft:shipwreck" + }, + "stronghold": { + "biomes": "#minecraft:has_structure/stronghold", + "spawn_overrides": {}, + "step": "surface_structures", + "terrain_adaptation": "bury", + "type": "minecraft:stronghold" + }, + "swamp_hut": { + "biomes": "#minecraft:has_structure/swamp_hut", + "spawn_overrides": { + "creature": { + "bounding_box": "piece", + "spawns": [ + { + "type": "minecraft:cat", + "minCount": 1, + "maxCount": 1, + "weight": 1 + } + ] + }, + "monster": { + "bounding_box": "piece", + "spawns": [ + { + "type": "minecraft:witch", + "minCount": 1, + "maxCount": 1, + "weight": 1 + } + ] + } + }, + "step": "surface_structures", + "type": "minecraft:swamp_hut" + }, + "trail_ruins": { + "use_expansion_hack": false, + "project_start_to_heightmap": "WORLD_SURFACE_WG", + "max_distance_from_center": 80, + "size": 7, + "start_height": { + "absolute": -15 + }, + "biomes": "#minecraft:has_structure/trail_ruins", + "spawn_overrides": {}, + "step": "underground_structures", + "terrain_adaptation": "bury", + "start_pool": "minecraft:trail_ruins/tower", + "type": "minecraft:jigsaw" + }, + "trial_chambers": { + "pool_aliases": [ + { + "groups": [ + { + "data": [ + { + "alias": "minecraft:trial_chambers/spawner/contents/ranged", + "target": "minecraft:trial_chambers/spawner/ranged/skeleton", + "type": "minecraft:direct" + }, + { + "alias": "minecraft:trial_chambers/spawner/contents/slow_ranged", + "target": "minecraft:trial_chambers/spawner/slow_ranged/skeleton", + "type": "minecraft:direct" + } + ], + "weight": 1 + }, + { + "data": [ + { + "alias": "minecraft:trial_chambers/spawner/contents/ranged", + "target": "minecraft:trial_chambers/spawner/ranged/stray", + "type": "minecraft:direct" + }, + { + "alias": "minecraft:trial_chambers/spawner/contents/slow_ranged", + "target": "minecraft:trial_chambers/spawner/slow_ranged/stray", + "type": "minecraft:direct" + } + ], + "weight": 1 + }, + { + "data": [ + { + "alias": "minecraft:trial_chambers/spawner/contents/ranged", + "target": "minecraft:trial_chambers/spawner/ranged/poison_skeleton", + "type": "minecraft:direct" + }, + { + "alias": "minecraft:trial_chambers/spawner/contents/slow_ranged", + "target": "minecraft:trial_chambers/spawner/slow_ranged/poison_skeleton", + "type": "minecraft:direct" + } + ], + "weight": 1 + } + ], + "type": "minecraft:random_group" + }, + { + "alias": "minecraft:trial_chambers/spawner/contents/melee", + "targets": [ + { + "data": "minecraft:trial_chambers/spawner/melee/zombie", + "weight": 1 + }, + { + "data": "minecraft:trial_chambers/spawner/melee/husk", + "weight": 1 + }, + { + "data": "minecraft:trial_chambers/spawner/melee/spider", + "weight": 1 + } + ], + "type": "minecraft:random" + }, + { + "alias": "minecraft:trial_chambers/spawner/contents/small_melee", + "targets": [ + { + "data": "minecraft:trial_chambers/spawner/small_melee/slime", + "weight": 1 + }, + { + "data": "minecraft:trial_chambers/spawner/small_melee/cave_spider", + "weight": 1 + }, + { + "data": "minecraft:trial_chambers/spawner/small_melee/silverfish", + "weight": 1 + }, + { + "data": "minecraft:trial_chambers/spawner/small_melee/baby_zombie", + "weight": 1 + } + ], + "type": "minecraft:random" + } + ], + "dimension_padding": 10, + "liquid_settings": "ignore_waterlogging", + "use_expansion_hack": false, + "max_distance_from_center": 116, + "size": 20, + "start_height": { + "min_inclusive": { + "absolute": -40 + }, + "max_inclusive": { + "absolute": -20 + }, + "type": "minecraft:uniform" + }, + "biomes": "#minecraft:has_structure/trial_chambers", + "spawn_overrides": { + "ambient": { + "bounding_box": "piece", + "spawns": [] + }, + "axolotls": { + "bounding_box": "piece", + "spawns": [] + }, + "creature": { + "bounding_box": "piece", + "spawns": [] + }, + "misc": { + "bounding_box": "piece", + "spawns": [] + }, + "monster": { + "bounding_box": "piece", + "spawns": [] + }, + "underground_water_creature": { + "bounding_box": "piece", + "spawns": [] + }, + "water_ambient": { + "bounding_box": "piece", + "spawns": [] + }, + "water_creature": { + "bounding_box": "piece", + "spawns": [] + } + }, + "step": "underground_structures", + "terrain_adaptation": "encapsulate", + "start_pool": "minecraft:trial_chambers/chamber/end", + "type": "minecraft:jigsaw" + }, + "village_desert": { + "use_expansion_hack": true, + "project_start_to_heightmap": "WORLD_SURFACE_WG", + "max_distance_from_center": 80, + "size": 6, + "start_height": { + "absolute": 0 + }, + "biomes": "#minecraft:has_structure/village_desert", + "spawn_overrides": {}, + "step": "surface_structures", + "terrain_adaptation": "beard_thin", + "start_pool": "minecraft:village/desert/town_centers", + "type": "minecraft:jigsaw" + }, + "village_plains": { + "use_expansion_hack": true, + "project_start_to_heightmap": "WORLD_SURFACE_WG", + "max_distance_from_center": 80, + "size": 6, + "start_height": { + "absolute": 0 + }, + "biomes": "#minecraft:has_structure/village_plains", + "spawn_overrides": {}, + "step": "surface_structures", + "terrain_adaptation": "beard_thin", + "start_pool": "minecraft:village/plains/town_centers", + "type": "minecraft:jigsaw" + }, + "village_savanna": { + "use_expansion_hack": true, + "project_start_to_heightmap": "WORLD_SURFACE_WG", + "max_distance_from_center": 80, + "size": 6, + "start_height": { + "absolute": 0 + }, + "biomes": "#minecraft:has_structure/village_savanna", + "spawn_overrides": {}, + "step": "surface_structures", + "terrain_adaptation": "beard_thin", + "start_pool": "minecraft:village/savanna/town_centers", + "type": "minecraft:jigsaw" + }, + "village_snowy": { + "use_expansion_hack": true, + "project_start_to_heightmap": "WORLD_SURFACE_WG", + "max_distance_from_center": 80, + "size": 6, + "start_height": { + "absolute": 0 + }, + "biomes": "#minecraft:has_structure/village_snowy", + "spawn_overrides": {}, + "step": "surface_structures", + "terrain_adaptation": "beard_thin", + "start_pool": "minecraft:village/snowy/town_centers", + "type": "minecraft:jigsaw" + }, + "village_taiga": { + "use_expansion_hack": true, + "project_start_to_heightmap": "WORLD_SURFACE_WG", + "max_distance_from_center": 80, + "size": 6, + "start_height": { + "absolute": 0 + }, + "biomes": "#minecraft:has_structure/village_taiga", + "spawn_overrides": {}, + "step": "surface_structures", + "terrain_adaptation": "beard_thin", + "start_pool": "minecraft:village/taiga/town_centers", + "type": "minecraft:jigsaw" + } +} \ No newline at end of file diff --git a/pumpkin-protocol/Cargo.toml b/pumpkin-protocol/Cargo.toml index 55e7ef2e0..c0fd75a28 100644 --- a/pumpkin-protocol/Cargo.toml +++ b/pumpkin-protocol/Cargo.toml @@ -30,7 +30,7 @@ cfb8 = "0.8" async-compression = { version = "0.4.27", features = ["tokio", "zlib"] } take_mut = "0.2.2" -bitflags = "2.9.1" +bitflags = "2.9.2" [dev-dependencies] # Validate correctness diff --git a/pumpkin-world/Cargo.toml b/pumpkin-world/Cargo.toml index 700d16c2f..9c6562efa 100644 --- a/pumpkin-world/Cargo.toml +++ b/pumpkin-world/Cargo.toml @@ -26,7 +26,7 @@ crossbeam.workspace = true num-derive = "0.4" sha2 = "0.10" -bitflags = "2.9.1" +bitflags = "2.9.2" dashmap = "6.1" diff --git a/pumpkin-world/src/block/mod.rs b/pumpkin-world/src/block/mod.rs index 3b558b4cf..f03ec1010 100644 --- a/pumpkin-world/src/block/mod.rs +++ b/pumpkin-world/src/block/mod.rs @@ -43,6 +43,10 @@ impl BlockStateCodec { BlockState::from_id(state_id) } + pub fn get_block(&self) -> &'static Block { + self.name + } + /// Prefer this over `get_state` when the only the state ID is needed pub fn get_state_id(&self) -> BlockStateId { let block = self.name; diff --git a/pumpkin-world/src/block/state.rs b/pumpkin-world/src/block/state.rs index adcd61a91..7aca87e7b 100644 --- a/pumpkin-world/src/block/state.rs +++ b/pumpkin-world/src/block/state.rs @@ -9,12 +9,6 @@ pub struct RawBlockState(pub BlockStateId); impl RawBlockState { pub const AIR: RawBlockState = RawBlockState(0); - /// Get a Block from the Vanilla Block registry at Runtime - pub fn new(registry_id: &str) -> Option { - let block = Block::from_name(registry_id); - block.map(|block| Self(block.default_state.id)) - } - #[inline] pub fn to_state(&self) -> &'static BlockState { BlockState::from_id(self.0) @@ -25,20 +19,3 @@ impl RawBlockState { Block::from_state_id(self.0) } } - -#[cfg(test)] -mod tests { - use super::RawBlockState; - - #[test] - fn not_existing() { - let result = RawBlockState::new("this_block_does_not_exist"); - assert!(result.is_none()); - } - - #[test] - fn does_exist() { - let result = RawBlockState::new("dirt"); - assert!(result.is_some()); - } -} diff --git a/pumpkin-world/src/generation/block_predicate.rs b/pumpkin-world/src/generation/block_predicate.rs index 5e4a2a6cf..2ac7b45c0 100644 --- a/pumpkin-world/src/generation/block_predicate.rs +++ b/pumpkin-world/src/generation/block_predicate.rs @@ -217,14 +217,9 @@ impl WouldSurviveBlockPredicate { chunk: &ProtoChunk<'_>, pos: &BlockPos, ) -> bool { - let state = self.state.get_state(); + let block = self.state.get_block(); let pos = self.offset.get(pos); - block_registry.can_place_at( - Block::from_state_id(state.id), - chunk, - &pos, - BlockDirection::Up, - ) + block_registry.can_place_at(block, chunk, &pos, BlockDirection::Up) } } diff --git a/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs b/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs index 89661e360..6438ea649 100644 --- a/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs +++ b/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs @@ -29,8 +29,7 @@ impl ReplaceBlobsFeature { random: &mut RandomGenerator, pos: BlockPos, ) -> bool { - let target = self.target.get_state(); - let target = Block::from_state_id(target.id); + let target = self.target.get_block(); let state = self.state.get_state(); let Some(pos) = Self::move_down_to_target(pos, chunk, target) else { return false; diff --git a/pumpkin-world/src/generation/proto_chunk.rs b/pumpkin-world/src/generation/proto_chunk.rs index b4872df1f..7cbaa4993 100644 --- a/pumpkin-world/src/generation/proto_chunk.rs +++ b/pumpkin-world/src/generation/proto_chunk.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; @@ -12,8 +13,9 @@ use pumpkin_util::{ }; use crate::generation::noise::perlin::DoublePerlinNoiseSampler; -use crate::generation::structure::STRUCTURE_SETS; use crate::generation::structure::placement::StructurePlacementCalculator; +use crate::generation::structure::structures::StructurePosition; +use crate::generation::structure::{STRUCTURE_SETS, STRUCTURS, Structure, StructureType}; use crate::{ BlockStateId, biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed}, @@ -124,6 +126,7 @@ pub struct ProtoChunk<'a> { pub flat_motion_blocking_height_map: Box<[i16]>, pub flat_motion_blocking_no_leaves_height_map: Box<[i16]>, // may want to use chunk status + structure_starts: HashMap, } pub struct TerrainCache { @@ -234,6 +237,7 @@ impl<'a> ProtoChunk<'a> { flat_ocean_floor_height_map: default_heightmap.clone(), flat_motion_blocking_height_map: default_heightmap.clone(), flat_motion_blocking_no_leaves_height_map: default_heightmap, + structure_starts: HashMap::new(), } } @@ -732,6 +736,10 @@ impl<'a> ProtoChunk<'a> { let population_seed = Xoroshiro::get_population_seed(self.random_config.seed, block_pos.0.x, block_pos.0.z); + for (_structure, (pos, stype)) in self.structure_starts.clone() { + stype.generate(pos.clone(), self); + } + // TODO: This needs to be different depending on what biomes are in the chunk -> affects the // random for (name, feature) in PLACED_FEATURES.iter() { @@ -751,14 +759,33 @@ impl<'a> ProtoChunk<'a> { } } - pub fn set_structure_starts(&self) { - for (_name, set) in STRUCTURE_SETS.iter() { + pub fn set_structure_starts(&mut self) { + for (name, set) in STRUCTURE_SETS.iter() { let calculator = StructurePlacementCalculator { seed: self.random_config.seed as i64, }; + // for structure in &set.structures { + // let start = self.structure_starts.get(STRUCTURS.get(name).unwrap()); + // } if !set.placement.should_generate(calculator, self.chunk_pos) { continue; // ?? } + + if set.structures.len() == 1 { + let position = set.structures[0] + .structure + .get_structure_position(name, self); + if let Some(position) = position + && !position.generator.pieces_positions.is_empty() + { + self.structure_starts.insert( + STRUCTURS.get(name).unwrap().clone(), + (position, set.structures[0].structure.clone()), + ); + } + return; + } + // TODO: handle multiple structures } } diff --git a/pumpkin-world/src/generation/rule/block_state_match.rs b/pumpkin-world/src/generation/rule/block_state_match.rs index 202b4eb8f..5d36ad5ab 100644 --- a/pumpkin-world/src/generation/rule/block_state_match.rs +++ b/pumpkin-world/src/generation/rule/block_state_match.rs @@ -10,6 +10,6 @@ pub struct BlockStateMatchRuleTest { impl BlockStateMatchRuleTest { pub fn test(&self, state: &BlockState) -> bool { - state.id == self.block_state.get_state().id + state.id == self.block_state.get_state_id() } } diff --git a/pumpkin-world/src/generation/structure/mod.rs b/pumpkin-world/src/generation/structure/mod.rs index 881d9b380..513219de2 100644 --- a/pumpkin-world/src/generation/structure/mod.rs +++ b/pumpkin-world/src/generation/structure/mod.rs @@ -1,9 +1,19 @@ use std::{collections::HashMap, sync::LazyLock}; +use pumpkin_data::{chunk::Biome, tag::Taggable}; use pumpkin_util::read_data_from_file; use serde::Deserialize; -use crate::generation::structure::placement::StructurePlacement; +use crate::{ + ProtoChunk, + generation::structure::{ + placement::StructurePlacement, + structures::{ + StructureGenerator, StructurePosition, buried_treasure::BuriedTreasureGenerator, + nether_fortress::NetherFortressGenerator, + }, + }, +}; pub mod placement; pub mod structures; @@ -11,7 +21,61 @@ pub mod structures; #[derive(Deserialize)] pub struct StructureSet { pub placement: StructurePlacement, + pub structures: Vec, } +#[derive(Deserialize)] +pub struct Structures { + pub structure: StructureType, +} + +#[derive(Deserialize, Clone)] +pub enum StructureType { + #[serde(rename = "minecraft:buried_treasure")] + BuriedTreasure(BuriedTreasureGenerator), + #[serde(rename = "minecraft:fortress")] + NetherFortress(NetherFortressGenerator), +} + +impl StructureType { + pub fn get_structure_position( + &self, + name: &str, + chunk: &ProtoChunk, + ) -> Option { + let position = match self { + StructureType::BuriedTreasure(generator) => generator.get_structure_position(chunk), + StructureType::NetherFortress(generator) => generator.get_structure_position(chunk), + }; + if let Some(structure) = STRUCTURS.get(name) { + let current_biome = chunk.get_biome(&position.position.0); + if Biome::get_tag_values(&structure.biomes) + .unwrap() + .contains(¤t_biome.registry_id) + { + return Some(position); + } + } + None + } + + pub fn generate(&self, position: StructurePosition, chunk: &mut crate::ProtoChunk) { + for pos in position.generator.pieces_positions { + match self { + StructureType::BuriedTreasure(generator) => generator.generate(pos, chunk), + StructureType::NetherFortress(generator) => generator.generate(pos, chunk), + } + } + } +} + +#[derive(Deserialize, Clone, PartialEq, Eq, Hash)] +pub struct Structure { + biomes: String, +} + +pub static STRUCTURS: LazyLock> = + LazyLock::new(|| read_data_from_file!("../../../assets/structure.json")); + pub static STRUCTURE_SETS: LazyLock> = LazyLock::new(|| read_data_from_file!("../../../assets/structure_set.json")); diff --git a/pumpkin-world/src/generation/structure/structures/buried_treasure.rs b/pumpkin-world/src/generation/structure/structures/buried_treasure.rs index 4746aaf3f..665fbe75f 100644 --- a/pumpkin-world/src/generation/structure/structures/buried_treasure.rs +++ b/pumpkin-world/src/generation/structure/structures/buried_treasure.rs @@ -3,25 +3,25 @@ use pumpkin_util::{ HeightMap, math::{position::BlockPos, vector2::Vector2, vector3::Vector3}, }; +use serde::Deserialize; use crate::{ ProtoChunk, generation::{ height_limit::HeightLimitView, positions::chunk_pos::{get_center_x, get_center_z, get_offset_x, get_offset_z}, - structure::structures::{Structure, StructurePiecesCollector, StructurePosition}, + structure::structures::{StructureGenerator, StructurePiecesCollector, StructurePosition}, }, }; -pub struct BuriedTreasureGenerator { - position: BlockPos, -} +#[derive(Deserialize, Clone)] +pub struct BuriedTreasureGenerator; -impl Structure for BuriedTreasureGenerator { +impl StructureGenerator for BuriedTreasureGenerator { fn get_structure_position(&self, chunk: &ProtoChunk) -> super::StructurePosition { let x = get_center_x(chunk.chunk_pos.x); let z = get_center_z(chunk.chunk_pos.y); - let y = chunk.get_top_y(&HeightMap::OceanFloorWg, &Vector2::new(x, z)); + let y = chunk.get_top_y(&HeightMap::OceanFloorWg, &Vector2::new(x, z)) - 1; let generator = StructurePiecesCollector { pieces_positions: vec![BlockPos::new( get_offset_x(chunk.chunk_pos.x, 9), @@ -35,12 +35,12 @@ impl Structure for BuriedTreasureGenerator { } } - fn generate(&self, chunk: &mut crate::ProtoChunk) { + fn generate(&self, position: BlockPos, chunk: &mut crate::ProtoChunk) { let y = chunk.get_top_y( &HeightMap::OceanFloorWg, - &Vector2::new(self.position.0.x, self.position.0.z), + &Vector2::new(position.0.x, position.0.z), ); - let mut pos = BlockPos::new(self.position.0.x, y, self.position.0.z); + let mut pos = BlockPos::new(position.0.x, y, position.0.z); for _ in y..chunk.bottom_y() as i32 { let state = chunk.get_block_state(&pos.0); let down_raw_state = chunk.get_block_state(&pos.down().0); diff --git a/pumpkin-world/src/generation/structure/structures/mod.rs b/pumpkin-world/src/generation/structure/structures/mod.rs index 41a7d49d9..ba821cf3f 100644 --- a/pumpkin-world/src/generation/structure/structures/mod.rs +++ b/pumpkin-world/src/generation/structure/structures/mod.rs @@ -3,19 +3,21 @@ use pumpkin_util::math::position::BlockPos; use crate::ProtoChunk; pub mod buried_treasure; +pub mod nether_fortress; -pub trait Structure { +pub trait StructureGenerator { fn get_structure_position(&self, chunk: &ProtoChunk) -> StructurePosition; - fn generate(&self, chunk: &mut crate::ProtoChunk); + fn generate(&self, position: BlockPos, chunk: &mut crate::ProtoChunk); } +#[derive(Clone)] pub struct StructurePosition { - position: BlockPos, - generator: StructurePiecesCollector, + pub position: BlockPos, + pub generator: StructurePiecesCollector, } -#[derive(Default)] +#[derive(Default, Clone)] pub struct StructurePiecesCollector { - pieces_positions: Vec, + pub pieces_positions: Vec, } diff --git a/pumpkin-world/src/generation/structure/structures/nether_fortress.rs b/pumpkin-world/src/generation/structure/structures/nether_fortress.rs new file mode 100644 index 000000000..05a257385 --- /dev/null +++ b/pumpkin-world/src/generation/structure/structures/nether_fortress.rs @@ -0,0 +1,30 @@ +use pumpkin_util::math::position::BlockPos; +use serde::Deserialize; + +use crate::{ + ProtoChunk, + generation::{ + positions::chunk_pos, + structure::structures::{StructureGenerator, StructurePiecesCollector, StructurePosition}, + }, +}; + +#[derive(Deserialize, Clone)] +pub struct NetherFortressGenerator; + +impl StructureGenerator for NetherFortressGenerator { + fn get_structure_position(&self, chunk: &ProtoChunk) -> StructurePosition { + let chunk_pos = chunk.chunk_pos; + let start_x = chunk_pos::start_block_x(&chunk_pos); + let start_z = chunk_pos::start_block_z(&chunk_pos); + let generator = StructurePiecesCollector { + pieces_positions: vec![], // TODO + }; + + StructurePosition { + position: BlockPos::new(start_x, 64, start_z), + generator, + } + } + fn generate(&self, _position: BlockPos, _chunk: &mut crate::ProtoChunk) {} +} diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 2036e25ca..f988b4b71 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -54,7 +54,7 @@ rsa = { version = "=0.10.0-rc.4", features = ["sha1"] } rsa-der = "0.3" # authentication -ureq = { version = "3.0.12", features = [ +ureq = { version = "3.1.0", features = [ "json", ] }