pumpkin-world(structures): Add structure placement calculation
This commit is contained in:
parent
f63a039918
commit
fae24008db
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -2264,9 +2264,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
@ -2274,9 +2274,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon-core"
|
name = "rayon-core"
|
||||||
version = "1.12.1"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-deque",
|
"crossbeam-deque",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
|||||||
@ -48,7 +48,7 @@ bytes = "1.10"
|
|||||||
|
|
||||||
# Concurrency/Parallelism and Synchronization
|
# Concurrency/Parallelism and Synchronization
|
||||||
futures = { version = "0.3", default-features = false, features = ["executor"] }
|
futures = { version = "0.3", default-features = false, features = ["executor"] }
|
||||||
rayon = "1.10"
|
rayon = "1.11"
|
||||||
crossbeam = "0.8"
|
crossbeam = "0.8"
|
||||||
|
|
||||||
uuid = { version = "1.18", features = ["serde", "v3", "v4"] }
|
uuid = { version = "1.18", features = ["serde", "v3", "v4"] }
|
||||||
|
|||||||
358
assets/structure_set.json
Normal file
358
assets/structure_set.json
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
{
|
||||||
|
"ancient_cities": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ancient_city",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 24,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 20083232,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buried_treasures": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:buried_treasure",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 1,
|
||||||
|
"separation": 0,
|
||||||
|
"locate_offset": [
|
||||||
|
9,
|
||||||
|
0,
|
||||||
|
9
|
||||||
|
],
|
||||||
|
"frequency_reduction_method": "legacy_type_2",
|
||||||
|
"frequency": 0.01,
|
||||||
|
"salt": 0,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"desert_pyramids": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:desert_pyramid",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 32,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 14357617,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"end_cities": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:end_city",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 20,
|
||||||
|
"separation": 11,
|
||||||
|
"spread_type": "triangular",
|
||||||
|
"salt": 10387313,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"igloos": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:igloo",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 32,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 14357618,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jungle_temples": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:jungle_pyramid",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 32,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 14357619,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mineshafts": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:mineshaft",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:mineshaft_mesa",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 1,
|
||||||
|
"separation": 0,
|
||||||
|
"frequency_reduction_method": "legacy_type_3",
|
||||||
|
"frequency": 0.004,
|
||||||
|
"salt": 0,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nether_complexes": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:fortress",
|
||||||
|
"weight": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:bastion_remnant",
|
||||||
|
"weight": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 27,
|
||||||
|
"separation": 4,
|
||||||
|
"salt": 30084232,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nether_fossils": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:nether_fossil",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 2,
|
||||||
|
"separation": 1,
|
||||||
|
"salt": 14357921,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ocean_monuments": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:monument",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 32,
|
||||||
|
"separation": 5,
|
||||||
|
"spread_type": "triangular",
|
||||||
|
"salt": 10387313,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ocean_ruins": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ocean_ruin_cold",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ocean_ruin_warm",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 20,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 14357621,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pillager_outposts": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:pillager_outpost",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"exclusion_zone": {
|
||||||
|
"other_set": "minecraft:villages",
|
||||||
|
"chunk_count": 10
|
||||||
|
},
|
||||||
|
"spacing": 32,
|
||||||
|
"separation": 8,
|
||||||
|
"frequency_reduction_method": "legacy_type_1",
|
||||||
|
"frequency": 0.2,
|
||||||
|
"salt": 165745296,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ruined_portals": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ruined_portal",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ruined_portal_desert",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ruined_portal_jungle",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ruined_portal_swamp",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ruined_portal_mountain",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ruined_portal_ocean",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:ruined_portal_nether",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 40,
|
||||||
|
"separation": 15,
|
||||||
|
"salt": 34222645,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shipwrecks": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:shipwreck",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:shipwreck_beached",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 24,
|
||||||
|
"separation": 4,
|
||||||
|
"salt": 165745295,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strongholds": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:stronghold",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spread": 3,
|
||||||
|
"count": 128,
|
||||||
|
"preferred_biomes": "#minecraft:stronghold_biased_to",
|
||||||
|
"distance": 32,
|
||||||
|
"salt": 0,
|
||||||
|
"type": "minecraft:concentric_rings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"swamp_huts": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:swamp_hut",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 32,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 14357620,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"trail_ruins": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:trail_ruins",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 34,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 83469867,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"trial_chambers": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:trial_chambers",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 34,
|
||||||
|
"separation": 12,
|
||||||
|
"salt": 94251327,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"villages": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:village_plains",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:village_desert",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:village_savanna",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:village_snowy",
|
||||||
|
"weight": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"structure": "minecraft:village_taiga",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 34,
|
||||||
|
"separation": 8,
|
||||||
|
"salt": 10387312,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"woodland_mansions": {
|
||||||
|
"structures": [
|
||||||
|
{
|
||||||
|
"structure": "minecraft:mansion",
|
||||||
|
"weight": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placement": {
|
||||||
|
"spacing": 80,
|
||||||
|
"separation": 20,
|
||||||
|
"spread_type": "triangular",
|
||||||
|
"salt": 10387319,
|
||||||
|
"type": "minecraft:random_spread"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -68,6 +68,30 @@ pub fn get_decorator_seed(population_seed: u64, index: usize, step: usize) -> u6
|
|||||||
.wrapping_add(10_000u64.wrapping_mul(step as u64))
|
.wrapping_add(10_000u64.wrapping_mul(step as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_region_seed(world_seed: u64, region_x: i32, region_z: i32, salt: i32) -> u64 {
|
||||||
|
let region_x_long: u64 = region_x as u64;
|
||||||
|
let region_z_long: u64 = region_z as u64;
|
||||||
|
let salt_long: u64 = salt as u64;
|
||||||
|
region_x_long
|
||||||
|
.wrapping_mul(341873128712)
|
||||||
|
.wrapping_add(region_z_long.wrapping_mul(132897987541))
|
||||||
|
.wrapping_add(world_seed)
|
||||||
|
.wrapping_add(salt_long)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_carver_seed(
|
||||||
|
random: &mut RandomGenerator,
|
||||||
|
world_seed: u64,
|
||||||
|
chunk_x: i32,
|
||||||
|
chunk_z: i32,
|
||||||
|
) -> u64 {
|
||||||
|
let x = random.next_i64();
|
||||||
|
let z = random.next_i64();
|
||||||
|
(chunk_x as u64).wrapping_mul(x as u64) ^ (chunk_z as u64).wrapping_mul(z as u64) ^ world_seed
|
||||||
|
}
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait RandomImpl {
|
pub trait RandomImpl {
|
||||||
fn split(&mut self) -> Self;
|
fn split(&mut self) -> Self;
|
||||||
|
|||||||
@ -4,9 +4,9 @@ use crate::inventory::{Clearable, Inventory, split_stack};
|
|||||||
use crate::item::ItemStack;
|
use crate::item::ItemStack;
|
||||||
use crate::world::SimpleWorld;
|
use crate::world::SimpleWorld;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use pumpkin_data::Block;
|
|
||||||
use pumpkin_data::block_properties::{BlockProperties, HopperFacing, HopperLikeProperties};
|
use pumpkin_data::block_properties::{BlockProperties, HopperFacing, HopperLikeProperties};
|
||||||
use pumpkin_data::tag::Taggable;
|
use pumpkin_data::tag::Taggable;
|
||||||
|
use pumpkin_data::{Block, tag};
|
||||||
use pumpkin_nbt::tag::NbtTag;
|
use pumpkin_nbt::tag::NbtTag;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
@ -184,9 +184,7 @@ impl HopperBlockEntity {
|
|||||||
}
|
}
|
||||||
let (block, state) = world.get_block_and_state(pos_up).await;
|
let (block, state) = world.get_block_and_state(pos_up).await;
|
||||||
if !(state.is_solid()
|
if !(state.is_solid()
|
||||||
&& block
|
&& block.is_tagged_with_by_tag(&tag::Block::MINECRAFT_DOES_NOT_BLOCK_HOPPERS))
|
||||||
.is_tagged_with("minecraft:does_not_block_hoppers")
|
|
||||||
.unwrap())
|
|
||||||
{
|
{
|
||||||
// TODO getItemsAtAndAbove(level, hopper)
|
// TODO getItemsAtAndAbove(level, hopper)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -37,7 +37,7 @@ pub const CHUNK_COUNT: usize = REGION_SIZE * REGION_SIZE;
|
|||||||
/// The number of bytes in a sector (4 KiB)
|
/// The number of bytes in a sector (4 KiB)
|
||||||
const SECTOR_BYTES: usize = 4096;
|
const SECTOR_BYTES: usize = 4096;
|
||||||
|
|
||||||
// 1.21.7
|
// 1.21.8
|
||||||
pub const WORLD_DATA_VERSION: i32 = 4438;
|
pub const WORLD_DATA_VERSION: i32 = 4438;
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
|||||||
@ -102,7 +102,7 @@ impl WorldGenerator for VanillaGenerator {
|
|||||||
proto_chunk.populate_biomes(self.dimension);
|
proto_chunk.populate_biomes(self.dimension);
|
||||||
proto_chunk.populate_noise();
|
proto_chunk.populate_noise();
|
||||||
proto_chunk.build_surface();
|
proto_chunk.build_surface();
|
||||||
proto_chunk.generate_features(level, block_registry);
|
proto_chunk.generate_features_and_structure(level, block_registry);
|
||||||
|
|
||||||
for y in 0..biome_coords::from_block(generation_settings.shape.height) {
|
for y in 0..biome_coords::from_block(generation_settings.shape.height) {
|
||||||
let relative_y = y as usize;
|
let relative_y = y as usize;
|
||||||
|
|||||||
@ -19,6 +19,7 @@ pub mod rule;
|
|||||||
mod rule_test;
|
mod rule_test;
|
||||||
mod seed;
|
mod seed;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
pub mod structure;
|
||||||
mod surface;
|
mod surface;
|
||||||
pub mod y_offset;
|
pub mod y_offset;
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,8 @@ 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::{
|
use crate::{
|
||||||
BlockStateId,
|
BlockStateId,
|
||||||
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed},
|
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed},
|
||||||
@ -702,7 +704,7 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This generates "Features," also known as decorations, which include things like trees, grass, ores, and more.
|
/// This generates "Structure Pieces" and "Features" also known as decorations, which include things like trees, grass, ores, and more.
|
||||||
/// Essentially, it encompasses everything above the surface or underground. It's crucial that this step is executed after biomes are generated,
|
/// Essentially, it encompasses everything above the surface or underground. It's crucial that this step is executed after biomes are generated,
|
||||||
/// as the decoration directly depends on the biome. Similarly, running this after the surface is built is logical, as it often involves checking block types.
|
/// as the decoration directly depends on the biome. Similarly, running this after the surface is built is logical, as it often involves checking block types.
|
||||||
/// For example, flowers are typically placed only on grass blocks.
|
/// For example, flowers are typically placed only on grass blocks.
|
||||||
@ -711,7 +713,11 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
///
|
///
|
||||||
/// 1. First, we determine **whether** to generate a feature and **at which block positions** to place it.
|
/// 1. First, we determine **whether** to generate a feature and **at which block positions** to place it.
|
||||||
/// 2. Then, using the second file, we determine **how** to generate the feature.
|
/// 2. Then, using the second file, we determine **how** to generate the feature.
|
||||||
pub fn generate_features(&mut self, level: &Arc<Level>, block_registry: &dyn BlockRegistryExt) {
|
pub fn generate_features_and_structure(
|
||||||
|
&mut self,
|
||||||
|
level: &Arc<Level>,
|
||||||
|
block_registry: &dyn BlockRegistryExt,
|
||||||
|
) {
|
||||||
let chunk_pos = self.chunk_pos;
|
let chunk_pos = self.chunk_pos;
|
||||||
let min_y = self.noise_sampler.min_y();
|
let min_y = self.noise_sampler.min_y();
|
||||||
let height = self.noise_sampler.height();
|
let height = self.noise_sampler.height();
|
||||||
@ -745,6 +751,17 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_structure_starts(&self) {
|
||||||
|
for (_name, set) in STRUCTURE_SETS.iter() {
|
||||||
|
let calculator = StructurePlacementCalculator {
|
||||||
|
seed: self.random_config.seed as i64,
|
||||||
|
};
|
||||||
|
if !set.placement.should_generate(calculator, self.chunk_pos) {
|
||||||
|
continue; // ??
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start_cell_x(&self) -> i32 {
|
fn start_cell_x(&self) -> i32 {
|
||||||
self.start_block_x() / self.noise_sampler.horizontal_cell_block_count() as i32
|
self.start_block_x() / self.noise_sampler.horizontal_cell_block_count() as i32
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
use std::{collections::HashMap, sync::LazyLock};
|
||||||
|
|
||||||
|
use pumpkin_util::read_data_from_file;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::generation::structure::placement::StructurePlacement;
|
||||||
|
|
||||||
|
pub mod placement;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct StructureSet {
|
||||||
|
pub placement: StructurePlacement,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static STRUCTURE_SETS: LazyLock<HashMap<String, StructureSet>> =
|
||||||
|
LazyLock::new(|| read_data_from_file!("../../../assets/structure_set.json"));
|
||||||
167
pumpkin-world/src/generation/structure/placement.rs
Normal file
167
pumpkin-world/src/generation/structure/placement.rs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
use pumpkin_util::{
|
||||||
|
math::{floor_div, vector2::Vector2},
|
||||||
|
random::{
|
||||||
|
RandomGenerator, RandomImpl, get_carver_seed, get_region_seed, xoroshiro128::Xoroshiro,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct StructurePlacement {
|
||||||
|
frequency_reduction_method: Option<FrequencyReductionMethod>,
|
||||||
|
frequency: Option<f32>,
|
||||||
|
salt: i32,
|
||||||
|
#[serde(flatten)]
|
||||||
|
r#type: StructurePlacementType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructurePlacement {
|
||||||
|
pub fn should_generate(
|
||||||
|
&self,
|
||||||
|
calculator: StructurePlacementCalculator,
|
||||||
|
chunk_pos: Vector2<i32>,
|
||||||
|
) -> bool {
|
||||||
|
self.r#type
|
||||||
|
.is_start_chunk(&calculator, chunk_pos, self.salt)
|
||||||
|
&& self.apply_frequency_reduction(calculator.seed, chunk_pos)
|
||||||
|
// TODO: add exclusion_zone, only used for pillager_outposts
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_frequency_reduction(&self, seed: i64, chunk_pos: Vector2<i32>) -> bool {
|
||||||
|
let frequency = self.frequency.unwrap_or(1.0);
|
||||||
|
frequency >= 1.0
|
||||||
|
|| self
|
||||||
|
.frequency_reduction_method
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&FrequencyReductionMethod::Default)
|
||||||
|
.should_generate(seed, chunk_pos, self.salt, frequency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum FrequencyReductionMethod {
|
||||||
|
Default,
|
||||||
|
LegacyType1,
|
||||||
|
LegacyType2,
|
||||||
|
LegacyType3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrequencyReductionMethod {
|
||||||
|
pub fn should_generate(
|
||||||
|
&self,
|
||||||
|
seed: i64,
|
||||||
|
chunk_pos: Vector2<i32>,
|
||||||
|
salt: i32,
|
||||||
|
frequency: f32,
|
||||||
|
) -> bool {
|
||||||
|
match self {
|
||||||
|
FrequencyReductionMethod::Default => {
|
||||||
|
let region_seed = get_region_seed(seed as u64, chunk_pos.x, chunk_pos.y, salt);
|
||||||
|
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed));
|
||||||
|
random.next_f32() < frequency
|
||||||
|
}
|
||||||
|
FrequencyReductionMethod::LegacyType1 => {
|
||||||
|
let x = chunk_pos.x >> 4;
|
||||||
|
let z = chunk_pos.y >> 4;
|
||||||
|
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(
|
||||||
|
(x ^ z << 4) as u64 ^ seed as u64,
|
||||||
|
));
|
||||||
|
random.next_i32(); // yeah mojang just does that and does not use the value
|
||||||
|
random.next_bounded_i32((1.0 / frequency) as i32) == 0
|
||||||
|
}
|
||||||
|
FrequencyReductionMethod::LegacyType2 => {
|
||||||
|
let region_seed = get_region_seed(seed as u64, chunk_pos.x, chunk_pos.y, 10387320);
|
||||||
|
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed));
|
||||||
|
random.next_f32() < frequency
|
||||||
|
}
|
||||||
|
FrequencyReductionMethod::LegacyType3 => {
|
||||||
|
let mut random: RandomGenerator =
|
||||||
|
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(seed as u64));
|
||||||
|
let carver_seed =
|
||||||
|
get_carver_seed(&mut random, seed as u64, chunk_pos.x, chunk_pos.y);
|
||||||
|
let mut random: RandomGenerator =
|
||||||
|
RandomGenerator::Xoroshiro(Xoroshiro::from_seed(carver_seed));
|
||||||
|
|
||||||
|
random.next_f64() < frequency as f64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum StructurePlacementType {
|
||||||
|
#[serde(rename = "minecraft:random_spread")]
|
||||||
|
RandomSpread(RandomSpreadStructurePlacement),
|
||||||
|
#[serde(rename = "minecraft:concentric_rings")]
|
||||||
|
ConcentricRings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructurePlacementType {
|
||||||
|
pub fn is_start_chunk(
|
||||||
|
&self,
|
||||||
|
calculator: &StructurePlacementCalculator,
|
||||||
|
chunk_pos: Vector2<i32>,
|
||||||
|
salt: i32,
|
||||||
|
) -> bool {
|
||||||
|
match self {
|
||||||
|
StructurePlacementType::RandomSpread(placement) => {
|
||||||
|
placement.is_start_chunk(calculator, chunk_pos, salt)
|
||||||
|
}
|
||||||
|
StructurePlacementType::ConcentricRings => false, // TODO, This is needed for Stronghold, since it is placed in rings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct RandomSpreadStructurePlacement {
|
||||||
|
spacing: i32,
|
||||||
|
separation: i32,
|
||||||
|
spread_type: SpreadType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum SpreadType {
|
||||||
|
Linear,
|
||||||
|
Triangular,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpreadType {
|
||||||
|
pub fn get(&self, random: &mut RandomGenerator, bound: i32) -> i32 {
|
||||||
|
match self {
|
||||||
|
SpreadType::Linear => random.next_bounded_i32(bound),
|
||||||
|
SpreadType::Triangular => {
|
||||||
|
(random.next_bounded_i32(bound) + random.next_bounded_i32(bound)) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RandomSpreadStructurePlacement {
|
||||||
|
fn get_start_chunk(&self, seed: i64, chunk_pos: Vector2<i32>, salt: i32) -> Vector2<i32> {
|
||||||
|
let x = floor_div(chunk_pos.x, self.spacing);
|
||||||
|
let z = floor_div(chunk_pos.y, self.spacing);
|
||||||
|
let region_seed = get_region_seed(seed as u64, x, z, salt);
|
||||||
|
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed));
|
||||||
|
let bound = self.spacing - self.separation;
|
||||||
|
let rand_x = self.spread_type.get(&mut random, bound);
|
||||||
|
let rand_z = self.spread_type.get(&mut random, bound);
|
||||||
|
Vector2::new(x * self.spacing + rand_x, z * self.spacing + rand_z)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_start_chunk(
|
||||||
|
&self,
|
||||||
|
calculator: &StructurePlacementCalculator,
|
||||||
|
chunk_pos: Vector2<i32>,
|
||||||
|
salt: i32,
|
||||||
|
) -> bool {
|
||||||
|
let pos = self.get_start_chunk(calculator.seed, chunk_pos, salt);
|
||||||
|
pos == chunk_pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StructurePlacementCalculator {
|
||||||
|
pub seed: i64,
|
||||||
|
}
|
||||||
@ -1,54 +1,42 @@
|
|||||||
|
use pumpkin_data::tag;
|
||||||
use pumpkin_data::tag::Taggable;
|
use pumpkin_data::tag::Taggable;
|
||||||
|
|
||||||
use crate::item::ItemStack;
|
use crate::item::ItemStack;
|
||||||
|
|
||||||
const SWORDS_TAG: &str = "#minecraft:swords";
|
|
||||||
const HEAD_ARMOR_TAG: &str = "#minecraft:head_armor";
|
|
||||||
const SKULL_TAG: &str = "#minecraft:skulls";
|
|
||||||
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 {
|
impl ItemStack {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_sword(&self) -> bool {
|
pub fn is_sword(&self) -> bool {
|
||||||
self.item.is_tagged_with(SWORDS_TAG).expect(
|
self.item
|
||||||
"This is a default minecraft tag that should have been gotten from the extractor",
|
.is_tagged_with_by_tag(&tag::Item::MINECRAFT_SWORDS)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_helmet(&self) -> bool {
|
pub fn is_helmet(&self) -> bool {
|
||||||
self.item.is_tagged_with(HEAD_ARMOR_TAG).expect(
|
self.item
|
||||||
"This is a default minecraft tag that should have been gotten from the extractor",
|
.is_tagged_with_by_tag(&tag::Item::MINECRAFT_HEAD_ARMOR)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_skull(&self) -> bool {
|
pub fn is_skull(&self) -> bool {
|
||||||
self.item.is_tagged_with(SKULL_TAG).expect(
|
self.item
|
||||||
"This is a default minecraft tag that should have been gotten from the extractor",
|
.is_tagged_with_by_tag(&tag::Item::MINECRAFT_SKULLS)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_chestplate(&self) -> bool {
|
pub fn is_chestplate(&self) -> bool {
|
||||||
self.item.is_tagged_with(CHEST_ARMOR_TAG).expect(
|
self.item
|
||||||
"This is a default minecraft tag that should have been gotten from the extractor",
|
.is_tagged_with_by_tag(&tag::Item::MINECRAFT_CHEST_ARMOR)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_leggings(&self) -> bool {
|
pub fn is_leggings(&self) -> bool {
|
||||||
self.item.is_tagged_with(LEG_ARMOR_TAG).expect(
|
self.item
|
||||||
"This is a default minecraft tag that should have been gotten from the extractor",
|
.is_tagged_with_by_tag(&tag::Item::MINECRAFT_LEG_ARMOR)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_boots(&self) -> bool {
|
pub fn is_boots(&self) -> bool {
|
||||||
self.item.is_tagged_with(FOOT_ARMOR_TAG).expect(
|
self.item
|
||||||
"This is a default minecraft tag that should have been gotten from the extractor",
|
.is_tagged_with_by_tag(&tag::Item::MINECRAFT_FOOT_ARMOR)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub mod world_info;
|
|||||||
pub type BlockId = u16;
|
pub type BlockId = u16;
|
||||||
pub type BlockStateId = u16;
|
pub type BlockStateId = u16;
|
||||||
|
|
||||||
pub const CURRENT_MC_VERSION: &str = "1.21.7";
|
pub const CURRENT_MC_VERSION: &str = "1.21.8";
|
||||||
pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.21.94";
|
pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.21.94";
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|||||||
@ -12,11 +12,11 @@ use thiserror::Error;
|
|||||||
pub mod anvil;
|
pub mod anvil;
|
||||||
|
|
||||||
// Constraint: disk biome palette serialization changed in 1.21.5
|
// Constraint: disk biome palette serialization changed in 1.21.5
|
||||||
pub const MINIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4435; // 1.21.7
|
pub const MINIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4435; // 1.21.8
|
||||||
pub const MAXIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4438; // 1.21.7
|
pub const MAXIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4438; // 1.21.8
|
||||||
|
|
||||||
pub const MINIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19132; // 1.21.7
|
pub const MINIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19132; // 1.21.8
|
||||||
pub const MAXIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19133; // 1.21.7
|
pub const MAXIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19133; // 1.21.8
|
||||||
|
|
||||||
pub trait WorldInfoReader {
|
pub trait WorldInfoReader {
|
||||||
fn read_world_info(&self, level_folder: &Path) -> Result<LevelData, WorldInfoError>;
|
fn read_world_info(&self, level_folder: &Path) -> Result<LevelData, WorldInfoError>;
|
||||||
|
|||||||
@ -93,7 +93,7 @@ use pumpkin_data::potion::Effect;
|
|||||||
const MAX_CACHED_SIGNATURES: u8 = 128; // Vanilla: 128
|
const MAX_CACHED_SIGNATURES: u8 = 128; // Vanilla: 128
|
||||||
const MAX_PREVIOUS_MESSAGES: u8 = 20; // Vanilla: 20
|
const MAX_PREVIOUS_MESSAGES: u8 = 20; // Vanilla: 20
|
||||||
|
|
||||||
pub const DATA_VERSION: i32 = 4438; // 1.21.7
|
pub const DATA_VERSION: i32 = 4438; // 1.21.8
|
||||||
|
|
||||||
enum BatchState {
|
enum BatchState {
|
||||||
Initial,
|
Initial,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user