summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs179
1 files changed, 170 insertions, 9 deletions
diff --git a/src/main.rs b/src/main.rs
index 80dea19..1e1c306 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,15 +1,16 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, TcpStream};
+use std::time::Duration;
use anyhow::Result;
use craftio_rs::{CraftIo, CraftSyncReader, CraftSyncWriter, CraftTcpConnection};
-use mcproto_rs::nbt::{NamedTag, Tag};
+use mcproto_rs::nbt::Tag;
use mcproto_rs::protocol::{HasPacketKind, State};
+use mcproto_rs::Serializer;
use mcproto_rs::status::{StatusPlayersSpec, StatusSpec, StatusVersionSpec};
-use mcproto_rs::types::{Chat, NamedNbtTag};
+use mcproto_rs::types::{BytesSerializer, Chat, IntPosition, ItemStack, NamedNbtTag, Slot, Vec3};
use mcproto_rs::uuid::UUID4;
-use mcproto_rs::v1_19_3::{GameMode, HandshakeNextState, LoginPlaySpec, LoginSuccessSpec,
- Packet761, Packet761Kind, PingRequestSpec, PingResponseSpec,
- PreviousGameMode, RawPacket761, StatusResponseSpec};
+use mcproto_rs::v1_19_3::{BitSet, BlobArray, BookSettings, ChunkDataAndUpdateLightSpec, ChunkDataSpec, ChunkSection, CommandNode, CommandNodeSpec, CommandsSpec, EntityEventSpec, InitializeWorldBorderSpec, KeepAliveClientBoundSpec, LightDataSpec, PalettedContainer, RecipeBookAction, RecipeBookInitSpec, SetCenterChunkSpec, SetContainerContentSpec, SetDefaultSpawnPositionSpec, SynchronizePlayerPositionSpec, TagType, TypedTagList, UpdateRecipeBookSpec};
+use mcproto_rs::v1_19_3::{GameMode, HandshakeNextState, LoginPlaySpec, LoginSuccessSpec, Packet761, Packet761Kind, PingRequestSpec, PingResponseSpec, PreviousGameMode, RawPacket761, SetHeldItemClientSpec, StatusResponseSpec, UpdateRecipesSpec, UpdateTagsSpec};
use tokio;
pub struct MinecraftClient {
@@ -197,6 +198,12 @@ async fn handle_conn(mut client: MinecraftClient) -> Result<()> {
properties: vec![].into(),
}))
.await?;
+ let min_build_height = -64i32;
+ let max_build_height = 256i32;
+ let world_height = max_build_height - min_build_height;
+ let min_world_section = min_build_height >> 4;
+ let max_world_section = ((max_build_height - 1) >> 4) + 1;
+ let section_count = max_world_section - min_world_section;
let overworld_spec = nbt! {
"id" :: (0),
"name" :: ("minecraft:overworld"),
@@ -208,10 +215,10 @@ async fn handle_conn(mut client: MinecraftClient) -> Result<()> {
"has_ceiling" :: (false),
"has_skylight" :: (true),
"has_raids" :: (false),
- "height" :: (384),
+ "height" :: (world_height),
"infiniburn" :: ("#minecraft:infiniburn_overworld"),
- "logical_height" :: (384),
- "min_y" :: (-64),
+ "logical_height" :: (world_height),
+ "min_y" :: (min_build_height),
"monster_spawn_block_light_limit" :: (0),
"monster_spawn_light_level" :: {
"type" :: ("minecraft:uniform"),
@@ -287,7 +294,161 @@ async fn handle_conn(mut client: MinecraftClient) -> Result<()> {
.await?;
let client_information = await_packet!(ClientInformation, client);
println!("Client Information: {:?}", client_information);
- anyhow::bail!("TODO");
+ client.send_packet(Packet761::SetHeldItemClient(SetHeldItemClientSpec {
+ selected_slot: 0,
+ })).await?;
+ client.send_packet(Packet761::UpdateRecipes(UpdateRecipesSpec { recipes: vec![].into() })).await?;
+ client.send_packet(Packet761::UpdateTags(UpdateTagsSpec {
+ tags: vec![
+ TypedTagList {
+ tag_type: TagType::Block,
+ tags: vec![].into(),
+ },
+ TypedTagList {
+ tag_type: TagType::Item,
+ tags: vec![].into(),
+ },
+ TypedTagList {
+ tag_type: TagType::EntityType,
+ tags: vec![].into(),
+ },
+ TypedTagList {
+ tag_type: TagType::GameEvent,
+ tags: vec![].into(),
+ },
+ TypedTagList {
+ tag_type: TagType::Fluid,
+ tags: vec![].into(),
+ },
+ ].into(),
+ })).await?;
+ client.send_packet(Packet761::EntityEvent(EntityEventSpec {
+ entity_id: 0,
+ entity_status: 24 /* OP permission level = 0 */,
+ })).await?;
+ client.send_packet(Packet761::Commands(CommandsSpec {
+ nodes: vec![
+ CommandNodeSpec {
+ children_indices: vec![].into(),
+ redirect_node: None,
+ is_executable: false,
+ node: CommandNode::Root,
+ }
+ ].into(),
+ root_index: 0.into(),
+ })).await?;
+ client.send_packet(Packet761::UpdateRecipeBook(UpdateRecipeBookSpec {
+ action: RecipeBookAction::Init(RecipeBookInitSpec {
+ book_settings: BookSettings::default(),
+ known_recipes: vec![].into(),
+ highlighted_recipes: vec![].into(),
+ })
+ })).await?;
+ client.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,
+ })).await?;
+ client.send_packet(Packet761::SetCenterChunk(SetCenterChunkSpec {
+ chunk_x: 0.into(),
+ chunk_z: 0.into(),
+ })).await?;
+ 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..section_count {
+ 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(&section)?;
+ }
+ let chunk_column_bytes = chunk_dat_serializer.into_bytes();
+ client.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(),
+ },
+ })).await?;
+ }
+ }
+ client.send_packet(Packet761::InitializeWorldBorder(InitializeWorldBorderSpec {
+ x: 0.0,
+ z: 0.0,
+ old_diameter: 10000000.0,
+ new_diameter: 10000000.0,
+ speed: 0.into(),
+ portal_teleport_boundary: 29999984.into(),
+ warning_blocks: 0.into(),
+ warning_time: 0.into(),
+ })).await?;
+ client.send_packet(Packet761::SetDefaultSpawnPosition(SetDefaultSpawnPositionSpec {
+ location: IntPosition {
+ x: 0,
+ y: 0,
+ z: 0,
+ },
+ angle: 0.0,
+ })).await?;
+ client.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,
+ })).await?;
+ client.send_packet(Packet761::SetContainerContent(SetContainerContentSpec {
+ window_id: 0,
+ state_id: 0.into(),
+ slot_data: vec![Some(ItemStack {
+ item_id: 1.into(),
+ item_count: 1,
+ nbt: None,
+ }); 45].into(),
+ carried_item: None,
+ }));
+ let mut i = 0;
+ loop {
+ client.send_packet(Packet761::KeepAliveClientBound(KeepAliveClientBoundSpec {
+ keep_alive_id: i,
+ })).await?;
+ i += 1;
+ tokio::time::sleep(Duration::from_secs(10)).await;
+ }
} else if hs.next_state == HandshakeNextState::Status {
return handle_status(client).await;
} else {