Add structures

this is by far not done and the implementation is not correct in many ways, but it is still something
This commit is contained in:
Alexander Medvedev 2025-08-17 22:12:38 +02:00
parent b741881729
commit 53cef4b050
15 changed files with 859 additions and 95 deletions

71
Cargo.lock generated
View File

@ -269,9 +269,9 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.1" version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@ -317,9 +317,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.27" version = "1.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@ -489,9 +489,9 @@ dependencies = [
[[package]] [[package]]
name = "cookie_store" name = "cookie_store"
version = "0.21.1" version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" checksum = "3fc4bff745c9b4c7fb1e97b25d13153da2bc7796260141df62378998d070207f"
dependencies = [ dependencies = [
"cookie", "cookie",
"document-features", "document-features",
@ -545,9 +545,9 @@ dependencies = [
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.4.2" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -1106,9 +1106,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.4" version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [ dependencies = [
"allocator-api2", "allocator-api2",
"equivalent", "equivalent",
@ -1389,7 +1389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.15.4", "hashbrown 0.15.5",
"serde", "serde",
] ]
@ -1485,9 +1485,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.174" version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -1519,9 +1519,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]] [[package]]
name = "litrs" name = "litrs"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -1545,7 +1545,7 @@ version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86ea4e65087ff52f3862caff188d489f1fab49a0cb09e01b2e3f1a617b10aaed" checksum = "86ea4e65087ff52f3862caff188d489f1fab49a0cb09e01b2e3f1a617b10aaed"
dependencies = [ dependencies = [
"hashbrown 0.15.4", "hashbrown 0.15.5",
] ]
[[package]] [[package]]
@ -1981,9 +1981,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.95" version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -2459,9 +2459,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.28" version = "0.23.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
dependencies = [ dependencies = [
"log", "log",
"once_cell", "once_cell",
@ -2492,9 +2492,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.103.3" version = "0.103.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
dependencies = [ dependencies = [
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
@ -2574,9 +2574,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.140" version = "1.0.142"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -3229,9 +3229,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]] [[package]]
name = "ureq" name = "ureq"
version = "3.0.12" version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f0fde9bc91026e381155f8c67cb354bcd35260b2f4a29bcc84639f762760c39" checksum = "00432f493971db5d8e47a65aeb3b02f8226b9b11f1450ff86bb772776ebadd70"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"cookie_store", "cookie_store",
@ -3245,14 +3245,14 @@ dependencies = [
"serde_json", "serde_json",
"ureq-proto", "ureq-proto",
"utf-8", "utf-8",
"webpki-roots 0.26.11", "webpki-roots",
] ]
[[package]] [[package]]
name = "ureq-proto" name = "ureq-proto"
version = "0.4.2" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59db78ad1923f2b1be62b6da81fe80b173605ca0d57f85da2e005382adf693f7" checksum = "c5b6cabebbecc4c45189ab06b52f956206cea7d8c8a20851c35a85cb169224cc"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"http", "http",
@ -3408,18 +3408,9 @@ dependencies = [
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "0.26.11" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
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"
dependencies = [ dependencies = [
"rustls-pki-types", "rustls-pki-types",
] ]

675
assets/structures.json Normal file
View File

@ -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"
}
}

View File

@ -30,7 +30,7 @@ cfb8 = "0.8"
async-compression = { version = "0.4.27", features = ["tokio", "zlib"] } async-compression = { version = "0.4.27", features = ["tokio", "zlib"] }
take_mut = "0.2.2" take_mut = "0.2.2"
bitflags = "2.9.1" bitflags = "2.9.2"
[dev-dependencies] [dev-dependencies]
# Validate correctness # Validate correctness

View File

@ -26,7 +26,7 @@ crossbeam.workspace = true
num-derive = "0.4" num-derive = "0.4"
sha2 = "0.10" sha2 = "0.10"
bitflags = "2.9.1" bitflags = "2.9.2"
dashmap = "6.1" dashmap = "6.1"

View File

@ -43,6 +43,10 @@ impl BlockStateCodec {
BlockState::from_id(state_id) 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 /// Prefer this over `get_state` when the only the state ID is needed
pub fn get_state_id(&self) -> BlockStateId { pub fn get_state_id(&self) -> BlockStateId {
let block = self.name; let block = self.name;

View File

@ -9,12 +9,6 @@ pub struct RawBlockState(pub BlockStateId);
impl RawBlockState { impl RawBlockState {
pub const AIR: RawBlockState = RawBlockState(0); pub const AIR: RawBlockState = RawBlockState(0);
/// Get a Block from the Vanilla Block registry at Runtime
pub fn new(registry_id: &str) -> Option<Self> {
let block = Block::from_name(registry_id);
block.map(|block| Self(block.default_state.id))
}
#[inline] #[inline]
pub fn to_state(&self) -> &'static BlockState { pub fn to_state(&self) -> &'static BlockState {
BlockState::from_id(self.0) BlockState::from_id(self.0)
@ -25,20 +19,3 @@ impl RawBlockState {
Block::from_state_id(self.0) 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());
}
}

View File

@ -217,14 +217,9 @@ impl WouldSurviveBlockPredicate {
chunk: &ProtoChunk<'_>, chunk: &ProtoChunk<'_>,
pos: &BlockPos, pos: &BlockPos,
) -> bool { ) -> bool {
let state = self.state.get_state(); let block = self.state.get_block();
let pos = self.offset.get(pos); let pos = self.offset.get(pos);
block_registry.can_place_at( block_registry.can_place_at(block, chunk, &pos, BlockDirection::Up)
Block::from_state_id(state.id),
chunk,
&pos,
BlockDirection::Up,
)
} }
} }

View File

@ -29,8 +29,7 @@ impl ReplaceBlobsFeature {
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
) -> bool { ) -> bool {
let target = self.target.get_state(); let target = self.target.get_block();
let target = Block::from_state_id(target.id);
let state = self.state.get_state(); let state = self.state.get_state();
let Some(pos) = Self::move_down_to_target(pos, chunk, target) else { let Some(pos) = Self::move_down_to_target(pos, chunk, target) else {
return false; return false;

View File

@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
@ -12,8 +13,9 @@ use pumpkin_util::{
}; };
use crate::generation::noise::perlin::DoublePerlinNoiseSampler; use crate::generation::noise::perlin::DoublePerlinNoiseSampler;
use crate::generation::structure::STRUCTURE_SETS;
use crate::generation::structure::placement::StructurePlacementCalculator; use crate::generation::structure::placement::StructurePlacementCalculator;
use crate::generation::structure::structures::StructurePosition;
use crate::generation::structure::{STRUCTURE_SETS, STRUCTURS, Structure, StructureType};
use crate::{ use crate::{
BlockStateId, BlockStateId,
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed}, 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_height_map: Box<[i16]>,
pub flat_motion_blocking_no_leaves_height_map: Box<[i16]>, pub flat_motion_blocking_no_leaves_height_map: Box<[i16]>,
// may want to use chunk status // may want to use chunk status
structure_starts: HashMap<Structure, (StructurePosition, StructureType)>,
} }
pub struct TerrainCache { pub struct TerrainCache {
@ -234,6 +237,7 @@ impl<'a> ProtoChunk<'a> {
flat_ocean_floor_height_map: default_heightmap.clone(), flat_ocean_floor_height_map: default_heightmap.clone(),
flat_motion_blocking_height_map: default_heightmap.clone(), flat_motion_blocking_height_map: default_heightmap.clone(),
flat_motion_blocking_no_leaves_height_map: default_heightmap, flat_motion_blocking_no_leaves_height_map: default_heightmap,
structure_starts: HashMap::new(),
} }
} }
@ -732,6 +736,10 @@ impl<'a> ProtoChunk<'a> {
let population_seed = let population_seed =
Xoroshiro::get_population_seed(self.random_config.seed, block_pos.0.x, block_pos.0.z); 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 // TODO: This needs to be different depending on what biomes are in the chunk -> affects the
// random // random
for (name, feature) in PLACED_FEATURES.iter() { for (name, feature) in PLACED_FEATURES.iter() {
@ -751,14 +759,33 @@ impl<'a> ProtoChunk<'a> {
} }
} }
pub fn set_structure_starts(&self) { pub fn set_structure_starts(&mut self) {
for (_name, set) in STRUCTURE_SETS.iter() { for (name, set) in STRUCTURE_SETS.iter() {
let calculator = StructurePlacementCalculator { let calculator = StructurePlacementCalculator {
seed: self.random_config.seed as i64, 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) { if !set.placement.should_generate(calculator, self.chunk_pos) {
continue; // ?? 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
} }
} }

View File

@ -10,6 +10,6 @@ pub struct BlockStateMatchRuleTest {
impl BlockStateMatchRuleTest { impl BlockStateMatchRuleTest {
pub fn test(&self, state: &BlockState) -> bool { pub fn test(&self, state: &BlockState) -> bool {
state.id == self.block_state.get_state().id state.id == self.block_state.get_state_id()
} }
} }

View File

@ -1,9 +1,19 @@
use std::{collections::HashMap, sync::LazyLock}; use std::{collections::HashMap, sync::LazyLock};
use pumpkin_data::{chunk::Biome, tag::Taggable};
use pumpkin_util::read_data_from_file; use pumpkin_util::read_data_from_file;
use serde::Deserialize; 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 placement;
pub mod structures; pub mod structures;
@ -11,7 +21,61 @@ pub mod structures;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct StructureSet { pub struct StructureSet {
pub placement: StructurePlacement, pub placement: StructurePlacement,
pub structures: Vec<Structures>,
} }
#[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<StructurePosition> {
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(&current_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<HashMap<String, Structure>> =
LazyLock::new(|| read_data_from_file!("../../../assets/structure.json"));
pub static STRUCTURE_SETS: LazyLock<HashMap<String, StructureSet>> = pub static STRUCTURE_SETS: LazyLock<HashMap<String, StructureSet>> =
LazyLock::new(|| read_data_from_file!("../../../assets/structure_set.json")); LazyLock::new(|| read_data_from_file!("../../../assets/structure_set.json"));

View File

@ -3,25 +3,25 @@ use pumpkin_util::{
HeightMap, HeightMap,
math::{position::BlockPos, vector2::Vector2, vector3::Vector3}, math::{position::BlockPos, vector2::Vector2, vector3::Vector3},
}; };
use serde::Deserialize;
use crate::{ use crate::{
ProtoChunk, ProtoChunk,
generation::{ generation::{
height_limit::HeightLimitView, height_limit::HeightLimitView,
positions::chunk_pos::{get_center_x, get_center_z, get_offset_x, get_offset_z}, 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 { #[derive(Deserialize, Clone)]
position: BlockPos, pub struct BuriedTreasureGenerator;
}
impl Structure for BuriedTreasureGenerator { impl StructureGenerator for BuriedTreasureGenerator {
fn get_structure_position(&self, chunk: &ProtoChunk) -> super::StructurePosition { fn get_structure_position(&self, chunk: &ProtoChunk) -> super::StructurePosition {
let x = get_center_x(chunk.chunk_pos.x); let x = get_center_x(chunk.chunk_pos.x);
let z = get_center_z(chunk.chunk_pos.y); 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 { let generator = StructurePiecesCollector {
pieces_positions: vec![BlockPos::new( pieces_positions: vec![BlockPos::new(
get_offset_x(chunk.chunk_pos.x, 9), 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( let y = chunk.get_top_y(
&HeightMap::OceanFloorWg, &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 { for _ in y..chunk.bottom_y() as i32 {
let state = chunk.get_block_state(&pos.0); let state = chunk.get_block_state(&pos.0);
let down_raw_state = chunk.get_block_state(&pos.down().0); let down_raw_state = chunk.get_block_state(&pos.down().0);

View File

@ -3,19 +3,21 @@ use pumpkin_util::math::position::BlockPos;
use crate::ProtoChunk; use crate::ProtoChunk;
pub mod buried_treasure; pub mod buried_treasure;
pub mod nether_fortress;
pub trait Structure { pub trait StructureGenerator {
fn get_structure_position(&self, chunk: &ProtoChunk) -> StructurePosition; 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 { pub struct StructurePosition {
position: BlockPos, pub position: BlockPos,
generator: StructurePiecesCollector, pub generator: StructurePiecesCollector,
} }
#[derive(Default)] #[derive(Default, Clone)]
pub struct StructurePiecesCollector { pub struct StructurePiecesCollector {
pieces_positions: Vec<BlockPos>, pub pieces_positions: Vec<BlockPos>,
} }

View File

@ -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) {}
}

View File

@ -54,7 +54,7 @@ rsa = { version = "=0.10.0-rc.4", features = ["sha1"] }
rsa-der = "0.3" rsa-der = "0.3"
# authentication # authentication
ureq = { version = "3.0.12", features = [ ureq = { version = "3.1.0", features = [
"json", "json",
] } ] }