diff --git a/Cargo.lock b/Cargo.lock index bd3b6c09..811c9413 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,6 +1557,7 @@ name = "server" version = "0.1.0" dependencies = [ "anyhow", + "azalea-buf", "azalea-world", "base64", "bytes", diff --git a/Dockerfile b/Dockerfile index 7d85d70c..fa674791 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,9 @@ COPY .cargo ./.cargo COPY Cargo.toml Cargo.lock ./ +COPY chunk/Cargo.toml ./chunk/Cargo.toml +COPY chunk/src ./chunk/src + COPY server/Cargo.toml ./server/Cargo.toml COPY server/src ./server/src diff --git a/chunk/src/chunk.rs b/chunk/src/chunk.rs index a4372af1..7e6349e4 100644 --- a/chunk/src/chunk.rs +++ b/chunk/src/chunk.rs @@ -271,6 +271,8 @@ impl IntoBlock for BlockState { } pub const SECTION_BLOCK_COUNT: usize = 16 * 16 * 16; +pub const SLICE_BLOCK_COUNT: usize = 16 * 16; + pub const SECTION_BIOME_COUNT: usize = 4 * 4 * 4; /// The maximum height of a chunk. diff --git a/server/Cargo.toml b/server/Cargo.toml index e746ae8a..ddc5f60b 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -20,7 +20,7 @@ chunk.workspace = true #azalea-buf = { git = "https://github.com/azalea-rs/azalea", branch = "1.20.1" } #azalea-world = { git = "https://github.com/azalea-rs/azalea", branch = "1.20.1" } -#azalea-buf = { git = "https://github.com/azalea-rs/azalea" } +azalea-buf = { git = "https://github.com/azalea-rs/azalea" } azalea-world = { git = "https://github.com/azalea-rs/azalea" } @@ -36,6 +36,7 @@ flume = "0.11.0" monoio = { version = "0.2.3", features = ["sync"] } signal-hook = "0.3.17" base64 = "0.21.7" +#bit-set = "0.5.3" [lints.rust] diff --git a/server/src/blocks.rs b/server/src/blocks.rs deleted file mode 100644 index 9bdb64fc..00000000 --- a/server/src/blocks.rs +++ /dev/null @@ -1,3 +0,0 @@ -// struct Chunk { -// -// } diff --git a/server/src/main.rs b/server/src/main.rs index 2845b992..dd202978 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -25,8 +25,6 @@ mod handshake; mod packets; mod system; -mod blocks; - // A zero-sized component, often called a "marker" or "tag". #[derive(Component)] struct Player { diff --git a/server/src/system/player_join_world.rs b/server/src/system/player_join_world.rs index 48a36b33..f03aca8f 100644 --- a/server/src/system/player_join_world.rs +++ b/server/src/system/player_join_world.rs @@ -1,8 +1,9 @@ use std::{borrow::Cow, io::Write}; +use azalea_world::BitStorage; use chunk::{ bit_width, - chunk::{BiomeContainer, BlockStateContainer, SECTION_BLOCK_COUNT}, + chunk::{BiomeContainer, BlockStateContainer, SECTION_BLOCK_COUNT, SLICE_BLOCK_COUNT}, palette::{BlockGetter, DirectEncoding}, }; use evenio::prelude::*; @@ -12,7 +13,7 @@ use valence_protocol::{ math::DVec3, nbt::{compound, List}, packets::{play, play::player_position_look_s2c::PlayerPositionLookFlags}, - BlockPos, BlockState, ChunkPos, Encode, + BlockPos, BlockState, ChunkPos, Encode, FixedArray, }; use valence_registry::{biome::BiomeId, RegistryIdx}; @@ -64,6 +65,25 @@ fn write_biomes(biomes: BiomeContainer, writer: &mut impl Write) -> anyhow::Resu Ok(()) } +trait Array3d { + type Item; + fn get3(&self, x: usize, y: usize, z: usize) -> &Self::Item; + fn get3_mut(&mut self, x: usize, y: usize, z: usize) -> &mut Self::Item; +} + +#[allow(clippy::indexing_slicing)] +impl Array3d for [T; N] { + type Item = T; + + fn get3(&self, x: usize, y: usize, z: usize) -> &Self::Item { + &self[x + z * 16 + y * 16 * 16] + } + + fn get3_mut(&mut self, x: usize, y: usize, z: usize) -> &mut Self::Item { + &mut self[x + z * 16 + y * 16 * 16] + } +} + fn air_section() -> Vec { let mut section_bytes = Vec::new(); 0_u16.encode(&mut section_bytes).unwrap(); @@ -77,19 +97,54 @@ fn air_section() -> Vec { section_bytes } +fn stone_section() -> Vec { + let mut section_bytes = Vec::new(); + (SECTION_BLOCK_COUNT as u16) + .encode(&mut section_bytes) + .unwrap(); + + let mut blocks = [BlockState::STONE; SECTION_BLOCK_COUNT]; + let block_states = BlockStateContainer::Direct(Box::new(blocks)); + write_block_states(block_states, &mut section_bytes).unwrap(); + + let biomes = BiomeContainer::Single(BiomeId::DEFAULT); + write_biomes(biomes, &mut section_bytes).unwrap(); + + section_bytes +} + fn ground_section() -> Vec { let mut section_bytes = Vec::new(); let number_blocks: u16 = 16 * 16; number_blocks.encode(&mut section_bytes).unwrap(); - let blocks: [_; SECTION_BLOCK_COUNT] = std::array::from_fn(|i| { - if i < 16 * 16 { - BlockState::GRASS_BLOCK - } else { - BlockState::AIR + let mut blocks = [BlockState::AIR; SECTION_BLOCK_COUNT]; + // set sin wave with peak at center of chunk + + let bedrock_layers = 3; + + for block in blocks.iter_mut().take(SLICE_BLOCK_COUNT * bedrock_layers) { + *block = BlockState::BEDROCK; + } + + #[allow(clippy::cast_sign_loss)] + #[allow(clippy::suboptimal_flops)] + #[allow(clippy::indexing_slicing)] + for x in 0..16 { + for z in 0..16 { + let dist_from_center = (x as f64 - 8.0).hypot(z as f64 - 8.0); + + // based on x and z + // should be highest at center of chunk + let height = (16.0 - dist_from_center) * 0.5 + 3.0; + let height = height as usize; + let height = height.min(16); + for y in 0..height { + *blocks.get3_mut(x, y, z) = BlockState::SAND; + } } - }); + } let block_states = BlockStateContainer::Direct(Box::new(blocks)); @@ -112,7 +167,7 @@ fn inner(io: &mut Player) -> anyhow::Result<()> { })?; io.writer.send_packet(&play::PlayerPositionLookS2c { - position: DVec3::new(0.0, 3.0, 0.0), + position: DVec3::new(0.0, 30.0, 0.0), yaw: 0.0, pitch: 0.0, flags: PlayerPositionLookFlags::default(), @@ -124,15 +179,24 @@ fn inner(io: &mut Player) -> anyhow::Result<()> { chunk_z: 0.into(), })?; - let section_count = 384 / 16; + let section_count = 384 / 16_usize; let air_section = air_section(); let ground_section = ground_section(); + let stone_section = stone_section(); let mut bytes = Vec::new(); + bytes.extend_from_slice(&stone_section); + bytes.extend_from_slice(&stone_section); + bytes.extend_from_slice(&stone_section); + bytes.extend_from_slice(&stone_section); bytes.extend_from_slice(&ground_section); - for _ in (0..section_count).skip(1) { + // 2048 bytes per section -> long count = 2048 / 8 = 256 + let sky_light_array = FixedArray([0xFF_u8; 2048]); + let sky_light_arrays = vec![sky_light_array; section_count + 2]; + + for _ in (0..section_count).skip(5) { bytes.extend_from_slice(&air_section); } @@ -141,6 +205,13 @@ fn inner(io: &mut Player) -> anyhow::Result<()> { let map = heightmap(dimension_height, dimension_height - 3); let map: Vec<_> = map.into_iter().map(i64::try_from).try_collect()?; + // convert section_count + 2 0b1s into u64 array + let mut bits = BitStorage::new(1, section_count + 2, None).unwrap(); + + for i in 0..section_count + 2 { + bits.set(i, 1); + } + let mut pkt = play::ChunkDataS2c { pos: ChunkPos::new(0, 0), heightmaps: Cow::Owned(compound! { @@ -149,11 +220,11 @@ fn inner(io: &mut Player) -> anyhow::Result<()> { blocks_and_biomes: &bytes, block_entities: Cow::Borrowed(&[]), - sky_light_mask: Cow::Borrowed(&[]), + sky_light_mask: Cow::Owned(bits.data), block_light_mask: Cow::Borrowed(&[]), empty_sky_light_mask: Cow::Borrowed(&[]), empty_block_light_mask: Cow::Borrowed(&[]), - sky_light_arrays: Cow::Borrowed(&[]), + sky_light_arrays: Cow::Owned(sky_light_arrays), block_light_arrays: Cow::Borrowed(&[]), }; for x in -16..=16 {