aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/connect.rs
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-06-18 16:54:49 -0500
committermat <github@matdoes.dev>2022-06-18 16:54:49 -0500
commitfc3151f89db1cf018bfebebb8f102e20911e64d3 (patch)
treee04047dbcbfd9d9e8c6b7a98658ccdb4802eeabd /azalea-client/src/connect.rs
parente32b8fabb78a86e073c7bb3270b1bc89a532350a (diff)
downloadazalea-drasl-fc3151f89db1cf018bfebebb8f102e20911e64d3.tar.xz
account.rs and client.rs
Diffstat (limited to 'azalea-client/src/connect.rs')
-rwxr-xr-xazalea-client/src/connect.rs483
1 files changed, 0 insertions, 483 deletions
diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs
deleted file mode 100755
index dd3162eb..00000000
--- a/azalea-client/src/connect.rs
+++ /dev/null
@@ -1,483 +0,0 @@
-use crate::Player;
-use azalea_core::{resource_location::ResourceLocation, ChunkPos, EntityPos};
-use azalea_entity::Entity;
-use azalea_protocol::{
- connect::{GameConnection, HandshakeConnection},
- packets::{
- game::{
- clientbound_player_chat_packet::ClientboundPlayerChatPacket,
- clientbound_system_chat_packet::ClientboundSystemChatPacket,
- serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
- serverbound_keep_alive_packet::ServerboundKeepAlivePacket, GamePacket,
- },
- handshake::client_intention_packet::ClientIntentionPacket,
- login::{
- serverbound_hello_packet::ServerboundHelloPacket,
- serverbound_key_packet::{NonceOrSaltSignature, ServerboundKeyPacket},
- LoginPacket,
- },
- ConnectionProtocol, PROTOCOL_VERSION,
- },
- resolver, ServerAddress,
-};
-use azalea_world::{ChunkStorage, EntityStorage, World};
-use std::{fmt::Debug, sync::Arc};
-use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
-use tokio::sync::Mutex;
-
-///! Connect to Minecraft servers.
-
-/// Something that can join Minecraft servers.
-pub struct Account {
- username: String,
-}
-
-#[derive(Default)]
-pub struct ClientState {
- pub player: Player,
- pub world: Option<World>,
-}
-
-/// A player that you can control that is currently in a Minecraft server.
-pub struct Client {
- event_receiver: UnboundedReceiver<Event>,
- pub conn: Arc<Mutex<GameConnection>>,
- pub state: Arc<Mutex<ClientState>>,
- // game_loop
-}
-
-#[derive(Debug, Clone)]
-pub enum ChatPacket {
- System(ClientboundSystemChatPacket),
- Player(ClientboundPlayerChatPacket),
-}
-
-// impl ChatPacket {
-// pub fn message(&self) -> &str {
-// match self {
-// ChatPacket::System(p) => &p.content,
-// ChatPacket::Player(p) => &p.message,
-// }
-// }
-// }
-
-#[derive(Debug, Clone)]
-pub enum Event {
- Login,
- Chat(ChatPacket),
-}
-
-/// Whether we should ignore errors when decoding packets.
-const IGNORE_ERRORS: bool = false;
-
-impl Client {
- async fn join(account: &Account, address: &ServerAddress) -> Result<Self, String> {
- let resolved_address = resolver::resolve_address(address).await?;
-
- let mut conn = HandshakeConnection::new(&resolved_address).await?;
-
- // handshake
- conn.write(
- ClientIntentionPacket {
- protocol_version: PROTOCOL_VERSION,
- hostname: address.host.clone(),
- port: address.port,
- intention: ConnectionProtocol::Login,
- }
- .get(),
- )
- .await;
- let mut conn = conn.login();
-
- // login
- conn.write(
- ServerboundHelloPacket {
- username: account.username.clone(),
- public_key: None,
- }
- .get(),
- )
- .await;
-
- let conn = loop {
- let packet_result = conn.read().await;
- match packet_result {
- Ok(packet) => match packet {
- LoginPacket::ClientboundHelloPacket(p) => {
- println!("Got encryption request");
- let e = azalea_crypto::encrypt(&p.public_key, &p.nonce).unwrap();
-
- // TODO: authenticate with the server here (authenticateServer)
-
- conn.write(
- ServerboundKeyPacket {
- nonce_or_salt_signature: NonceOrSaltSignature::Nonce(
- e.encrypted_nonce,
- ),
- key_bytes: e.encrypted_public_key,
- }
- .get(),
- )
- .await;
- conn.set_encryption_key(e.secret_key);
- }
- LoginPacket::ClientboundLoginCompressionPacket(p) => {
- println!("Got compression request {:?}", p.compression_threshold);
- conn.set_compression_threshold(p.compression_threshold);
- }
- LoginPacket::ClientboundGameProfilePacket(p) => {
- println!("Got profile {:?}", p.game_profile);
- break conn.game();
- }
- LoginPacket::ClientboundLoginDisconnectPacket(p) => {
- println!("Got disconnect {:?}", p);
- }
- LoginPacket::ClientboundCustomQueryPacket(p) => {
- println!("Got custom query {:?}", p);
- }
- _ => panic!("Unexpected packet {:?}", packet),
- },
- Err(e) => {
- panic!("Error: {:?}", e);
- }
- }
- };
-
- let conn = Arc::new(Mutex::new(conn));
-
- let (tx, rx) = mpsc::unbounded_channel();
-
- // we got the GameConnection, so the server is now connected :)
- let client = Client {
- event_receiver: rx,
- conn: conn.clone(),
- state: Arc::new(Mutex::new(ClientState::default())),
- };
- // let client = Arc::new(Mutex::new(client));
- // let weak_client = Arc::<_>::downgrade(&client);
-
- // just start up the game loop and we're ready!
- // tokio::spawn(Self::game_loop(conn, tx, handler, state))
-
- let game_loop_state = client.state.clone();
-
- tokio::spawn(Self::game_loop(conn, tx, game_loop_state));
-
- Ok(client)
- }
-
- async fn game_loop(
- conn: Arc<Mutex<GameConnection>>,
- tx: UnboundedSender<Event>,
- state: Arc<Mutex<ClientState>>,
- ) {
- loop {
- let r = conn.lock().await.read().await;
- match r {
- Ok(packet) => Self::handle(&packet, &tx, &state, &conn).await,
- Err(e) => {
- if IGNORE_ERRORS {
- println!("Error: {:?}", e);
- if e == "length wider than 21-bit" {
- panic!();
- }
- } else {
- panic!("Error: {:?}", e);
- }
- }
- };
- }
- }
-
- async fn handle(
- packet: &GamePacket,
- tx: &UnboundedSender<Event>,
- state: &Arc<Mutex<ClientState>>,
- conn: &Arc<Mutex<GameConnection>>,
- ) {
- match packet {
- GamePacket::ClientboundLoginPacket(p) => {
- println!("Got login packet {:?}", p);
-
- let mut state = state.lock().await;
-
- // // write p into login.txt
- // std::io::Write::write_all(
- // &mut std::fs::File::create("login.txt").unwrap(),
- // format!("{:#?}", p).as_bytes(),
- // )
- // .unwrap();
-
- state.player.entity.id = p.player_id;
-
- // TODO: have registry_holder be a struct because this sucks rn
- // best way would be to add serde support to azalea-nbt
-
- let registry_holder = p
- .registry_holder
- .as_compound()
- .expect("Registry holder is not a compound")
- .get("")
- .expect("No \"\" tag")
- .as_compound()
- .expect("\"\" tag is not a compound");
- let dimension_types = registry_holder
- .get("minecraft:dimension_type")
- .expect("No dimension_type tag")
- .as_compound()
- .expect("dimension_type is not a compound")
- .get("value")
- .expect("No dimension_type value")
- .as_list()
- .expect("dimension_type value is not a list");
- let dimension_type = dimension_types
- .iter()
- .find(|t| {
- t.as_compound()
- .expect("dimension_type value is not a compound")
- .get("name")
- .expect("No name tag")
- .as_string()
- .expect("name is not a string")
- == p.dimension_type.to_string()
- })
- .expect(&format!("No dimension_type with name {}", p.dimension_type))
- .as_compound()
- .unwrap()
- .get("element")
- .expect("No element tag")
- .as_compound()
- .expect("element is not a compound");
- let height = (*dimension_type
- .get("height")
- .expect("No height tag")
- .as_int()
- .expect("height tag is not an int"))
- .try_into()
- .expect("height is not a u32");
- let min_y = (*dimension_type
- .get("min_y")
- .expect("No min_y tag")
- .as_int()
- .expect("min_y tag is not an int"))
- .try_into()
- .expect("min_y is not an i32");
-
- state.world = Some(World {
- height,
- min_y,
- storage: ChunkStorage::new(16),
- entities: EntityStorage::new(),
- });
-
- conn.lock()
- .await
- .write(
- ServerboundCustomPayloadPacket {
- identifier: ResourceLocation::new("brand").unwrap(),
- // they don't have to know :)
- data: "vanilla".into(),
- }
- .get(),
- )
- .await;
-
- tx.send(Event::Login).unwrap();
- }
- GamePacket::ClientboundUpdateViewDistancePacket(p) => {
- println!("Got view distance packet {:?}", p);
- }
- GamePacket::ClientboundCustomPayloadPacket(p) => {
- println!("Got custom payload packet {:?}", p);
- }
- GamePacket::ClientboundChangeDifficultyPacket(p) => {
- println!("Got difficulty packet {:?}", p);
- }
- GamePacket::ClientboundDeclareCommandsPacket(_p) => {
- println!("Got declare commands packet");
- }
- GamePacket::ClientboundPlayerAbilitiesPacket(p) => {
- println!("Got player abilities packet {:?}", p);
- }
- GamePacket::ClientboundSetCarriedItemPacket(p) => {
- println!("Got set carried item packet {:?}", p);
- }
- GamePacket::ClientboundUpdateTagsPacket(_p) => {
- println!("Got update tags packet");
- }
- GamePacket::ClientboundDisconnectPacket(p) => {
- println!("Got disconnect packet {:?}", p);
- }
- GamePacket::ClientboundUpdateRecipesPacket(_p) => {
- println!("Got update recipes packet");
- }
- GamePacket::ClientboundEntityEventPacket(p) => {
- // println!("Got entity event packet {:?}", p);
- }
- GamePacket::ClientboundRecipePacket(_p) => {
- println!("Got recipe packet");
- }
- GamePacket::ClientboundPlayerPositionPacket(p) => {
- // TODO: reply with teleport confirm
- println!("Got player position packet {:?}", p);
- }
- GamePacket::ClientboundPlayerInfoPacket(p) => {
- println!("Got player info packet {:?}", p);
- }
- GamePacket::ClientboundSetChunkCacheCenterPacket(p) => {
- println!("Got chunk cache center packet {:?}", p);
- state
- .lock()
- .await
- .world
- .as_mut()
- .unwrap()
- .update_view_center(&ChunkPos::new(p.x, p.z));
- }
- GamePacket::ClientboundLevelChunkWithLightPacket(p) => {
- println!("Got chunk with light packet {} {}", p.x, p.z);
- let pos = ChunkPos::new(p.x, p.z);
- // let chunk = Chunk::read_with_world_height(&mut p.chunk_data);
- // println("chunk {:?}")
- state
- .lock()
- .await
- .world
- .as_mut()
- .expect("World doesn't exist! We should've gotten a login packet by now.")
- .replace_with_packet_data(&pos, &mut p.chunk_data.data.as_slice())
- .unwrap();
- }
- GamePacket::ClientboundLightUpdatePacket(p) => {
- println!("Got light update packet {:?}", p);
- }
- GamePacket::ClientboundAddEntityPacket(p) => {
- println!("Got add entity packet {:?}", p);
- let entity = Entity::from(p);
- state
- .lock()
- .await
- .world
- .as_mut()
- .expect("World doesn't exist! We should've gotten a login packet by now.")
- .entities
- .insert(entity);
- }
- GamePacket::ClientboundSetEntityDataPacket(p) => {
- // println!("Got set entity data packet {:?}", p);
- }
- GamePacket::ClientboundUpdateAttributesPacket(p) => {
- // println!("Got update attributes packet {:?}", p);
- }
- GamePacket::ClientboundEntityVelocityPacket(p) => {
- // println!("Got entity velocity packet {:?}", p);
- }
- GamePacket::ClientboundSetEntityLinkPacket(p) => {
- println!("Got set entity link packet {:?}", p);
- }
- GamePacket::ClientboundAddPlayerPacket(p) => {
- println!("Got add player packet {:?}", p);
- }
- GamePacket::ClientboundInitializeBorderPacket(p) => {
- println!("Got initialize border packet {:?}", p);
- }
- GamePacket::ClientboundSetTimePacket(p) => {
- println!("Got set time packet {:?}", p);
- }
- GamePacket::ClientboundSetDefaultSpawnPositionPacket(p) => {
- println!("Got set default spawn position packet {:?}", p);
- }
- GamePacket::ClientboundContainerSetContentPacket(p) => {
- println!("Got container set content packet {:?}", p);
- }
- GamePacket::ClientboundSetHealthPacket(p) => {
- println!("Got set health packet {:?}", p);
- }
- GamePacket::ClientboundSetExperiencePacket(p) => {
- println!("Got set experience packet {:?}", p);
- }
- GamePacket::ClientboundTeleportEntityPacket(p) => {
- // println!("Got teleport entity packet {:?}", p);
- }
- GamePacket::ClientboundUpdateAdvancementsPacket(p) => {
- println!("Got update advancements packet {:?}", p);
- }
- GamePacket::ClientboundRotateHeadPacket(p) => {
- // println!("Got rotate head packet {:?}", p);
- }
- GamePacket::ClientboundMoveEntityPosPacket(p) => {
- // println!("Got move entity pos packet {:?}", p);
- }
- GamePacket::ClientboundMoveEntityPosRotPacket(p) => {
- // println!("Got move entity pos rot packet {:?}", p);
- }
- GamePacket::ClientboundMoveEntityRotPacket(p) => {
- println!("Got move entity rot packet {:?}", p);
- }
- GamePacket::ClientboundKeepAlivePacket(p) => {
- println!("Got keep alive packet {:?}", p);
- conn.lock()
- .await
- .write(ServerboundKeepAlivePacket { id: p.id }.get())
- .await;
- }
- GamePacket::ClientboundRemoveEntitiesPacket(p) => {
- println!("Got remove entities packet {:?}", p);
- }
- GamePacket::ClientboundPlayerChatPacket(p) => {
- println!("Got player chat packet {:?}", p);
- tx.send(Event::Chat(ChatPacket::Player(p.clone()))).unwrap();
- }
- GamePacket::ClientboundSystemChatPacket(p) => {
- println!("Got system chat packet {:?}", p);
- tx.send(Event::Chat(ChatPacket::System(p.clone()))).unwrap();
- }
- GamePacket::ClientboundSoundPacket(p) => {
- println!("Got sound packet {:?}", p);
- }
- GamePacket::ClientboundLevelEventPacket(p) => {
- println!("Got level event packet {:?}", p);
- }
- GamePacket::ClientboundBlockUpdatePacket(p) => {
- println!("Got block update packet {:?}", p);
- // TODO: update world
- }
- GamePacket::ClientboundAnimatePacket(p) => {
- println!("Got animate packet {:?}", p);
- }
- GamePacket::ClientboundSectionBlocksUpdatePacket(p) => {
- println!("Got section blocks update packet {:?}", p);
- // TODO: update world
- }
- GamePacket::ClientboundGameEventPacket(p) => {
- println!("Got game event packet {:?}", p);
- }
- GamePacket::ClientboundLevelParticlesPacket(p) => {
- println!("Got level particles packet {:?}", p);
- }
- GamePacket::ClientboundServerDataPacket(p) => {
- println!("Got server data packet {:?}", p);
- }
- GamePacket::ClientboundSetEquipmentPacket(p) => {
- println!("Got set equipment packet {:?}", p);
- }
- _ => panic!("Unexpected packet {:?}", packet),
- }
- }
-
- pub async fn next(&mut self) -> Option<Event> {
- self.event_receiver.recv().await
- }
-}
-
-impl Account {
- pub fn offline(username: &str) -> Self {
- Self {
- username: username.to_string(),
- }
- }
-
- pub async fn join(&self, address: &ServerAddress) -> Result<Client, String> {
- Client::join(self, address).await
- }
-}