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.
|
||||
pub async fn auth(email: &str, opts: AuthOpts) -> Result<AuthResult, AuthError> {
|
||||
let cached_account = if let Some(cache_file) = &opts.cache_file {
|
||||
if let Some(account) = cache::get_account_in_cache(cache_file, email).await {
|
||||
Some(account)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
cache::get_account_in_cache(cache_file, email).await
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
@ -110,7 +110,6 @@ impl McBufWritable for String {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl McBufWritable for &str {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
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
|
||||
.get(matched)
|
||||
.cloned()
|
||||
.unwrap_or(StringOrComponent::String("".to_string()));
|
||||
.unwrap_or_else(|| StringOrComponent::String("".to_string()));
|
||||
|
||||
components.push(TextComponent::new(built_text.clone()));
|
||||
built_text.clear();
|
||||
|
@ -107,7 +107,7 @@ impl TranslatableComponent {
|
|||
|
||||
Ok(TextComponent {
|
||||
base: BaseComponent {
|
||||
siblings: components.into_iter().map(|c| Component::Text(c)).collect(),
|
||||
siblings: components.into_iter().map(Component::Text).collect(),
|
||||
style: Style::default(),
|
||||
},
|
||||
text: "".to_string(),
|
||||
|
@ -135,7 +135,7 @@ impl Display for StringOrComponent {
|
|||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
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> {
|
||||
if message.starts_with('/') {
|
||||
self.send_command_packet(&message[1..]).await
|
||||
if let Some(command) = message.strip_prefix('/') {
|
||||
self.send_command_packet(command).await
|
||||
} else {
|
||||
self.send_chat_packet(message).await
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use azalea_protocol::{
|
|||
clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
||||
clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
||||
serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket,
|
||||
serverbound_client_information_packet::ServerboundClientInformationPacket,
|
||||
serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||
serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
||||
serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||
|
@ -30,7 +31,7 @@ use azalea_world::{
|
|||
Dimension,
|
||||
};
|
||||
use log::{debug, error, warn};
|
||||
use parking_lot::Mutex;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
io::{self, Cursor},
|
||||
|
@ -43,10 +44,17 @@ use tokio::{
|
|||
time::{self},
|
||||
};
|
||||
|
||||
pub type ClientInformation = ServerboundClientInformationPacket;
|
||||
|
||||
/// Events are sent before they're processed, so for example game ticks happen
|
||||
/// at the beginning of a tick before anything has happened.
|
||||
#[derive(Debug, Clone)]
|
||||
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,
|
||||
Chat(ChatPacket),
|
||||
/// 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 dimension: Arc<Mutex<Dimension>>,
|
||||
pub physics_state: Arc<Mutex<PhysicsState>>,
|
||||
pub client_information: Arc<RwLock<ClientInformation>>,
|
||||
tasks: Arc<Mutex<Vec<JoinHandle<()>>>>,
|
||||
}
|
||||
|
||||
|
@ -123,6 +132,8 @@ pub enum HandleError {
|
|||
impl Client {
|
||||
/// Connect to a Minecraft server.
|
||||
///
|
||||
/// To change the render distance and other settings, use [`Client::set_client_information`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
|
@ -240,8 +251,11 @@ impl Client {
|
|||
dimension: Arc::new(Mutex::new(Dimension::default())),
|
||||
physics_state: Arc::new(Mutex::new(PhysicsState::default())),
|
||||
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!
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
.write_packet(
|
||||
ServerboundCustomPayloadPacket {
|
||||
|
@ -806,6 +826,35 @@ impl Client {
|
|||
.entity(entity_id)
|
||||
.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 {
|
||||
|
|
|
@ -14,7 +14,7 @@ pub mod ping;
|
|||
mod player;
|
||||
|
||||
pub use account::Account;
|
||||
pub use client::{Client, Event};
|
||||
pub use client::{Client, ClientInformation, Event};
|
||||
pub use movement::MoveDirection;
|
||||
pub use player::Player;
|
||||
|
||||
|
|
|
@ -3,20 +3,48 @@ use azalea_protocol_macros::ServerboundGamePacket;
|
|||
|
||||
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
|
||||
pub struct ServerboundClientInformationPacket {
|
||||
/// The locale of the client.
|
||||
pub language: String,
|
||||
/// The view distance of the client in chunks, same as the render distance
|
||||
/// in-game.
|
||||
pub view_distance: u8,
|
||||
/// The types of chat messages the client wants to receive. Note that many
|
||||
/// servers ignore this.
|
||||
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 model_customisation: u8,
|
||||
pub main_hand: HumanoidArm,
|
||||
pub text_filtering_enabled: bool,
|
||||
/// Whether the client should show up as "Anonymous Player" in the server
|
||||
/// list.
|
||||
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)]
|
||||
pub enum ChatVisibility {
|
||||
/// All chat messages should be sent to the client.
|
||||
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,
|
||||
/// No chat messages should be sent to the client.
|
||||
Hidden = 2,
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,8 @@ impl ChunkStorage {
|
|||
if !self.in_range(pos) {
|
||||
log::trace!(
|
||||
"Ignoring chunk since it's not in the view range: {}, {}",
|
||||
pos.x, pos.z
|
||||
pos.x,
|
||||
pos.z
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use azalea::{pathfinder, Account};
|
||||
use azalea::{Bot, Client, Event};
|
||||
use azalea::pathfinder;
|
||||
use azalea::prelude::*;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
//! A simple bot that repeats chat messages sent by other players.
|
||||
|
||||
use azalea::{Account, Client, Event};
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
use azalea::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod autoeat;
|
||||
|
||||
use azalea::prelude::*;
|
||||
use azalea::{pathfinder, Account, BlockPos, Client, Event, ItemKind, MoveDirection, Plugin, Vec3};
|
||||
use azalea::{pathfinder, BlockPos, ItemKind, Vec3};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct State {}
|
||||
|
|
|
@ -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 azalea_client::{Account, Client, Event};
|
||||
|
|
|
@ -28,6 +28,9 @@ async fn handle(bot: Client, event: Event, _state: State) -> anyhow::Result<()>
|
|||
Event::Login => {
|
||||
bot.chat("Hello world").await?;
|
||||
}
|
||||
Event::Initialize => {
|
||||
println!("initialized");
|
||||
}
|
||||
Event::Tick => {
|
||||
bot.jump();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue