summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs453
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(&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! {
+ 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(&section)?;
+ }
+ 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"),