diff options
Diffstat (limited to 'azalea-client/src')
| -rw-r--r-- | azalea-client/src/chunks.rs | 34 | ||||
| -rw-r--r-- | azalea-client/src/client.rs | 14 | ||||
| -rw-r--r-- | azalea-client/src/events.rs | 2 | ||||
| -rw-r--r-- | azalea-client/src/lib.rs | 2 | ||||
| -rw-r--r-- | azalea-client/src/local_player.rs | 2 | ||||
| -rw-r--r-- | azalea-client/src/packet_handling/configuration.rs | 29 | ||||
| -rw-r--r-- | azalea-client/src/packet_handling/game.rs | 70 | ||||
| -rw-r--r-- | azalea-client/src/received_registries.rs | 28 |
8 files changed, 79 insertions, 102 deletions
diff --git a/azalea-client/src/chunks.rs b/azalea-client/src/chunks.rs index 80c350c8..4d2641f5 100644 --- a/azalea-client/src/chunks.rs +++ b/azalea-client/src/chunks.rs @@ -79,30 +79,22 @@ fn handle_receive_chunk_events( let local_player = query.get_mut(event.entity).unwrap(); - // OPTIMIZATION: if we already know about the chunk from the - // shared world (and not ourselves), then we don't need to - // parse it again. This is only used when we have a shared - // world, since we check that the chunk isn't currently owned - // by this client. - let shared_chunk = local_player.instance.read().chunks.get(&pos); - let this_client_has_chunk = local_player - .partial_instance - .read() - .chunks - .limited_get(&pos) - .is_some(); + let mut instance = local_player.instance.write(); + let mut partial_instance = local_player.partial_instance.write(); - let mut world = local_player.instance.write(); - let mut partial_world = local_player.partial_instance.write(); + // OPTIMIZATION: if we already know about the chunk from the shared world (and + // not ourselves), then we don't need to parse it again. This is only used when + // we have a shared world, since we check that the chunk isn't currently owned + // by this client. + let shared_chunk = instance.chunks.get(&pos); + let this_client_has_chunk = partial_instance.chunks.limited_get(&pos).is_some(); if !this_client_has_chunk { if let Some(shared_chunk) = shared_chunk { trace!("Skipping parsing chunk {pos:?} because we already know about it"); - partial_world.chunks.set_with_shared_reference( - &pos, - Some(shared_chunk.clone()), - &mut world.chunks, - ); + partial_instance + .chunks + .limited_set(&pos, Some(shared_chunk)); continue; } } @@ -112,11 +104,11 @@ fn handle_receive_chunk_events( let empty_nbt_compound = NbtCompound::default(); let heightmaps = heightmaps.unwrap_or(&empty_nbt_compound); - if let Err(e) = partial_world.chunks.replace_with_packet_data( + if let Err(e) = partial_instance.chunks.replace_with_packet_data( &pos, &mut Cursor::new(&event.packet.chunk_data.data), heightmaps, - &mut world.chunks, + &mut instance.chunks, ) { error!("Couldn't set chunk data: {e}"); } diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index 4f1c4b9e..787e6144 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -17,7 +17,7 @@ use crate::{ raw_connection::RawConnection, respawn::RespawnPlugin, task_pool::TaskPoolPlugin, - Account, PlayerInfo, ReceivedRegistries, + Account, PlayerInfo, }; use azalea_auth::{game_profile::GameProfile, sessionserver::ClientSessionServerError}; @@ -99,8 +99,6 @@ pub struct Client { pub profile: GameProfile, /// The entity for this client in the ECS. pub entity: Entity, - /// The world that this client is in. - pub world: Arc<RwLock<PartialInstance>>, /// The entity component system. You probably don't need to access this /// directly. Note that if you're using a shared world (i.e. a swarm), this @@ -147,7 +145,6 @@ impl Client { profile, // default our id to 0, it'll be set later entity, - world: Arc::new(RwLock::new(PartialInstance::default())), ecs, @@ -268,7 +265,6 @@ impl Client { read_conn, write_conn, ), - received_registries: ReceivedRegistries::default(), local_player_events: LocalPlayerEvents(tx), game_profile: GameProfileComponent(game_profile), client_information: crate::ClientInformation::default(), @@ -592,7 +588,6 @@ impl Client { #[derive(Bundle)] pub struct LocalPlayerBundle { pub raw_connection: RawConnection, - pub received_registries: ReceivedRegistries, pub local_player_events: LocalPlayerEvents, pub game_profile: GameProfileComponent, pub client_information: ClientInformation, @@ -604,7 +599,7 @@ pub struct LocalPlayerBundle { /// use [`LocalEntity`]. #[derive(Bundle)] pub struct JoinedClientBundle { - pub instance_holder: InstanceHolder, + // note that InstanceHolder isn't here because it's set slightly before we fully join the world pub physics_state: PhysicsState, pub inventory: InventoryComponent, pub tab_list: TabList, @@ -679,11 +674,12 @@ async fn run_schedule_loop( mut run_schedule_receiver: mpsc::UnboundedReceiver<()>, ) { loop { - // whenever we get an event from run_schedule_receiver, run the schedule - run_schedule_receiver.recv().await; // get rid of any queued events while let Ok(()) = run_schedule_receiver.try_recv() {} + // whenever we get an event from run_schedule_receiver, run the schedule + run_schedule_receiver.recv().await; + let mut ecs = ecs.lock(); ecs.run_schedule(outer_schedule_label); ecs.clear_trackers(); diff --git a/azalea-client/src/events.rs b/azalea-client/src/events.rs index e5e30b6a..c85f142e 100644 --- a/azalea-client/src/events.rs +++ b/azalea-client/src/events.rs @@ -163,7 +163,7 @@ fn packet_listener(query: Query<&LocalPlayerEvents>, mut events: EventReader<Pac for event in events.read() { let local_player_events = query .get(event.entity) - .expect("Non-local entities shouldn't be able to receive add player events"); + .expect("Non-local entities shouldn't be able to receive packet events"); local_player_events .send(Event::Packet(event.packet.clone())) .unwrap(); diff --git a/azalea-client/src/lib.rs b/azalea-client/src/lib.rs index bc5616e8..9d016bde 100644 --- a/azalea-client/src/lib.rs +++ b/azalea-client/src/lib.rs @@ -27,7 +27,6 @@ pub mod packet_handling; pub mod ping; mod player; pub mod raw_connection; -pub mod received_registries; pub mod respawn; pub mod task_pool; @@ -42,4 +41,3 @@ pub use movement::{ PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection, }; pub use player::PlayerInfo; -pub use received_registries::ReceivedRegistries; diff --git a/azalea-client/src/local_player.rs b/azalea-client/src/local_player.rs index db0a14f1..bebe841e 100644 --- a/azalea-client/src/local_player.rs +++ b/azalea-client/src/local_player.rs @@ -26,7 +26,7 @@ use crate::{ /// A component that keeps strong references to our [`PartialInstance`] and /// [`Instance`] for local players. -#[derive(Component)] +#[derive(Component, Clone)] pub struct InstanceHolder { /// The partial instance is the world this client currently has loaded. It /// has a limited render distance. diff --git a/azalea-client/src/packet_handling/configuration.rs b/azalea-client/src/packet_handling/configuration.rs index f35e25b2..ab0ce089 100644 --- a/azalea-client/src/packet_handling/configuration.rs +++ b/azalea-client/src/packet_handling/configuration.rs @@ -20,7 +20,6 @@ use crate::disconnect::DisconnectEvent; use crate::local_player::Hunger; use crate::packet_handling::game::KeepAliveEvent; use crate::raw_connection::RawConnection; -use crate::ReceivedRegistries; #[derive(Event, Debug, Clone)] pub struct PacketEvent { @@ -78,19 +77,21 @@ pub fn process_packet_events(ecs: &mut World) { for (player_entity, packet) in events_owned { match packet { ClientboundConfigurationPacket::RegistryData(p) => { - let mut system_state: SystemState<Query<&mut ReceivedRegistries>> = - SystemState::new(ecs); - let mut query = system_state.get_mut(ecs); - let mut received_registries = query.get_mut(player_entity).unwrap(); + let mut instance = Instance::default(); - let new_received_registries = p.registry_holder.registries; // override the old registries with the new ones // but if a registry wasn't sent, keep the old one - for (registry_name, registry) in new_received_registries { - received_registries - .registries - .insert(registry_name, registry); + for (registry_name, registry) in p.registry_holder.map { + instance.registries.map.insert(registry_name, registry); } + + let instance_holder = crate::local_player::InstanceHolder::new( + player_entity, + // default to an empty world, it'll be set correctly later when we + // get the login packet + Arc::new(RwLock::new(instance)), + ); + ecs.entity_mut(player_entity).insert(instance_holder); } ClientboundConfigurationPacket::CustomPayload(p) => { @@ -113,13 +114,6 @@ pub fn process_packet_events(ecs: &mut World) { let mut query = system_state.get_mut(ecs); let mut raw_connection = query.get_mut(player_entity).unwrap(); - let instance_holder = crate::local_player::InstanceHolder::new( - player_entity, - // default to an empty world, it'll be set correctly later when we - // get the login packet - Arc::new(RwLock::new(Instance::default())), - ); - raw_connection .write_packet(ServerboundFinishConfigurationPacket {}.get()) .expect( @@ -131,7 +125,6 @@ pub fn process_packet_events(ecs: &mut World) { ecs.entity_mut(player_entity) .remove::<InConfigurationState>() .insert(crate::JoinedClientBundle { - instance_holder, physics_state: crate::PhysicsState::default(), inventory: crate::inventory::InventoryComponent::default(), tab_list: crate::local_player::TabList::default(), diff --git a/azalea-client/src/packet_handling/game.rs b/azalea-client/src/packet_handling/game.rs index 71726142..9f7c5e69 100644 --- a/azalea-client/src/packet_handling/game.rs +++ b/azalea-client/src/packet_handling/game.rs @@ -45,7 +45,7 @@ use crate::{ }, movement::{KnockbackEvent, KnockbackType}, raw_connection::RawConnection, - ClientInformation, PlayerInfo, ReceivedRegistries, + ClientInformation, PlayerInfo, }; /// An event that's sent when we receive a packet. @@ -174,16 +174,18 @@ pub fn send_packet_events( } pub fn process_packet_events(ecs: &mut World) { - let mut events_owned = Vec::new(); - let mut system_state: SystemState<EventReader<PacketEvent>> = SystemState::new(ecs); - let mut events = system_state.get_mut(ecs); - for PacketEvent { - entity: player_entity, - packet, - } in events.read() + let mut events_owned = Vec::<(Entity, Arc<ClientboundGamePacket>)>::new(); { - // we do this so `ecs` isn't borrowed for the whole loop - events_owned.push((*player_entity, packet.clone())); + let mut system_state = SystemState::<EventReader<PacketEvent>>::new(ecs); + let mut events = system_state.get_mut(ecs); + for PacketEvent { + entity: player_entity, + packet, + } in events.read() + { + // we do this so `ecs` isn't borrowed for the whole loop + events_owned.push((*player_entity, packet.clone())); + } } for (player_entity, packet) in events_owned { let packet_clone = packet.clone(); @@ -198,7 +200,6 @@ pub fn process_packet_events(ecs: &mut World) { Query<( &GameProfileComponent, &ClientInformation, - &ReceivedRegistries, Option<&mut InstanceName>, Option<&mut LoadedBy>, &mut EntityIdIndex, @@ -220,7 +221,6 @@ pub fn process_packet_events(ecs: &mut World) { let ( game_profile, client_information, - received_registries, instance_name, loaded_by, mut entity_id_index, @@ -238,7 +238,9 @@ pub fn process_packet_events(ecs: &mut World) { .insert(InstanceName(new_instance_name.clone())); } - let Some(dimension_type) = received_registries.dimension_type() else { + let Some(dimension_type) = + instance_holder.instance.read().registries.dimension_type() + else { error!("Server didn't send dimension type registry, can't log in"); continue; }; @@ -276,6 +278,17 @@ pub fn process_packet_events(ecs: &mut World) { // in a shared instance Some(player_entity), ); + { + let new_registries = &mut weak_instance.write().registries; + // add the registries from this instance to the weak instance + for (registry_name, registry) in + &instance_holder.instance.read().registries.map + { + new_registries + .map + .insert(registry_name.clone(), registry.clone()); + } + } instance_holder.instance = weak_instance; let player_bundle = PlayerBundle { @@ -295,8 +308,6 @@ pub fn process_packet_events(ecs: &mut World) { current: p.common.game_type, previous: p.common.previous_game_type.into(), }, - // this gets overwritten later by the SetHealth packet - received_registries.clone(), player_bundle, )); @@ -583,10 +594,12 @@ pub fn process_packet_events(ecs: &mut World) { let mut system_state: SystemState<Query<&mut InstanceHolder>> = SystemState::new(ecs); let mut query = system_state.get_mut(ecs); - let local_player = query.get_mut(player_entity).unwrap(); - let mut partial_world = local_player.partial_instance.write(); + let instance_holder = query.get_mut(player_entity).unwrap(); + let mut partial_world = instance_holder.partial_instance.write(); - partial_world.chunks.view_center = ChunkPos::new(p.x, p.z); + partial_world + .chunks + .update_view_center(ChunkPos::new(p.x, p.z)); } ClientboundGamePacket::ChunksBiomes(_) => {} ClientboundGamePacket::LightUpdate(_p) => { @@ -1167,7 +1180,18 @@ pub fn process_packet_events(ecs: &mut World) { system_state.apply(ecs); } - ClientboundGamePacket::ForgetLevelChunk(_) => {} + ClientboundGamePacket::ForgetLevelChunk(p) => { + debug!("Got forget level chunk packet {p:?}"); + + let mut system_state: SystemState<Query<&mut InstanceHolder>> = + SystemState::new(ecs); + let mut query = system_state.get_mut(ecs); + let local_player = query.get_mut(player_entity).unwrap(); + + let mut partial_instance = local_player.partial_instance.write(); + + partial_instance.chunks.limited_set(&p.pos, None); + } ClientboundGamePacket::HorseScreenOpen(_) => {} ClientboundGamePacket::MapItemData(_) => {} ClientboundGamePacket::MerchantOffers(_) => {} @@ -1255,20 +1279,21 @@ pub fn process_packet_events(ecs: &mut World) { &mut InstanceHolder, &GameProfileComponent, &ClientInformation, - &ReceivedRegistries, )>, EventWriter<InstanceLoadedEvent>, ResMut<InstanceContainer>, )> = SystemState::new(ecs); let (mut commands, mut query, mut instance_loaded_events, mut instance_container) = system_state.get_mut(ecs); - let (mut instance_holder, game_profile, client_information, received_registries) = + let (mut instance_holder, game_profile, client_information) = query.get_mut(player_entity).unwrap(); { let new_instance_name = p.common.dimension.clone(); - let Some(dimension_type) = received_registries.dimension_type() else { + let Some(dimension_type) = + instance_holder.instance.read().registries.dimension_type() + else { error!("Server didn't send dimension type registry, can't log in"); continue; }; @@ -1298,6 +1323,7 @@ pub fn process_packet_events(ecs: &mut World) { // set the partial_world to an empty world // (when we add chunks or entities those will be in the // instance_container) + *instance_holder.partial_instance.write() = PartialInstance::new( azalea_world::chunk_storage::calculate_chunk_storage_range( client_information.view_distance.into(), diff --git a/azalea-client/src/received_registries.rs b/azalea-client/src/received_registries.rs deleted file mode 100644 index f959a590..00000000 --- a/azalea-client/src/received_registries.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::collections::HashMap; - -use azalea_core::resource_location::ResourceLocation; -use azalea_nbt::Nbt; -use azalea_protocol::packets::configuration::clientbound_registry_data_packet::registry::{ - DimensionTypeElement, RegistryType, -}; -use bevy_ecs::prelude::*; -use serde::de::DeserializeOwned; - -/// The registries that were sent to us during the configuration state. -#[derive(Default, Component, Clone)] -pub struct ReceivedRegistries { - pub registries: HashMap<ResourceLocation, Nbt>, -} - -impl ReceivedRegistries { - fn get<T: DeserializeOwned>(&self, name: &ResourceLocation) -> Option<T> { - let nbt = self.registries.get(name)?; - serde_json::from_value(serde_json::to_value(nbt).ok()?).ok() - } - - /// Get the dimension type registry, or `None` if it doesn't exist. You - /// should do some type of error handling if this returns `None`. - pub fn dimension_type(&self) -> Option<RegistryType<DimensionTypeElement>> { - self.get(&ResourceLocation::new("minecraft:dimension_type")) - } -} |
