use std::net::TcpStream;
use simdnbt::owned::{NbtList, NbtTag};
use crate::{
Player, ServerError, StatusConfig,
channel_message::{ChannelMessage, MessageData},
message::MessageGenerator,
minecraft::{
auth::authenticate,
encrypt::Aes128CfbEnc,
handshake::Handshake,
login_start::LoginStart,
packet::{Packet, ReadPacketData},
packets, protocol_version,
server::ConnectionState,
},
token::TokenGenerator,
};
pub fn advance<T: TokenGenerator, M: MessageGenerator>(
stream: &mut TcpStream,
state: ConnectionState<T, M>,
handshake: Handshake,
status_config: StatusConfig,
) -> Result<(), ServerError> {
if handshake.protocol_version.0 < protocol_version::MIN_SUPPORTED_PROTOCOL {
packets::disconnect_login(&status_config.legacy_decription.unwrap_or_default())
.write_stream(stream)?;
return Ok(());
}
let mut packet = Packet::from_stream(stream, 0x00)?;
let login_start = LoginStart::read(&mut packet.data)?;
let mut auth_res = authenticate(
stream,
&state.public_key,
&state.private_key,
&login_start,
handshake.protocol_version.0,
)?;
let player = Player {
username: auth_res.profile.name,
uuid: auth_res.profile.id,
};
let token = send_disconnect(stream, state.clone(), &player, &mut auth_res.enc)?;
state
.broadcast
.send(ChannelMessage::new(MessageData::OnJoin {
player,
token: token.to_string(),
}));
Ok(())
}
fn send_disconnect<T: TokenGenerator, M: MessageGenerator>(
stream: &mut TcpStream,
state: ConnectionState<T, M>,
player: &Player,
enc: &mut Aes128CfbEnc,
) -> Result<String, ServerError> {
let gen_token = state.token.generate(&player);
let msg = state
.message
.create_message(&state.token.display(&gen_token));
match msg {
NbtTag::Compound(_) => (),
NbtTag::String(_) => (),
NbtTag::List(NbtList::Compound(_)) => (),
NbtTag::List(NbtList::String(_)) => (),
_ => return Err(ServerError::InvalidMessageNbtTag(msg)),
}
packets::disconnect_configuration(msg).write_compressed_encrypted_stream(stream, enc)?;
Ok(gen_token)
}