aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-client/src')
-rw-r--r--azalea-client/src/chunks.rs34
-rw-r--r--azalea-client/src/client.rs14
-rw-r--r--azalea-client/src/events.rs2
-rw-r--r--azalea-client/src/lib.rs2
-rw-r--r--azalea-client/src/local_player.rs2
-rw-r--r--azalea-client/src/packet_handling/configuration.rs29
-rw-r--r--azalea-client/src/packet_handling/game.rs70
-rw-r--r--azalea-client/src/received_registries.rs28
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"))
- }
-}