make ClientInformation and TabList their own components

This commit is contained in:
mat 2023-03-08 19:26:40 +00:00
parent 5ce830ae6c
commit f28efd5637
3 changed files with 40 additions and 49 deletions

View file

@ -51,6 +51,7 @@ use bevy_ecs::{
}; };
use bevy_log::LogPlugin; use bevy_log::LogPlugin;
use bevy_time::{prelude::FixedTime, TimePlugin}; use bevy_time::{prelude::FixedTime, TimePlugin};
use derive_more::{Deref, DerefMut};
use log::{debug, error}; use log::{debug, error};
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc, time::Duration}; use std::{collections::HashMap, fmt::Debug, io, net::SocketAddr, sync::Arc, time::Duration};
@ -58,8 +59,6 @@ use thiserror::Error;
use tokio::{sync::mpsc, time}; use tokio::{sync::mpsc, time};
use uuid::Uuid; 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`]. /// Things that a player in the world will want to know are in [`LocalPlayer`].
/// ///
@ -93,6 +92,16 @@ pub struct Client {
pub run_schedule_sender: mpsc::UnboundedSender<()>, pub run_schedule_sender: mpsc::UnboundedSender<()>,
} }
/// A component that contains some of the "settings" for this client that are
/// sent to the server, such as render distance.
#[derive(Component, Clone, Debug, Deref, DerefMut, Default, Eq, PartialEq)]
pub struct ClientInformation(ServerboundClientInformationPacket);
/// A component that contains a map of player UUIDs to their information in the
/// tab list
#[derive(Component, Clone, Debug, Deref, DerefMut, Default)]
pub struct TabList(HashMap<Uuid, PlayerInfo>);
/// An error that happened while joining the server. /// An error that happened while joining the server.
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum JoinError { pub enum JoinError {
@ -238,6 +247,8 @@ impl Client {
game_profile: GameProfileComponent(game_profile), game_profile: GameProfileComponent(game_profile),
physics_state: PhysicsState::default(), physics_state: PhysicsState::default(),
local_player_events: LocalPlayerEvents(tx), local_player_events: LocalPlayerEvents(tx),
client_information: ClientInformation::default(),
tab_list: TabList::default(),
_local: Local, _local: Local,
}); });
@ -451,32 +462,21 @@ impl Client {
client_information: ServerboundClientInformationPacket, client_information: ServerboundClientInformationPacket,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
{ {
self.local_player_mut(&mut self.ecs.lock()) let mut ecs = self.ecs.lock();
.client_information = client_information; let mut client_information_mut = self.query::<&mut ClientInformation>(&mut ecs);
**client_information_mut = client_information.clone();
} }
if self.logged_in() { if self.logged_in() {
let client_information_packet = self
.local_player(&mut self.ecs.lock())
.client_information
.clone()
.get();
log::debug!( log::debug!(
"Sending client information (already logged in): {:?}", "Sending client information (already logged in): {:?}",
client_information_packet client_information
); );
self.write_packet(client_information_packet); self.write_packet(client_information.get());
} }
Ok(()) Ok(())
} }
/// Get a HashMap of all the players in the tab list.
///
/// Internally, this fetches the `players` field in [`LocalPlayer`].
pub fn players(&mut self) -> HashMap<Uuid, PlayerInfo> {
self.local_player(&mut self.ecs.lock()).players.clone()
}
} }
/// A bundle for the components that are present on a local player that received /// A bundle for the components that are present on a local player that received
@ -488,6 +488,8 @@ pub struct JoinedClientBundle {
pub game_profile: GameProfileComponent, pub game_profile: GameProfileComponent,
pub physics_state: PhysicsState, pub physics_state: PhysicsState,
pub local_player_events: LocalPlayerEvents, pub local_player_events: LocalPlayerEvents,
pub client_information: ClientInformation,
pub tab_list: TabList,
pub _local: Local, pub _local: Local,
} }

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, io, sync::Arc}; use std::{io, sync::Arc};
use azalea_auth::game_profile::GameProfile; use azalea_auth::game_profile::GameProfile;
use azalea_core::ChunkPos; use azalea_core::ChunkPos;
@ -14,11 +14,10 @@ use derive_more::{Deref, DerefMut};
use parking_lot::RwLock; use parking_lot::RwLock;
use thiserror::Error; use thiserror::Error;
use tokio::{sync::mpsc, task::JoinHandle}; use tokio::{sync::mpsc, task::JoinHandle};
use uuid::Uuid;
use crate::{ use crate::{
events::{Event, LocalPlayerEvents}, events::{Event, LocalPlayerEvents},
ClientInformation, PlayerInfo, WalkDirection, ClientInformation, WalkDirection,
}; };
/// This is a component for our local player entities that are probably in a /// This is a component for our local player entities that are probably in a
@ -33,11 +32,7 @@ use crate::{
#[derive(Component)] #[derive(Component)]
pub struct LocalPlayer { pub struct LocalPlayer {
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
pub players: HashMap<Uuid, PlayerInfo>,
/// The partial world is the world this client currently has loaded. It has /// The partial world is the world this client currently has loaded. It has
/// a limited render distance. /// a limited render distance.
pub partial_world: Arc<RwLock<PartialWorld>>, pub partial_world: Arc<RwLock<PartialWorld>>,
@ -96,9 +91,6 @@ impl LocalPlayer {
LocalPlayer { LocalPlayer {
packet_writer, packet_writer,
client_information: ClientInformation::default(),
players: HashMap::new(),
world, world,
partial_world: Arc::new(RwLock::new(PartialWorld::new( partial_world: Arc::new(RwLock::new(PartialWorld::new(
client_information.view_distance.into(), client_information.view_distance.into(),

View file

@ -37,6 +37,7 @@ use tokio::sync::mpsc;
use crate::{ use crate::{
chat::{ChatPacket, ChatReceivedEvent}, chat::{ChatPacket, ChatReceivedEvent},
client::TabList,
disconnect::DisconnectEvent, disconnect::DisconnectEvent,
local_player::{GameProfileComponent, LocalPlayer}, local_player::{GameProfileComponent, LocalPlayer},
ClientInformation, PlayerInfo, ClientInformation, PlayerInfo,
@ -189,11 +190,12 @@ fn process_packet_events(ecs: &mut World) {
&mut LocalPlayer, &mut LocalPlayer,
Option<&mut WorldName>, Option<&mut WorldName>,
&GameProfileComponent, &GameProfileComponent,
&ClientInformation,
)>, )>,
ResMut<WorldContainer>, ResMut<WorldContainer>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut commands, mut query, mut world_container) = system_state.get_mut(ecs); let (mut commands, mut query, mut world_container) = system_state.get_mut(ecs);
let (mut local_player, world_name, game_profile) = let (mut local_player, world_name, game_profile, client_information) =
query.get_mut(player_entity).unwrap(); query.get_mut(player_entity).unwrap();
{ {
@ -267,7 +269,7 @@ fn process_packet_events(ecs: &mut World) {
// world_container) // world_container)
*local_player.partial_world.write() = PartialWorld::new( *local_player.partial_world.write() = PartialWorld::new(
local_player.client_information.view_distance.into(), client_information.view_distance.into(),
// this argument makes it so other clients don't update this // this argument makes it so other clients don't update this
// player entity // player entity
// in a shared world // in a shared world
@ -291,13 +293,12 @@ fn process_packet_events(ecs: &mut World) {
} }
// send the client information that we have set // send the client information that we have set
let client_information_packet: ClientInformation =
local_player.client_information.clone();
log::debug!( log::debug!(
"Sending client information because login: {:?}", "Sending client information because login: {:?}",
client_information_packet client_information
); );
local_player.write_packet(client_information_packet.get()); let client_information: ClientInformation = client_information.clone();
local_player.write_packet((*client_information).clone().get());
// brand // brand
local_player.write_packet( local_player.write_packet(
@ -444,13 +445,13 @@ fn process_packet_events(ecs: &mut World) {
debug!("Got player info packet {:?}", p); debug!("Got player info packet {:?}", p);
let mut system_state: SystemState<( let mut system_state: SystemState<(
Query<&mut LocalPlayer>, Query<&mut TabList>,
EventWriter<AddPlayerEvent>, EventWriter<AddPlayerEvent>,
EventWriter<UpdatePlayerEvent>, EventWriter<UpdatePlayerEvent>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut query, mut add_player_events, mut update_player_events) = let (mut query, mut add_player_events, mut update_player_events) =
system_state.get_mut(ecs); system_state.get_mut(ecs);
let mut local_player = query.get_mut(player_entity).unwrap(); let mut tab_list = query.get_mut(player_entity).unwrap();
for updated_info in &p.entries { for updated_info in &p.entries {
// add the new player maybe // add the new player maybe
@ -462,16 +463,12 @@ fn process_packet_events(ecs: &mut World) {
latency: updated_info.latency, latency: updated_info.latency,
display_name: updated_info.display_name.clone(), display_name: updated_info.display_name.clone(),
}; };
local_player tab_list.insert(updated_info.profile.uuid, info.clone());
.players
.insert(updated_info.profile.uuid, info.clone());
add_player_events.send(AddPlayerEvent { add_player_events.send(AddPlayerEvent {
entity: player_entity, entity: player_entity,
info: info.clone(), info: info.clone(),
}); });
} else if let Some(info) = } else if let Some(info) = tab_list.get_mut(&updated_info.profile.uuid) {
local_player.players.get_mut(&updated_info.profile.uuid)
{
// `else if` because the block for add_player above // `else if` because the block for add_player above
// already sets all the fields // already sets all the fields
if p.actions.update_game_mode { if p.actions.update_game_mode {
@ -497,14 +494,14 @@ fn process_packet_events(ecs: &mut World) {
} }
ClientboundGamePacket::PlayerInfoRemove(p) => { ClientboundGamePacket::PlayerInfoRemove(p) => {
let mut system_state: SystemState<( let mut system_state: SystemState<(
Query<&mut LocalPlayer>, Query<&mut TabList>,
EventWriter<RemovePlayerEvent>, EventWriter<RemovePlayerEvent>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut query, mut remove_player_events) = system_state.get_mut(ecs); let (mut query, mut remove_player_events) = system_state.get_mut(ecs);
let mut local_player = query.get_mut(player_entity).unwrap(); let mut tab_list = query.get_mut(player_entity).unwrap();
for uuid in &p.profile_ids { for uuid in &p.profile_ids {
if let Some(info) = local_player.players.remove(uuid) { if let Some(info) = tab_list.remove(uuid) {
remove_player_events.send(RemovePlayerEvent { remove_player_events.send(RemovePlayerEvent {
entity: player_entity, entity: player_entity,
info, info,
@ -642,10 +639,10 @@ fn process_packet_events(ecs: &mut World) {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
let mut system_state: SystemState<( let mut system_state: SystemState<(
Commands, Commands,
Query<(&mut LocalPlayer, Option<&WorldName>)>, Query<(&TabList, Option<&WorldName>)>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut commands, mut query) = system_state.get_mut(ecs); let (mut commands, mut query) = system_state.get_mut(ecs);
let (local_player, world_name) = query.get_mut(player_entity).unwrap(); let (tab_list, world_name) = query.get_mut(player_entity).unwrap();
if let Some(WorldName(world_name)) = world_name { if let Some(WorldName(world_name)) = world_name {
let bundle = p.as_player_bundle(world_name.clone()); let bundle = p.as_player_bundle(world_name.clone());
@ -655,7 +652,7 @@ fn process_packet_events(ecs: &mut World) {
bundle, bundle,
)); ));
if let Some(player_info) = local_player.players.get(&p.uuid) { if let Some(player_info) = tab_list.get(&p.uuid) {
spawned.insert(GameProfileComponent(player_info.profile.clone())); spawned.insert(GameProfileComponent(player_info.profile.clone()));
} }
} else { } else {