diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 453 |
1 files changed, 163 insertions, 290 deletions
diff --git a/src/main.rs b/src/main.rs index a113a30..6c1f95b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::time::Duration; use anyhow::Result; -use craftio_rs::CraftIo; use mcproto_rs::nbt::Tag; use mcproto_rs::protocol::State; use mcproto_rs::Serializer; @@ -14,7 +13,7 @@ use mcproto_rs::v1_19_3::{GameMode, HandshakeNextState, LoginPlaySpec, LoginSucc use tokio; use tokio::net::TcpStream; use tokio::signal::unix::{signal, SignalKind}; -use tokio::sync::{broadcast}; +use tokio::sync::broadcast; use tokio::sync::broadcast::Receiver; use tokio::task::JoinHandle; @@ -22,7 +21,8 @@ use crate::connect::MinecraftClient; pub mod connect; pub mod nbtdsl; - +pub mod player; +pub mod convention; #[tokio::main] async fn main() -> Result<()> { @@ -87,292 +87,169 @@ async fn listener(listener: tokio::net::TcpListener, mut receiver: Receiver<()>) async fn handle_conn(mut client: MinecraftClient) -> Result<()> { let hs = assert_packet!(Handshake, client, "Missing packet"); if hs.next_state == HandshakeNextState::Login { - client.connection.set_state(State::Login); - let loginstart = assert_packet!( + return handle_login(client).await; + } else if hs.next_state == HandshakeNextState::Status { + return handle_status(client).await; + } else { + anyhow::bail!("Unknown next status") + } +} + +async fn handle_login(mut client: MinecraftClient) -> Result<()> { + client.set_state(State::Login)?; + let loginstart = assert_packet!( LoginStart, client .read_next_packet() .await? .ok_or(anyhow::anyhow!("Missing packet"))? ); - println!("Login: {:?}", loginstart); - let uuid = UUID4::random(); - client - .send_packet(Packet761::LoginSuccess(LoginSuccessSpec { - uuid, - username: loginstart.name, - 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"), - "element" :: { - "ambient_light" :: (false), - "bed_works" :: (true), - "coordinate_scale" :: (1), - "effects" :: ("minecraft:overworld"), - "has_ceiling" :: (false), - "has_skylight" :: (true), - "has_raids" :: (false), - "height" :: (world_height), - "infiniburn" :: ("#minecraft:infiniburn_overworld"), - "logical_height" :: (world_height), - "min_y" :: (min_build_height), - "monster_spawn_block_light_limit" :: (0), - "monster_spawn_light_level" :: { - "type" :: ("minecraft:uniform"), - "value" :: { - "max_inclusive" :: (7), - "min_inclusive" :: (0), - }, - }, - "natural" :: (true), - "piglin_safe" :: (false), - "respawn_anchor_works" :: (false), - "ultrawarm" :: (false), - }, - }; - let biome_spec = nbt!( - [ - { - "id" :: (0), - "name" :: ("minecraft:plains"), - "element" :: { - "downfall" :: (0.5), - "precipitation" :: ("none"), - "temperature" :: (0.5), - "effects" :: { - "fog_color" :: (12638463), - "sky_color" :: (12638463), - "water_color" :: (12638463), - "water_fog_color" :: (12638463), - "mood_sound" :: { - "block_search_extent" :: (8), - "offset" :: (2), - "sound" :: ("minecraft:ambient.cave"), - "tick_delay" :: (6000), - }, - } - } - } - ] - ); - let registry_doex = nbt! { - "minecraft:dimension_type" :: { - "type" :: ("minecraft:dimension_type"), - "value" :: [(overworld_spec)] - }, - "minecraft:worldgen/biome" :: { - "type" :: ("minecraft:worldgen/biome"), - "value" :: (biome_spec), + println!("Login: {:?}", loginstart); + let uuid = UUID4::random(); + client + .send_packet(Packet761::LoginSuccess(LoginSuccessSpec { + uuid, + username: loginstart.name.clone(), + 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); + player.send_packet(universe.create_login_play_packet())?; + + let client_information = await_packet!(ClientInformation, player.client); + println!("Client Information: {:?}", client_information); + + player.send_packet(Packet761::SetHeldItemClient(SetHeldItemClientSpec { + selected_slot: 0, + }))?; + + player.send_all_packets(universe.create_tags_and_recipes())?; + + player.send_packet(Packet761::EntityEvent(EntityEventSpec { + entity_id: 0, + entity_status: 24 /* OP permission level = 0 */, + }))?; + 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) } - }; - client.connection.set_state(State::Play); - client - .send_packet(Packet761::LoginPlay(LoginPlaySpec { - entity_id: 0, - is_hardcore: false, - gamemode: GameMode::Survival, - previous_gamemode: PreviousGameMode::NoPrevious, - dimension_names: vec!["world".into()].into(), - registry_codex: NamedNbtTag { - root: registry_doex.with_name("root"), - }, - dimension_type: "minecraft:overworld".into(), - dimension_name: "world".into(), - hashed_seed: 0, - max_players: 10.into(), - view_distance: 10.into(), - simulation_distance: 10.into(), - reduced_debug_info: false, - enable_respawn_screen: false, - is_debug: false, - is_flat: false, - death_location: None, - })) - .await?; - let client_information = await_packet!(ClientInformation, client); - println!("Client Information: {:?}", client_information); - 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(§ion)?; - } - 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! { + 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(), - }, - })).await?; - } + 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(), + }, + }))?; } - 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, - })).await?; - let mut i = 0; - loop { - client.send_packet(Packet761::KeepAliveClientBound(KeepAliveClientBoundSpec { - keep_alive_id: i, - })).await?; - if i == 2 { - let mut brand_encoder = BytesSerializer::default(); - brand_encoder.serialize_other(&String::from("MGASI"))?; + } + player.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(), + }))?; + player.send_packet(Packet761::SetDefaultSpawnPosition(SetDefaultSpawnPositionSpec { + location: IntPosition { + x: 0, + y: 0, + z: 0, + }, + 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(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 { + player.send_packet(Packet761::KeepAliveClientBound(KeepAliveClientBoundSpec { + keep_alive_id: i, + }))?; + if i == 2 { + let mut brand_encoder = BytesSerializer::default(); + brand_encoder.serialize_other(&String::from("MGASI"))?; - client.send_packet(Packet761::PluginMessage(PluginMessageSpec { - channel: "minecraft:brand".to_string(), - data: RemainingBytes { data: brand_encoder.into_bytes() }, - })).await?; - } - i += 1; - tokio::time::sleep(Duration::from_secs(10)).await; + player.send_packet(Packet761::PluginMessage(PluginMessageSpec { + channel: "minecraft:brand".to_string(), + data: RemainingBytes { data: brand_encoder.into_bytes() }, + }))?; } - } else if hs.next_state == HandshakeNextState::Status { - return handle_status(client).await; - } else { - anyhow::bail!("Unknown next status") + i += 1; + tokio::time::sleep(Duration::from_secs(10)).await; } } + async fn handle_status(mut client: MinecraftClient) -> Result<()> { - client.connection.set_state(State::Status); + client.set_state(State::Status)?; loop { match client .read_next_packet() @@ -380,28 +257,24 @@ async fn handle_status(mut client: MinecraftClient) -> Result<()> { .ok_or(anyhow::anyhow!("Missing packet"))? { Packet761::StatusRequest(_) => { - client - .send_packet(Packet761::StatusRespone(StatusResponseSpec { - response: StatusSpec { - version: Some(StatusVersionSpec { - name: "1.19.3 mgasi".to_string(), - protocol: 761, - }), - players: StatusPlayersSpec { - max: 100, - online: 0, - sample: vec![], - }, - description: Chat::from_text("hehehe"), - favicon: None, + client.send_packet(Packet761::StatusRespone(StatusResponseSpec { + response: StatusSpec { + version: Some(StatusVersionSpec { + name: "1.19.3 mgasi".to_string(), + protocol: 761, + }), + players: StatusPlayersSpec { + max: 100, + online: 0, + sample: vec![], }, - })) - .await?; + description: Chat::from_text("hehehe"), + favicon: None, + }, + }))?; } Packet761::PingRequest(PingRequestSpec { payload }) => { - client - .send_packet(Packet761::PingResponse(PingResponseSpec { payload })) - .await?; + client.send_packet(Packet761::PingResponse(PingResponseSpec { payload }))?; return Ok(()); } _ => anyhow::bail!("Unexpected packet during status communication"), |