aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaeders <38367311+nebula161@users.noreply.github.com>2026-01-23 23:04:54 -0500
committerGitHub <noreply@github.com>2026-01-23 22:04:54 -0600
commitd665924eb2163fc8afe256e502a39e72ad0e4a42 (patch)
tree5050630905b9802ef254e4352ac6d5c23116cacc
parent4ab3609244d4eb87c3087f69f48083d9413a1cb3 (diff)
downloadazalea-drasl-d665924eb2163fc8afe256e502a39e72ad0e4a42.tar.xz
Implement SetExperience (#307)
-rw-r--r--azalea-client/src/client.rs4
-rw-r--r--azalea-client/src/local_player.rs23
-rw-r--r--azalea-client/src/plugins/packet/game/events.rs2
-rw-r--r--azalea-client/src/plugins/packet/game/mod.rs19
-rw-r--r--azalea/src/client_impl/mod.rs9
5 files changed, 46 insertions, 11 deletions
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs
index 90b1264c..b9a4e824 100644
--- a/azalea-client/src/client.rs
+++ b/azalea-client/src/client.rs
@@ -29,12 +29,11 @@ use crate::{
connection::RawConnection,
cookies::ServerCookies,
interact::BlockStatePredictionHandler,
- local_player::{Hunger, PermissionLevel, TabList, WorldHolder},
+ local_player::{Experience, Hunger, PermissionLevel, TabList, WorldHolder},
mining,
movement::LastSentLookDirection,
player::retroactively_add_game_profile_component,
};
-
/// A bundle of components that's inserted right when we switch to the `login`
/// state and stay present on our clients until we disconnect.
///
@@ -67,6 +66,7 @@ pub struct JoinedClientBundle {
pub permission_level: PermissionLevel,
pub chunk_batch_info: ChunkBatchInfo,
pub hunger: Hunger,
+ pub experience: Experience,
pub cookies: ServerCookies,
pub entity_id_index: EntityIdIndex,
diff --git a/azalea-client/src/local_player.rs b/azalea-client/src/local_player.rs
index 444b2fcc..1a2f059f 100644
--- a/azalea-client/src/local_player.rs
+++ b/azalea-client/src/local_player.rs
@@ -7,7 +7,7 @@ use derive_more::{Deref, DerefMut};
use parking_lot::RwLock;
use uuid::Uuid;
-use crate::{ClientInformation, player::PlayerInfo};
+use crate::{player::PlayerInfo, ClientInformation};
/// A component that keeps strong references to our [`PartialWorld`] and
/// [`World`] for local players.
@@ -104,6 +104,27 @@ impl Hunger {
}
}
+/// The player's experience state.
+#[derive(Clone, Component, Debug)]
+pub struct Experience {
+ /// Progress towards the next level, in the range 0.0..1.0.
+ pub progress: f32,
+ /// The current experience level. You'll mostly be using this.
+ pub level: u32,
+ /// Total experience points accumulated.
+ pub total: u32,
+}
+
+impl Default for Experience {
+ fn default() -> Self {
+ Experience {
+ progress: 0.0,
+ level: 0,
+ total: 0,
+ }
+ }
+}
+
impl WorldHolder {
/// Create a new `WorldHolder` for the given entity.
///
diff --git a/azalea-client/src/plugins/packet/game/events.rs b/azalea-client/src/plugins/packet/game/events.rs
index bc070ec8..4a919382 100644
--- a/azalea-client/src/plugins/packet/game/events.rs
+++ b/azalea-client/src/plugins/packet/game/events.rs
@@ -2,8 +2,8 @@ use std::sync::{Arc, Weak};
use azalea_chat::FormattedText;
use azalea_protocol::packets::{
- Packet,
game::{ClientboundGamePacket, ClientboundPlayerCombatKill, ServerboundGamePacket},
+ Packet,
};
use azalea_world::{World, WorldName};
use bevy_ecs::prelude::*;
diff --git a/azalea-client/src/plugins/packet/game/mod.rs b/azalea-client/src/plugins/packet/game/mod.rs
index 6489c899..1fdceddf 100644
--- a/azalea-client/src/plugins/packet/game/mod.rs
+++ b/azalea-client/src/plugins/packet/game/mod.rs
@@ -8,15 +8,15 @@ use azalea_core::{
position::{ChunkPos, Vec3},
};
use azalea_entity::{
- ActiveEffects, Dead, EntityBundle, EntityKindComponent, HasClientLoaded, LoadedBy, LocalEntity,
- LookDirection, Physics, PlayerAbilities, Position, RelativeEntityUpdate,
indexing::{EntityIdIndex, EntityUuidIndex},
inventory::Inventory,
- metadata::{Health, apply_metadata},
+ metadata::{apply_metadata, Health},
+ ActiveEffects, Dead, EntityBundle, EntityKindComponent, HasClientLoaded, LoadedBy, LocalEntity,
+ LookDirection, Physics, PlayerAbilities, Position, RelativeEntityUpdate,
};
use azalea_protocol::{
common::movements::MoveFlags,
- packets::{ConnectionProtocol, game::*},
+ packets::{game::*, ConnectionProtocol},
};
use azalea_registry::builtin::EntityKind;
use azalea_world::{PartialWorld, WorldName, Worlds};
@@ -25,7 +25,6 @@ pub use events::*;
use tracing::{debug, error, trace, warn};
use crate::{
- ClientInformation,
block_update::QueuedServerBlockUpdates,
chat::{ChatPacket, ChatReceivedEvent},
chunks,
@@ -34,11 +33,12 @@ use crate::{
disconnect::DisconnectEvent,
interact::BlockStatePredictionHandler,
inventory::{ClientsideCloseContainerEvent, MenuOpenedEvent, SetContainerContentEvent},
- local_player::{Hunger, LocalGameMode, TabList, WorldHolder},
+ local_player::{Experience, Hunger, LocalGameMode, TabList, WorldHolder},
movement::{KnockbackData, KnockbackEvent},
packet::{as_system, declare_packet_handlers},
player::{GameProfileComponent, PlayerInfo},
tick_counter::TicksConnected,
+ ClientInformation,
};
pub fn process_packet(ecs: &mut World, player: Entity, packet: &ClientboundGamePacket) {
@@ -781,6 +781,13 @@ impl GamePacketHandler<'_> {
pub fn set_experience(&mut self, p: &ClientboundSetExperience) {
debug!("Got set experience packet {p:?}");
+
+ as_system::<Query<&mut Experience>>(self.ecs, |mut query| {
+ let mut experience = query.get_mut(self.player).unwrap();
+ experience.progress = p.experience_progress;
+ experience.level = p.experience_level;
+ experience.total = p.total_experience;
+ });
}
pub fn teleport_entity(&mut self, p: &ClientboundTeleportEntity) {
diff --git a/azalea/src/client_impl/mod.rs b/azalea/src/client_impl/mod.rs
index 343b8aef..6725174c 100644
--- a/azalea/src/client_impl/mod.rs
+++ b/azalea/src/client_impl/mod.rs
@@ -7,7 +7,7 @@ use azalea_client::{
connection::RawConnection,
disconnect::DisconnectEvent,
join::{ConnectOpts, StartJoinServerEvent},
- local_player::{Hunger, TabList, WorldHolder},
+ local_player::{Experience, Hunger, TabList, WorldHolder},
packet::game::SendGamePacketEvent,
player::{GameProfileComponent, PlayerInfo},
start_ecs_runner,
@@ -329,6 +329,13 @@ impl Client {
self.component::<Hunger>().to_owned()
}
+ /// Get the experience of this client.
+ ///
+ /// This is a shortcut for `self.component::<Experience>().to_owned()`.
+ pub fn experience(&self) -> Experience {
+ self.component::<Experience>().to_owned()
+ }
+
/// Get the username of this client.
///
/// This is a shortcut for