diff options
Diffstat (limited to 'azalea-client/src')
| -rwxr-xr-x | azalea-client/src/account.rs | 6 | ||||
| -rw-r--r-- | azalea-client/src/client.rs | 36 | ||||
| -rw-r--r-- | azalea-client/src/entity_query.rs | 9 | ||||
| -rw-r--r-- | azalea-client/src/local_player.rs | 24 | ||||
| -rw-r--r-- | azalea-client/src/movement.rs | 4 | ||||
| -rw-r--r-- | azalea-client/src/packet_handling.rs | 42 | ||||
| -rw-r--r-- | azalea-client/src/task_pool.rs | 2 |
7 files changed, 84 insertions, 39 deletions
diff --git a/azalea-client/src/account.rs b/azalea-client/src/account.rs index 3c2c7d1b..b6073209 100755 --- a/azalea-client/src/account.rs +++ b/azalea-client/src/account.rs @@ -8,7 +8,8 @@ use uuid::Uuid; /// Something that can join Minecraft servers. /// -/// To join a server using this account, use [`crate::Client::join`]. +/// To join a server using this account, use [`Client::join`] or +/// [`azalea::ClientBuilder`]. /// /// # Examples /// @@ -21,6 +22,9 @@ use uuid::Uuid; /// // or Account::offline("example"); /// # } /// ``` +/// +/// [`Client::join`]: crate::Client::join +/// [`azalea::ClientBuilder`]: https://docs.rs/azalea/latest/azalea/struct.ClientBuilder.html #[derive(Clone, Debug)] pub struct Account { /// The Minecraft username of the account. diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index bc1d8d62..ddeeeef3 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -42,7 +42,7 @@ use azalea_protocol::{ }, resolver, ServerAddress, }; -use azalea_world::{EntityPlugin, Local, PartialWorld, World, WorldContainer}; +use azalea_world::{entity::WorldName, EntityPlugin, Local, PartialWorld, World, WorldContainer}; use log::{debug, error}; use parking_lot::{Mutex, RwLock}; use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc}; @@ -52,8 +52,13 @@ use uuid::Uuid; pub type ClientInformation = ServerboundClientInformationPacket; -/// Client has the things that a user interacting with the library will want. +/// `Client` has the things that a user interacting with the library will want. /// Things that a player in the world will want to know are in [`LocalPlayer`]. +/// +/// To make a new client, use either [`azalea::ClientBuilder`] or +/// [`Client::join`]. +/// +/// [`azalea::ClientBuilder`]: https://docs.rs/azalea/latest/azalea/struct.ClientBuilder.html #[derive(Clone)] pub struct Client { /// The [`GameProfile`] for our client. This contains your username, UUID, @@ -362,6 +367,17 @@ impl Client { /// Get a component from this client. This will clone the component and /// return it. + /// + /// # Panics + /// + /// This will panic if the component doesn't exist on the client. + /// + /// # Examples + /// + /// ``` + /// # fn example(client: &azalea::Client) { + /// let world_name = client.component::<WorldName>(); + /// # } pub fn component<T: Component + Clone>(&self) -> T { self.query::<&T>(&mut self.ecs.lock()).clone() } @@ -373,17 +389,8 @@ impl Client { /// If the client using a shared world, then the shared world will be a /// superset of the client's world. pub fn world(&self) -> Arc<RwLock<World>> { - let mut ecs = self.ecs.lock(); - - let world_name = { - let local_player = self.local_player(&mut ecs); - local_player - .world_name - .as_ref() - .expect("World name must be known if we're doing Client::world") - .clone() - }; - + let world_name = self.component::<WorldName>(); + let ecs = self.ecs.lock(); let world_container = ecs.resource::<WorldContainer>(); world_container.get(&world_name).unwrap() } @@ -391,7 +398,8 @@ impl Client { /// Returns whether we have a received the login packet yet. pub fn logged_in(&self) -> bool { // the login packet tells us the world name - self.local_player(&mut self.ecs.lock()).world_name.is_some() + self.query::<Option<&WorldName>>(&mut self.ecs.lock()) + .is_some() } /// Tell the server we changed our game options (i.e. render distance, main diff --git a/azalea-client/src/entity_query.rs b/azalea-client/src/entity_query.rs index 0e486741..7ac0e325 100644 --- a/azalea-client/src/entity_query.rs +++ b/azalea-client/src/entity_query.rs @@ -12,6 +12,15 @@ use crate::Client; impl Client { /// A convenience function for getting components of our player's entity. + /// + /// # Examples + /// ``` + /// # fn example(mut client: azalea_client::Client) { + /// let is_logged_in = client + /// .query::<Option<&WorldName>>(&mut client.ecs.lock()) + /// .is_some(); + /// # } + /// ``` pub fn query<'w, Q: WorldQuery>(&self, ecs: &'w mut Ecs) -> <Q as WorldQuery>::Item<'w> { ecs.query::<Q>() .get_mut(ecs, self.entity) diff --git a/azalea-client/src/local_player.rs b/azalea-client/src/local_player.rs index 0165a5f5..a6921d76 100644 --- a/azalea-client/src/local_player.rs +++ b/azalea-client/src/local_player.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, io, sync::Arc}; use azalea_auth::game_profile::GameProfile; -use azalea_core::{ChunkPos, ResourceLocation}; +use azalea_core::ChunkPos; use azalea_ecs::component::Component; use azalea_ecs::entity::Entity; use azalea_ecs::{query::Added, system::Query}; @@ -21,22 +21,29 @@ use crate::{ ClientInformation, PlayerInfo, WalkDirection, }; -/// A player that you control that is currently in a Minecraft server. +/// This is a component for our local player entities that are probably in a +/// world. If you have access to a [`Client`], you probably don't need to care +/// about this since `Client` gives you access to everything here. +/// +/// You can also use the [`Local`] marker component for queries if you're only +/// checking for a local player and don't need the contents of this component. +/// +/// [`Local`]: azalea_world::Local +/// [`Client`]: crate::Client #[derive(Component)] pub struct LocalPlayer { - pub packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>, - + packet_writer: mpsc::UnboundedSender<ServerboundGamePacket>, + /// Some of the "settings" for this client that are sent to the server, such + /// as render distance. pub client_information: ClientInformation, - /// A map of player uuids to their information in the tab list + /// A map of player UUIDs to their information in the tab list pub players: HashMap<Uuid, PlayerInfo>, - /// The partial world is the world this client currently has loaded. It has /// a limited render distance. pub partial_world: Arc<RwLock<PartialWorld>>, /// The world is the combined [`PartialWorld`]s of all clients in the same /// world. (Only relevant if you're using a shared world, i.e. a swarm) pub world: Arc<RwLock<World>>, - pub world_name: Option<ResourceLocation>, /// A list of async tasks that are running and will stop running when this /// LocalPlayer is dropped or disconnected with [`Self::disconnect`] @@ -93,13 +100,12 @@ impl LocalPlayer { client_information.view_distance.into(), Some(entity), ))), - world_name: None, tasks: Vec::new(), } } - /// Spawn a task to write a packet directly to the server. + /// Write a packet directly to the server. pub fn write_packet(&mut self, packet: ServerboundGamePacket) { self.packet_writer .send(packet) diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs index 8d6faabe..f379501c 100644 --- a/azalea-client/src/movement.rs +++ b/azalea-client/src/movement.rs @@ -333,6 +333,8 @@ impl Client { } } +/// An event sent when the client starts walking. This does not get sent for +/// non-local entities. pub struct StartWalkEvent { pub entity: Entity, pub direction: WalkDirection, @@ -354,6 +356,8 @@ pub fn walk_listener( } } +/// An event sent when the client starts sprinting. This does not get sent for +/// non-local entities. pub struct StartSprintEvent { pub entity: Entity, pub direction: SprintDirection, diff --git a/azalea-client/src/packet_handling.rs b/azalea-client/src/packet_handling.rs index db2c3c45..2d591531 100644 --- a/azalea-client/src/packet_handling.rs +++ b/azalea-client/src/packet_handling.rs @@ -26,7 +26,7 @@ use azalea_world::{ entity::{ metadata::{apply_metadata, Health, PlayerMetadataBundle}, set_rotation, Dead, EntityBundle, EntityKind, LastSentPosition, MinecraftEntityId, Physics, - PlayerBundle, Position, + PlayerBundle, Position, WorldName, }, LoadedBy, PartialWorld, RelativeEntityUpdate, WorldContainer, }; @@ -128,11 +128,16 @@ fn handle_packets(ecs: &mut Ecs) { #[allow(clippy::type_complexity)] let mut system_state: SystemState<( Commands, - Query<(&mut LocalPlayer, &GameProfileComponent)>, + Query<( + &mut LocalPlayer, + Option<&mut WorldName>, + &GameProfileComponent, + )>, ResMut<WorldContainer>, )> = SystemState::new(ecs); let (mut commands, mut query, mut world_container) = system_state.get_mut(ecs); - let (mut local_player, game_profile) = query.get_mut(player_entity).unwrap(); + let (mut local_player, world_name, game_profile) = + query.get_mut(player_entity).unwrap(); { // TODO: have registry_holder be a struct because this sucks rn @@ -188,12 +193,19 @@ fn handle_packets(ecs: &mut Ecs) { .as_int() .expect("min_y tag is not an int"); - let world_name = p.dimension.clone(); + let new_world_name = p.dimension.clone(); - local_player.world_name = Some(world_name.clone()); + if let Some(mut world_name) = world_name { + *world_name = world_name.clone(); + } else { + commands + .entity(player_entity) + .insert(WorldName(new_world_name.clone())); + } // add this world to the world_container (or don't if it's already // there) - let weak_world = world_container.insert(world_name.clone(), height, min_y); + let weak_world = + world_container.insert(new_world_name.clone(), height, min_y); // set the partial_world to an empty world // (when we add chunks or entities those will be in the // world_container) @@ -212,7 +224,7 @@ fn handle_packets(ecs: &mut Ecs) { game_profile.uuid, Vec3::default(), azalea_registry::EntityKind::Player, - world_name, + new_world_name, ), metadata: PlayerMetadataBundle::default(), }; @@ -506,12 +518,12 @@ fn handle_packets(ecs: &mut Ecs) { ClientboundGamePacket::AddEntity(p) => { debug!("Got add entity packet {:?}", p); - let mut system_state: SystemState<(Commands, Query<&mut LocalPlayer>)> = + let mut system_state: SystemState<(Commands, Query<Option<&WorldName>>)> = SystemState::new(ecs); let (mut commands, mut query) = system_state.get_mut(ecs); - let local_player = query.get_mut(player_entity).unwrap(); + let world_name = query.get_mut(player_entity).unwrap(); - if let Some(world_name) = &local_player.world_name { + if let Some(WorldName(world_name)) = world_name { let bundle = p.as_entity_bundle(world_name.clone()); let mut entity_commands = commands.spawn(( MinecraftEntityId(p.id), @@ -570,12 +582,14 @@ fn handle_packets(ecs: &mut Ecs) { ClientboundGamePacket::AddPlayer(p) => { debug!("Got add player packet {:?}", p); - let mut system_state: SystemState<(Commands, Query<&mut LocalPlayer>)> = - SystemState::new(ecs); + let mut system_state: SystemState<( + Commands, + Query<(&mut LocalPlayer, Option<&WorldName>)>, + )> = SystemState::new(ecs); let (mut commands, mut query) = system_state.get_mut(ecs); - let local_player = query.get_mut(player_entity).unwrap(); + let (local_player, world_name) = query.get_mut(player_entity).unwrap(); - if let Some(world_name) = &local_player.world_name { + if let Some(WorldName(world_name)) = world_name { let bundle = p.as_player_bundle(world_name.clone()); let mut spawned = commands.spawn(( MinecraftEntityId(p.id), diff --git a/azalea-client/src/task_pool.rs b/azalea-client/src/task_pool.rs index 2a3afbbc..59f70487 100644 --- a/azalea-client/src/task_pool.rs +++ b/azalea-client/src/task_pool.rs @@ -30,7 +30,7 @@ impl Plugin for TaskPoolPlugin { } /// Helper for configuring and creating the default task pools. For end-users -/// who want full control, set up [`TaskPoolPlugin`](super::TaskPoolPlugin) +/// who want full control, set up [`TaskPoolPlugin`](TaskPoolPlugin) #[derive(Clone, Resource)] pub struct TaskPoolOptions { /// If the number of physical cores is less than min_total_threads, force |
