1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

Add chat function (#28)

* add Client::chat

* make the default bot do chat
This commit is contained in:
mat 2022-10-16 23:08:39 -05:00 committed by GitHub
parent ab9e50b130
commit 0f88e05a0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 5 deletions

74
azalea-client/src/chat.rs Normal file
View file

@ -0,0 +1,74 @@
use std::time::{SystemTime, UNIX_EPOCH};
use azalea_crypto::MessageSignature;
use azalea_protocol::packets::game::{
clientbound_player_chat_packet::LastSeenMessagesUpdate,
serverbound_chat_command_packet::ServerboundChatCommandPacket,
serverbound_chat_packet::ServerboundChatPacket,
};
use crate::Client;
impl Client {
/// Sends chat message to the server. This only sends the chat packet and
/// not the command packet. The `chat` function handles checking whether
/// the message is a command and using the proper packet for you.
pub async fn send_chat_packet(&self, message: &str) -> Result<(), std::io::Error> {
// TODO: chat signing
let signature = sign_message();
let packet = ServerboundChatPacket {
message: message.to_string(),
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time shouldn't be before epoch")
.as_millis()
.try_into()
.expect("Instant should fit into a u64"),
salt: azalea_crypto::make_salt(),
signature,
signed_preview: false,
last_seen_messages: LastSeenMessagesUpdate::default(),
}
.get();
self.write_packet(packet).await
}
/// Send a command packet to the server. The `command` argument should not
/// include the slash at the front.
pub async fn send_command_packet(&self, command: &str) -> Result<(), std::io::Error> {
// TODO: chat signing
let packet = ServerboundChatCommandPacket {
command: command.to_string(),
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time shouldn't be before epoch")
.as_millis()
.try_into()
.expect("Instant should fit into a u64"),
salt: azalea_crypto::make_salt(),
argument_signatures: vec![],
signed_preview: false,
last_seen_messages: LastSeenMessagesUpdate::default(),
}
.get();
self.write_packet(packet).await
}
pub async fn chat(&self, message: &str) -> Result<(), std::io::Error> {
if message.chars().next() == Some('/') {
self.send_command_packet(&message[1..]).await
} else {
self.send_chat_packet(message).await
}
}
// will be used for when the server tells the client about a chat preview
// with custom formatting
// pub fn acknowledge_preview(&self, message: &str) {}
}
// TODO
// MessageSigner, ChatMessageContent, LastSeenMessages
fn sign_message() -> MessageSignature {
MessageSignature::default()
}

View file

@ -1,6 +1,7 @@
//! Significantly abstract azalea-protocol so it's actually useable for bots.
mod account;
mod chat;
mod client;
mod get_mc_dir;
mod movement;

View file

@ -17,3 +17,8 @@ pub struct SignedMessageHeader {
pub previous_signature: Option<MessageSignature>,
pub sender: Uuid,
}
/// Generates a random u64 to use as a salt
pub fn make_salt() -> u64 {
rand::random()
}

View file

@ -68,7 +68,7 @@ pub struct LastSeenMessagesEntry {
pub last_signature: MessageSignature,
}
#[derive(Clone, Debug, McBuf)]
#[derive(Clone, Debug, McBuf, Default)]
pub struct LastSeenMessagesUpdate {
pub last_seen: Vec<LastSeenMessagesEntry>,
pub last_received: Option<LastSeenMessagesEntry>,

View file

@ -9,7 +9,7 @@ pub struct ServerboundChatCommandPacket {
pub command: String,
// TODO: Choose a real timestamp type
pub timestamp: u64,
pub salt: i64,
pub salt: u64,
pub argument_signatures: Vec<ArgumentSignature>,
pub signed_preview: bool,
pub last_seen_messages: LastSeenMessagesUpdate,

View file

@ -10,7 +10,7 @@ struct State {}
async fn main() -> anyhow::Result<()> {
env_logger::init();
let account = Account::microsoft("example2@example.com").await?;
let account = Account::microsoft("example@example.com").await?;
azalea::start(azalea::Options {
account,
@ -26,8 +26,14 @@ async fn main() -> anyhow::Result<()> {
}
async fn handle(bot: Client, event: Arc<Event>, _state: Arc<Mutex<State>>) -> anyhow::Result<()> {
if let Event::Tick = *event {
bot.jump();
match *event {
Event::Login => {
bot.chat("Hello world").await?;
}
Event::Tick => {
bot.jump();
}
_ => {}
}
Ok(())