mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
Add Client::set_client_information (#33)
* start adding options * add default options * send options packet by default * mention set_options in Client::join doc * make TranslatableComponent::read return TextComponent * change set_options to set_client_information * clean up some code * Add `Initialize` event * fix some clippy warnings * change `Client::options` to `client_information`
This commit is contained in:
parent
587001724a
commit
65da123631
16 changed files with 97 additions and 23 deletions
|
@ -56,11 +56,7 @@ pub enum AuthError {
|
||||||
/// though, and in case the Microsoft API does start providing the real email.
|
/// though, and in case the Microsoft API does start providing the real email.
|
||||||
pub async fn auth(email: &str, opts: AuthOpts) -> Result<AuthResult, AuthError> {
|
pub async fn auth(email: &str, opts: AuthOpts) -> Result<AuthResult, AuthError> {
|
||||||
let cached_account = if let Some(cache_file) = &opts.cache_file {
|
let cached_account = if let Some(cache_file) = &opts.cache_file {
|
||||||
if let Some(account) = cache::get_account_in_cache(cache_file, email).await {
|
cache::get_account_in_cache(cache_file, email).await
|
||||||
Some(account)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -110,7 +110,6 @@ impl McBufWritable for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl McBufWritable for &str {
|
impl McBufWritable for &str {
|
||||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||||
write_utf_with_len(buf, self, MAX_STRING_LENGTH.into())
|
write_utf_with_len(buf, self, MAX_STRING_LENGTH.into())
|
||||||
|
|
0
azalea-chat/src/text_component.rs
Executable file → Normal file
0
azalea-chat/src/text_component.rs
Executable file → Normal file
6
azalea-chat/src/translatable_component.rs
Executable file → Normal file
6
azalea-chat/src/translatable_component.rs
Executable file → Normal file
|
@ -59,7 +59,7 @@ impl TranslatableComponent {
|
||||||
.args
|
.args
|
||||||
.get(matched)
|
.get(matched)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(StringOrComponent::String("".to_string()));
|
.unwrap_or_else(|| StringOrComponent::String("".to_string()));
|
||||||
|
|
||||||
components.push(TextComponent::new(built_text.clone()));
|
components.push(TextComponent::new(built_text.clone()));
|
||||||
built_text.clear();
|
built_text.clear();
|
||||||
|
@ -107,7 +107,7 @@ impl TranslatableComponent {
|
||||||
|
|
||||||
Ok(TextComponent {
|
Ok(TextComponent {
|
||||||
base: BaseComponent {
|
base: BaseComponent {
|
||||||
siblings: components.into_iter().map(|c| Component::Text(c)).collect(),
|
siblings: components.into_iter().map(Component::Text).collect(),
|
||||||
style: Style::default(),
|
style: Style::default(),
|
||||||
},
|
},
|
||||||
text: "".to_string(),
|
text: "".to_string(),
|
||||||
|
@ -135,7 +135,7 @@ impl Display for StringOrComponent {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
match self {
|
match self {
|
||||||
StringOrComponent::String(s) => write!(f, "{}", s),
|
StringOrComponent::String(s) => write!(f, "{}", s),
|
||||||
StringOrComponent::Component(c) => write!(f, "{}", c.to_string()),
|
StringOrComponent::Component(c) => write!(f, "{}", c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,8 +84,8 @@ impl Client {
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn chat(&self, message: &str) -> Result<(), std::io::Error> {
|
pub async fn chat(&self, message: &str) -> Result<(), std::io::Error> {
|
||||||
if message.starts_with('/') {
|
if let Some(command) = message.strip_prefix('/') {
|
||||||
self.send_command_packet(&message[1..]).await
|
self.send_command_packet(command).await
|
||||||
} else {
|
} else {
|
||||||
self.send_chat_packet(message).await
|
self.send_chat_packet(message).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use azalea_protocol::{
|
||||||
clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
||||||
clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
||||||
serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket,
|
serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket,
|
||||||
|
serverbound_client_information_packet::ServerboundClientInformationPacket,
|
||||||
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||||
serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
||||||
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||||
|
@ -30,7 +31,7 @@ use azalea_world::{
|
||||||
Dimension,
|
Dimension,
|
||||||
};
|
};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::{Mutex, RwLock};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
io::{self, Cursor},
|
io::{self, Cursor},
|
||||||
|
@ -43,10 +44,17 @@ use tokio::{
|
||||||
time::{self},
|
time::{self},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub type ClientInformation = ServerboundClientInformationPacket;
|
||||||
|
|
||||||
/// Events are sent before they're processed, so for example game ticks happen
|
/// Events are sent before they're processed, so for example game ticks happen
|
||||||
/// at the beginning of a tick before anything has happened.
|
/// at the beginning of a tick before anything has happened.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
|
/// Happens right after the bot switches into the Game state, but before
|
||||||
|
/// it's actually spawned. This can be useful for setting the client
|
||||||
|
/// information with `Client::set_client_information`, so the packet
|
||||||
|
/// doesn't have to be sent twice.
|
||||||
|
Initialize,
|
||||||
Login,
|
Login,
|
||||||
Chat(ChatPacket),
|
Chat(ChatPacket),
|
||||||
/// Happens 20 times per second, but only when the world is loaded.
|
/// Happens 20 times per second, but only when the world is loaded.
|
||||||
|
@ -78,6 +86,7 @@ pub struct Client {
|
||||||
pub player: Arc<Mutex<Player>>,
|
pub player: Arc<Mutex<Player>>,
|
||||||
pub dimension: Arc<Mutex<Dimension>>,
|
pub dimension: Arc<Mutex<Dimension>>,
|
||||||
pub physics_state: Arc<Mutex<PhysicsState>>,
|
pub physics_state: Arc<Mutex<PhysicsState>>,
|
||||||
|
pub client_information: Arc<RwLock<ClientInformation>>,
|
||||||
tasks: Arc<Mutex<Vec<JoinHandle<()>>>>,
|
tasks: Arc<Mutex<Vec<JoinHandle<()>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +132,8 @@ pub enum HandleError {
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Connect to a Minecraft server.
|
/// Connect to a Minecraft server.
|
||||||
///
|
///
|
||||||
|
/// To change the render distance and other settings, use [`Client::set_client_information`].
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
|
@ -240,8 +251,11 @@ impl Client {
|
||||||
dimension: Arc::new(Mutex::new(Dimension::default())),
|
dimension: Arc::new(Mutex::new(Dimension::default())),
|
||||||
physics_state: Arc::new(Mutex::new(PhysicsState::default())),
|
physics_state: Arc::new(Mutex::new(PhysicsState::default())),
|
||||||
tasks: Arc::new(Mutex::new(Vec::new())),
|
tasks: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
client_information: Arc::new(RwLock::new(ClientInformation::default())),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tx.send(Event::Initialize).unwrap();
|
||||||
|
|
||||||
// just start up the game loop and we're ready!
|
// just start up the game loop and we're ready!
|
||||||
|
|
||||||
// if you get an error right here that means you're doing something with locks wrong
|
// if you get an error right here that means you're doing something with locks wrong
|
||||||
|
@ -389,6 +403,12 @@ impl Client {
|
||||||
player_lock.set_entity_id(p.player_id);
|
player_lock.set_entity_id(p.player_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send the client information that we have set
|
||||||
|
let client_information_packet: ClientInformation =
|
||||||
|
client.client_information.read().clone();
|
||||||
|
client.write_packet(client_information_packet.get()).await?;
|
||||||
|
|
||||||
|
// brand
|
||||||
client
|
client
|
||||||
.write_packet(
|
.write_packet(
|
||||||
ServerboundCustomPayloadPacket {
|
ServerboundCustomPayloadPacket {
|
||||||
|
@ -806,6 +826,35 @@ impl Client {
|
||||||
.entity(entity_id)
|
.entity(entity_id)
|
||||||
.expect("Player entity should be in the given dimension")
|
.expect("Player entity should be in the given dimension")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether we have a received the login packet yet.
|
||||||
|
pub fn logged_in(&self) -> bool {
|
||||||
|
let dimension = self.dimension.lock();
|
||||||
|
let player = self.player.lock();
|
||||||
|
player.entity(&dimension).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tell the server we changed our game options (i.e. render distance, main hand).
|
||||||
|
/// If this is not set before the login packet, the default will be sent.
|
||||||
|
pub async fn set_client_information(
|
||||||
|
&self,
|
||||||
|
client_information: ServerboundClientInformationPacket,
|
||||||
|
) -> Result<(), std::io::Error> {
|
||||||
|
{
|
||||||
|
let mut client_information_lock = self.client_information.write();
|
||||||
|
*client_information_lock = client_information;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.logged_in() {
|
||||||
|
let client_information_packet = {
|
||||||
|
let client_information = self.client_information.read();
|
||||||
|
client_information.clone().get()
|
||||||
|
};
|
||||||
|
self.write_packet(client_information_packet).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<std::sync::PoisonError<T>> for HandleError {
|
impl<T> From<std::sync::PoisonError<T>> for HandleError {
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub mod ping;
|
||||||
mod player;
|
mod player;
|
||||||
|
|
||||||
pub use account::Account;
|
pub use account::Account;
|
||||||
pub use client::{Client, Event};
|
pub use client::{Client, ClientInformation, Event};
|
||||||
pub use movement::MoveDirection;
|
pub use movement::MoveDirection;
|
||||||
pub use player::Player;
|
pub use player::Player;
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
||||||
/// `ClientboundLoginPacket::Hello` packet.
|
/// `ClientboundLoginPacket::Hello` packet.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// let token = azalea_auth::auth(azalea_auth::AuthOpts {
|
/// let token = azalea_auth::auth(azalea_auth::AuthOpts {
|
||||||
/// ..Default::default()
|
/// ..Default::default()
|
||||||
|
|
|
@ -3,20 +3,48 @@ use azalea_protocol_macros::ServerboundGamePacket;
|
||||||
|
|
||||||
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
|
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
|
||||||
pub struct ServerboundClientInformationPacket {
|
pub struct ServerboundClientInformationPacket {
|
||||||
|
/// The locale of the client.
|
||||||
pub language: String,
|
pub language: String,
|
||||||
|
/// The view distance of the client in chunks, same as the render distance
|
||||||
|
/// in-game.
|
||||||
pub view_distance: u8,
|
pub view_distance: u8,
|
||||||
|
/// The types of chat messages the client wants to receive. Note that many
|
||||||
|
/// servers ignore this.
|
||||||
pub chat_visibility: ChatVisibility,
|
pub chat_visibility: ChatVisibility,
|
||||||
|
/// Whether the messages sent from the server should have colors. Note that
|
||||||
|
/// many servers ignore this and always send colored messages.
|
||||||
pub chat_colors: bool,
|
pub chat_colors: bool,
|
||||||
pub model_customisation: u8,
|
pub model_customisation: u8,
|
||||||
pub main_hand: HumanoidArm,
|
pub main_hand: HumanoidArm,
|
||||||
pub text_filtering_enabled: bool,
|
pub text_filtering_enabled: bool,
|
||||||
|
/// Whether the client should show up as "Anonymous Player" in the server
|
||||||
|
/// list.
|
||||||
pub allows_listing: bool,
|
pub allows_listing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for ServerboundClientInformationPacket {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
language: "en_us".to_string(),
|
||||||
|
view_distance: 8,
|
||||||
|
chat_visibility: ChatVisibility::Full,
|
||||||
|
chat_colors: true,
|
||||||
|
model_customisation: 0,
|
||||||
|
main_hand: HumanoidArm::Right,
|
||||||
|
text_filtering_enabled: false,
|
||||||
|
allows_listing: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(McBuf, Clone, Copy, Debug)]
|
#[derive(McBuf, Clone, Copy, Debug)]
|
||||||
pub enum ChatVisibility {
|
pub enum ChatVisibility {
|
||||||
|
/// All chat messages should be sent to the client.
|
||||||
Full = 0,
|
Full = 0,
|
||||||
|
/// Chat messages from other players should be not sent to the client, only
|
||||||
|
/// messages from the server like "Player joined the game" should be sent.
|
||||||
System = 1,
|
System = 1,
|
||||||
|
/// No chat messages should be sent to the client.
|
||||||
Hidden = 2,
|
Hidden = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,8 @@ impl ChunkStorage {
|
||||||
if !self.in_range(pos) {
|
if !self.in_range(pos) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"Ignoring chunk since it's not in the view range: {}, {}",
|
"Ignoring chunk since it's not in the view range: {}, {}",
|
||||||
pos.x, pos.z
|
pos.x,
|
||||||
|
pos.z
|
||||||
);
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use azalea::{pathfinder, Account};
|
use azalea::pathfinder;
|
||||||
use azalea::{Bot, Client, Event};
|
use azalea::prelude::*;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
//! A simple bot that repeats chat messages sent by other players.
|
//! A simple bot that repeats chat messages sent by other players.
|
||||||
|
|
||||||
use azalea::{Account, Client, Event};
|
use azalea::prelude::*;
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod autoeat;
|
mod autoeat;
|
||||||
|
|
||||||
use azalea::prelude::*;
|
use azalea::prelude::*;
|
||||||
use azalea::{pathfinder, Account, BlockPos, Client, Event, ItemKind, MoveDirection, Plugin, Vec3};
|
use azalea::{pathfinder, BlockPos, ItemKind, Vec3};
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
struct State {}
|
struct State {}
|
||||||
|
|
|
@ -129,7 +129,7 @@ pub enum Error {
|
||||||
/// it gets disconnected from the server.
|
/// it gets disconnected from the server.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// let error = azalea::start(azalea::Options {
|
/// let error = azalea::start(azalea::Options {
|
||||||
/// account,
|
/// account,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! The Azalea prelude.
|
//! The Azalea prelude. Things that are necessary for a bare-bones bot are re-exported here.
|
||||||
|
|
||||||
pub use crate::bot::BotTrait;
|
pub use crate::bot::BotTrait;
|
||||||
pub use azalea_client::{Account, Client, Event};
|
pub use azalea_client::{Account, Client, Event};
|
||||||
|
|
|
@ -28,6 +28,9 @@ async fn handle(bot: Client, event: Event, _state: State) -> anyhow::Result<()>
|
||||||
Event::Login => {
|
Event::Login => {
|
||||||
bot.chat("Hello world").await?;
|
bot.chat("Hello world").await?;
|
||||||
}
|
}
|
||||||
|
Event::Initialize => {
|
||||||
|
println!("initialized");
|
||||||
|
}
|
||||||
Event::Tick => {
|
Event::Tick => {
|
||||||
bot.jump();
|
bot.jump();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue