diff --git a/examples/basic.rs b/examples/basic.rs index cbfcff1..655dbda 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -7,8 +7,8 @@ use valence::client::GameMode; use valence::config::{Config, ServerListPing}; use valence::text::Color; use valence::{ - async_trait, ChunkPos, ClientMut, DimensionId, Server, ShutdownResult, Text, TextFormat, - WorldId, WorldsMut, + async_trait, ChunkPos, ClientMut, DimensionId, EntityType, Server, ShutdownResult, Text, + TextFormat, WorldId, WorldsMut, }; pub fn main() -> ShutdownResult { @@ -83,14 +83,38 @@ impl Config for Game { if x != -size && x != size - 1 && z != -size && z != size - 1 { for z in 0..16 { for x in 0..16 { - for y in 0..50 { - chunk.set_block_state(x, y, z, BlockState::STONE); + let block_x = pos.x * 16 + x as i32; + let block_z = pos.z * 16 + z as i32; + + let height = 50.0 + + ((block_x as f64 / 10.0).cos() + (block_z as f64 / 10.0).sin()) + * 7.0; + + for y in 0..height.round() as usize { + let states = [ + BlockState::ACACIA_PLANKS, + BlockState::SLIME_BLOCK, + BlockState::IRON_BLOCK, + BlockState::SEA_LANTERN, + BlockState::STONE, + BlockState::DIRT, + BlockState::PRISMARINE_BRICKS, + BlockState::DIAMOND_ORE, + ]; + + chunk.set_block_state(x, y, z, states[y % states.len()]); } } } } } } + + let entity_id = world.entities.create(); + let mut entity = world.entities.get_mut(entity_id).unwrap(); + + entity.set_type(EntityType::Cow); + entity.set_position([0.0, 50.0, 0.0]); } fn update(&self, server: &Server, mut worlds: WorldsMut) { diff --git a/src/chunk.rs b/src/chunk.rs index 2c4d3bf..6c59ac0 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -59,9 +59,9 @@ impl<'a> ChunksMut<'a> { Self(chunks) } - pub fn create(&mut self, pos: ChunkPos) -> bool { + pub fn create(&mut self, pos: impl Into) -> bool { let chunk = Chunk::new(self.section_count, self.server.current_tick()); - self.0.chunks.insert(pos, chunk).is_none() + self.0.chunks.insert(pos.into(), chunk).is_none() } pub fn delete(&mut self, pos: ChunkPos) -> bool { @@ -358,14 +358,12 @@ fn build_heightmap(sections: &[ChunkSection], heightmap: &mut Vec) { } fn encode_paletted_container( - entries: impl ExactSizeIterator + Clone, + mut entries: impl ExactSizeIterator + Clone, min_bits_per_idx: usize, direct_threshold: usize, direct_bits_per_idx: usize, w: &mut impl Write, ) -> anyhow::Result<()> { - let entries_len = entries.len(); - let mut palette = Vec::new(); for entry in entries.clone() { @@ -391,10 +389,12 @@ fn encode_paletted_container( VarInt(u64_count as i32).encode(w)?; - for entry in entries { + for _ in 0..idxs_per_u64 { let mut val = 0u64; for i in 0..idxs_per_u64 { - val |= (entry as u64) << (i * direct_bits_per_idx); + if let Some(entry) = entries.next() { + val |= (entry as u64) << (i * direct_bits_per_idx); + } } val.encode(w)?; } @@ -411,15 +411,17 @@ fn encode_paletted_container( VarInt(u64_count as i32).encode(w)?; - for entry in entries { - let palette_idx = palette - .iter() - .position(|&e| e == entry) - .expect("entry should be in the palette") as u64; - + for _ in 0..u64_count { let mut val = 0u64; for i in 0..idxs_per_u64 { - val |= palette_idx << (i * bits_per_idx); + if let Some(entry) = entries.next() { + let palette_idx = palette + .iter() + .position(|&e| e == entry) + .expect("entry should be in the palette") as u64; + + val |= palette_idx << (i * bits_per_idx); + } } val.encode(w)?; } @@ -428,14 +430,6 @@ fn encode_paletted_container( Ok(()) } -/// Encode a paletted container where all values are the same. -fn encode_paletted_container_single(entry: u16, w: &mut impl Write) -> anyhow::Result<()> { - 0u8.encode(w)?; // bits per idx - VarInt(entry as i32).encode(w)?; // single value - VarInt(0).encode(w)?; // data array length - Ok(()) -} - /// Calculates the log base 2 rounded up. fn log2_ceil(n: usize) -> usize { n.next_power_of_two().trailing_zeros() as usize diff --git a/src/client.rs b/src/client.rs index 6275af2..c54219b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -505,7 +505,9 @@ impl<'a> ClientMut<'a> { self.0.loaded_entities.retain(|&id| { if let Some(entity) = entities.get(id) { if self.0.new_position.distance(entity.position()) <= view_dist as f64 * 16.0 { - todo!("update entity"); + if let Some(meta) = entity.updated_metadata_packet(id) { + send_packet(&mut self.0.send, meta); + } return true; } } diff --git a/src/entity.rs b/src/entity.rs index b4774ed..ba78439 100644 --- a/src/entity.rs +++ b/src/entity.rs @@ -16,7 +16,7 @@ use crate::packets::play::{ ClientPlayPacket, EntityMetadata, SpawnEntity, SpawnExperienceOrb, SpawnLivingEntity, SpawnPainting, SpawnPlayer, }; -use crate::protocol::ReadToEnd; +use crate::protocol::RawBytes; use crate::slotmap::{Key, SlotMap}; use crate::util::aabb_from_bottom_and_size; use crate::var_int::VarInt; @@ -172,8 +172,8 @@ pub struct EntityId(Key); impl EntityId { pub(crate) fn to_network_id(self) -> i32 { - // TODO: is ID 0 reserved? - self.0.index() as i32 + // ID 0 is reserved for clients. + self.0.index() as i32 + 1 } } @@ -271,7 +271,7 @@ impl Entity { pub(crate) fn initial_metadata_packet(&self, this_id: EntityId) -> Option { self.meta.initial_metadata().map(|meta| EntityMetadata { entity_id: VarInt(this_id.to_network_id()), - metadata: ReadToEnd(meta), + metadata: RawBytes(meta), }) } @@ -281,7 +281,7 @@ impl Entity { pub(crate) fn updated_metadata_packet(&self, this_id: EntityId) -> Option { self.meta.updated_metadata().map(|meta| EntityMetadata { entity_id: VarInt(this_id.to_network_id()), - metadata: ReadToEnd(meta), + metadata: RawBytes(meta), }) } diff --git a/src/lib.rs b/src/lib.rs index af23b74..ce6f368 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,7 +31,7 @@ pub use block_pos::BlockPos; pub use chunk::{Chunk, ChunkPos, Chunks, ChunksMut}; pub use client::{Client, ClientMut, Clients, ClientsMut}; pub use config::{Biome, BiomeId, Config, Dimension, DimensionId}; -pub use entity::{Entities, EntitiesMut, Entity, EntityId}; +pub use entity::{Entities, EntitiesMut, Entity, EntityId, EntityType}; pub use identifier::Identifier; pub use server::{start_server, NewClientData, Server, ShutdownResult}; pub use text::{Text, TextFormat}; diff --git a/src/packets.rs b/src/packets.rs index 65d574d..3705c65 100644 --- a/src/packets.rs +++ b/src/packets.rs @@ -18,7 +18,7 @@ use vek::{Vec2, Vec3}; use crate::block_pos::BlockPos; use crate::byte_angle::ByteAngle; use crate::identifier::Identifier; -use crate::protocol::{BoundedArray, BoundedInt, BoundedString, Decode, Encode, Nbt, ReadToEnd}; +use crate::protocol::{BoundedArray, BoundedInt, BoundedString, Decode, Encode, Nbt, RawBytes}; use crate::var_int::VarInt; use crate::var_long::VarLong; use crate::Text; @@ -1028,7 +1028,7 @@ pub mod play { def_struct! { EntityMetadata 0x4d { entity_id: VarInt, - metadata: ReadToEnd, + metadata: RawBytes, } } @@ -1246,7 +1246,7 @@ pub mod play { def_struct! { PluginMessageServerbound 0x0a { channel: Identifier, - data: ReadToEnd, + data: RawBytes, } } diff --git a/src/protocol.rs b/src/protocol.rs index 9d25027..0954826 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -519,17 +519,17 @@ impl Decode for BitBox { /// `Vec`. When encoding, the data is inserted into the packet with no /// length prefix. #[derive(Clone, Debug)] -pub struct ReadToEnd(pub Vec); +pub struct RawBytes(pub Vec); -impl Decode for ReadToEnd { +impl Decode for RawBytes { fn decode(r: &mut impl Read) -> anyhow::Result { let mut buf = Vec::new(); r.read_to_end(&mut buf)?; - Ok(ReadToEnd(buf)) + Ok(RawBytes(buf)) } } -impl Encode for ReadToEnd { +impl Encode for RawBytes { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { w.write_all(&self.0).map_err(|e| e.into()) }