diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 87 | ||||
-rw-r--r-- | src/nbtdsl.rs | 6 | ||||
-rw-r--r-- | src/player.rs | 48 | ||||
-rw-r--r-- | src/world.rs | 74 |
4 files changed, 139 insertions, 76 deletions
diff --git a/src/main.rs b/src/main.rs index 24666d0..a697b08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,14 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::sync::Arc; use std::time::Duration; use anyhow::Result; -use mcproto_rs::nbt::Tag; use mcproto_rs::protocol::State; use mcproto_rs::Serializer; use mcproto_rs::status::{StatusPlayersSpec, StatusSpec, StatusVersionSpec}; -use mcproto_rs::types::{BytesSerializer, Chat, IntPosition, ItemStack, NamedNbtTag, RemainingBytes, Vec3}; +use mcproto_rs::types::{BytesSerializer, Chat, IntPosition, ItemStack, RemainingBytes, Vec3}; use mcproto_rs::uuid::UUID4; -use mcproto_rs::v1_19_3::{BitSet, BlobArray, ChunkDataAndUpdateLightSpec, ChunkDataSpec, ChunkSection, EntityEventSpec, InitializeWorldBorderSpec, KeepAliveClientBoundSpec, LightDataSpec, PalettedContainer, PluginMessageSpec, SetCenterChunkSpec, SetContainerContentSpec, SetDefaultSpawnPositionSpec, SynchronizePlayerPositionSpec}; +use mcproto_rs::v1_19_3::{EntityEventSpec, InitializeWorldBorderSpec, KeepAliveClientBoundSpec, PluginMessageSpec, SetContainerContentSpec, SetDefaultSpawnPositionSpec}; use mcproto_rs::v1_19_3::{HandshakeNextState, LoginSuccessSpec, Packet761, Packet761Kind, PingRequestSpec, PingResponseSpec, SetHeldItemClientSpec, StatusResponseSpec}; use tokio; use tokio::net::TcpStream; @@ -18,11 +18,13 @@ use tokio::sync::broadcast::Receiver; use tokio::task::JoinHandle; use crate::connect::MinecraftClient; +use crate::world::DebugWorld; pub mod connect; pub mod nbtdsl; pub mod player; pub mod convention; +pub mod world; #[tokio::main] async fn main() -> Result<()> { @@ -113,18 +115,13 @@ async fn handle_login(mut client: MinecraftClient) -> Result<()> { properties: vec![].into(), }))?; client.set_state(State::Play)?; - let mut player = player::Player { - client, - name: loginstart.name.clone(), - position: Vec3 { - x: 0.0, - y: 100.0, - z: 0.0, - }, - yaw: 0.0, - pitch: 0.0, - }; - let universe = convention::Universe::default_meta(-64, 256); + let mut player = player::Player::new(client, loginstart.name.clone(), Vec3 { + x: 0.0, + y: 0.0, + z: 0.0, + }, 0.0, 0.0); + let universe = Arc::new(convention::Universe::default_meta(-64, 256)); + let world = DebugWorld::new(universe.clone()); player.send_packet(universe.create_login_play_packet())?; let client_information = await_packet!(ClientInformation, player.client); @@ -143,51 +140,8 @@ async fn handle_login(mut client: MinecraftClient) -> Result<()> { player.send_packet(universe.empty_commands())?; player.send_packet(universe.init_empty_recipe_book())?; player.send_packet(player.create_teleport_packet())?; - player.send_packet(Packet761::SetCenterChunk(SetCenterChunkSpec { - chunk_x: 0.into(), - chunk_z: 0.into(), - }))?; - for i in -7..7 { - for j in -7..7 { - let mut heightmap = BlobArray::new(9); - for cx in 0..(16 * 16) { - heightmap.set_entry(cx, 2) - } - let mut chunk_dat_serializer = BytesSerializer::default(); - for i in 0..(universe.max_world_section - universe.min_world_section) { - let section = ChunkSection { - block_count: if i < 4 { 16 * 16 * 16 } else { 0 }, - block_state: PalettedContainer { singular_value: if i < 4 { 1.into() } else { 0.into() } }, - biomes: PalettedContainer { singular_value: 0.into() }, - }; - chunk_dat_serializer.serialize_other(§ion)?; - } - let chunk_column_bytes = chunk_dat_serializer.into_bytes(); - player.send_packet(Packet761::ChunkDataAndUpdateLight(ChunkDataAndUpdateLightSpec { - chunk_x: i, - chunk_z: j, - chunk_data: ChunkDataSpec { - heightmaps: NamedNbtTag { - root: nbt! { - "MOTION_BLOCKING" :: (Tag::LongArray(heightmap.data.iter().map(|n| n.to_owned() as _).collect())), - "WORLD_SURFACE" :: (Tag::LongArray(heightmap.data.iter().map(|n| n.to_owned() as _).collect())), - }.with_name("root") - }, - buffer: chunk_column_bytes.into(), - block_entities: vec![].into(), - }, - light_data: LightDataSpec { - trust_edges: true, - sky_y_mask: BitSet::empty(), - block_y_mask: BitSet::empty(), - empty_sky_y_mask: BitSet::empty(), - empty_block_y_mask: BitSet::empty(), - sky_updates: vec![].into(), - block_updates: vec![].into(), - }, - }))?; - } - } + player.synchronize_center_chunk()?; + player.send_all_nearby_chunks(&world).await?; player.send_packet(Packet761::InitializeWorldBorder(InitializeWorldBorderSpec { x: 0.0, z: 0.0, @@ -206,18 +160,7 @@ async fn handle_login(mut client: MinecraftClient) -> Result<()> { }, angle: 0.0, }))?; - player.send_packet(Packet761::SynchronizePlayerPosition(SynchronizePlayerPositionSpec { - position: Vec3 { - x: 0f64, - y: 100f64, - z: 0f64, - }, - yaw: 0.0, - pitch: 0.0, - flags: Default::default(), - teleport_id: 0.into(), - dismount_vehicle: false, - }))?; + player.send_packet(player.create_teleport_packet())?; player.send_packet(Packet761::SetContainerContent(SetContainerContentSpec { window_id: 0, state_id: 0.into(), diff --git a/src/nbtdsl.rs b/src/nbtdsl.rs index 86b2116..4e4baa4 100644 --- a/src/nbtdsl.rs +++ b/src/nbtdsl.rs @@ -55,21 +55,21 @@ impl ShittyToNbt for f64 { #[macro_export] macro_rules! nbt { ( {$($name:literal :: $value:tt),* $(,)? } ) => { - Tag::Compound(vec![ + mcproto_rs::nbt::Tag::Compound(vec![ $( nbt!($value).with_name($name) ),* ]) }; { $($name:literal :: $value:tt),* $(,)? } => { - Tag::Compound(vec![ + mcproto_rs::nbt::Tag::Compound(vec![ $( nbt!($value).with_name($name) ),* ]) }; ([ $($value:tt),* $(,)? ]) => { - Tag::List(vec![ + mcproto_rs::nbt::Tag::List(vec![ $( nbt!($value) ),* diff --git a/src/player.rs b/src/player.rs index 7b99c16..e63c8a4 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,8 +1,9 @@ use anyhow::Result; use mcproto_rs::types::Vec3; -use mcproto_rs::v1_19_3::{Packet761, SynchronizePlayerPositionSpec}; +use mcproto_rs::v1_19_3::{Packet761, SetCenterChunkSpec, SynchronizePlayerPositionSpec}; use crate::connect::MinecraftClient; +use crate::world::World; pub struct Player { pub client: MinecraftClient, @@ -10,10 +11,23 @@ pub struct Player { pub position: Vec3<f64>, pub yaw: f32, pub pitch: f32, + last_center_chunk: Option<(i32, i32)>, + } impl Player { + pub fn new(client: MinecraftClient, name: String, position: Vec3<f64>, yaw: f32, pitch: f32) -> Player { + Player { + client, + name, + position, + yaw, + pitch, + last_center_chunk: None, + } + } + pub fn create_teleport_packet(&self) -> Packet761 { Packet761::SynchronizePlayerPosition(SynchronizePlayerPositionSpec { position: self.position.clone(), @@ -33,6 +47,38 @@ impl Player { Ok(()) } + pub fn chunk_x(&self) -> i32 { + self.position.x.ceil() as i32 / 16 + } + + pub fn chunk_z(&self) -> i32 { + self.position.z.ceil() as i32 / 16 + } + + pub fn synchronize_center_chunk(&mut self) -> Result<()> { + let cx = self.chunk_x(); + let cz = self.chunk_z(); + let tup = Some((cx, cz)); + if self.last_center_chunk != tup { + self.last_center_chunk = tup; + self.send_packet(Packet761::SetCenterChunk(SetCenterChunkSpec { + chunk_x: cx.into(), + chunk_z: cz.into(), + }))?; + } + Ok(()) + } + + pub async fn send_all_nearby_chunks(&self, world: &(dyn World + Sync + Send)) -> Result<()> { + // TODO: proper chunk observing + for x_off in -7..7 { + for z_off in -7..7 { + world.send_chunk(&self, self.chunk_x() + x_off, self.chunk_z() + z_off).await?; + } + } + Ok(()) + } + pub fn send_packet(&self, packet: Packet761) -> Result<()> { self.client.send_packet(packet) } diff --git a/src/world.rs b/src/world.rs new file mode 100644 index 0000000..a1c7e11 --- /dev/null +++ b/src/world.rs @@ -0,0 +1,74 @@ +use std::sync::Arc; + +use anyhow::Result; +use async_trait::async_trait; +use mcproto_rs::nbt::Tag; +use mcproto_rs::Serializer; +use mcproto_rs::types::{BytesSerializer, NamedNbtTag}; +use mcproto_rs::v1_19_3::{BitSet, BlobArray, ChunkDataAndUpdateLightSpec, ChunkDataSpec, ChunkSection, LightDataSpec, Packet761, PalettedContainer}; + +use crate::convention::Universe; +use crate::nbt; +use crate::player::Player; + +#[async_trait] +pub trait World { + async fn send_chunk(&self, observer: &Player, chunk_x: i32, chunk_z: i32) -> Result<()>; +} + +pub struct DebugWorld { + universe: Arc<Universe>, +} + +impl DebugWorld { + pub fn new(universe: Arc<Universe>) -> DebugWorld { + DebugWorld { universe } + } +} + +#[async_trait] +impl World for DebugWorld { + async fn send_chunk(&self, observer: &Player, chunk_x: i32, chunk_z: i32) -> Result<()> { + let mut heightmap = BlobArray::new(9); + for cx in 0..(16 * 16) { + heightmap.set_entry(cx, 2) + } + let mut chunk_dat_serializer = BytesSerializer::default(); + for i in 0..(self.universe.max_world_section - self.universe.min_world_section) { + let section = ChunkSection { + block_count: if i < 4 { 16 * 16 * 16 } else { 0 }, + block_state: PalettedContainer { singular_value: if i < 4 { 1.into() } else { 0.into() } }, + biomes: PalettedContainer { singular_value: 0.into() }, + }; + chunk_dat_serializer.serialize_other(§ion)?; + } + let chunk_column_bytes = chunk_dat_serializer.into_bytes(); + observer.send_packet(Packet761::ChunkDataAndUpdateLight(ChunkDataAndUpdateLightSpec { + chunk_x, + chunk_z, + chunk_data: ChunkDataSpec { + heightmaps: NamedNbtTag { + root: nbt! { + "MOTION_BLOCKING" :: (Tag::LongArray(heightmap.data.iter().map(|n| n.to_owned() as _).collect())), + "WORLD_SURFACE" :: (Tag::LongArray(heightmap.data.iter().map(|n| n.to_owned() as _).collect())), + }.with_name("root") + }, + buffer: chunk_column_bytes.into(), + block_entities: vec![].into(), + }, + light_data: LightDataSpec { + trust_edges: true, + sky_y_mask: BitSet::empty(), + block_y_mask: BitSet::empty(), + empty_sky_y_mask: BitSet::empty(), + empty_block_y_mask: BitSet::empty(), + sky_updates: vec![].into(), + block_updates: vec![].into(), + }, + }))?; + Ok(()) + } +} + + + |