aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md175
-rw-r--r--azalea-client/src/plugins/inventory.rs151
-rw-r--r--azalea-client/src/plugins/packet/game/mod.rs47
3 files changed, 193 insertions, 180 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c439b15b..88b6b056 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,107 +10,108 @@ is breaking anyways, semantic versioning is not followed.
### Added
-- Sneaking/crouching.
-- `HitResult` now contains the entity that's being looked at.
-- A `QueuedServerBlockUpdates` component that keeps track of block updates per `Update`.
-- Local clients now have a `TicksConnected` component. (@Kumpelinus)
-- There is now a `azalea_inventory::default_components::get_default_component` function to get the default value of a component for a registry item.
-- `ItemStack` now has a `get_component` function that supports default components.
-- `Client::nearest_entity_by`.
-- `BitSet::len`, `BitSet::get`, `BitSet::iter_ones`.
-- All packets are now `PartialEq`.
+- Sneaking/crouching.
+- `HitResult` now contains the entity that's being looked at.
+- A `QueuedServerBlockUpdates` component that keeps track of block updates per `Update`.
+- Local clients now have a `TicksConnected` component. (@Kumpelinus)
+- There is now a `azalea_inventory::default_components::get_default_component` function to get the default value of a component for a registry item.
+- `ItemStack` now has a `get_component` function that supports default components.
+- `Client::nearest_entity_by`.
+- `BitSet::len`, `BitSet::get`, `BitSet::iter_ones`.
+- All packets are now `PartialEq`.
### Changed
-- Update to Minecraft 1.21.8.
-- Renamed `azalea_entity::EntityKind` to `EntityKindComponent` to disambiguate with `azalea_registry::EntityKind`.
-- Moved functions and types related to hit results from `azalea::interact` to `azalea::interact::pick`.
-- `Client::attack` now takes `Entity` instead of `MinecraftEntityId`.
-- `ItemStackData::components` was renamed to `component_patch`.
-- The fields in `LookDirection` have been replaced with getters.
-- Renamed `Client::entity_by` to `any_entity_by`, and `Client::entities_by` to `nearest_entities_by`.
-- `EyeHeight` was moved into `EntityDimensions`, and `EntityDimensions` is now its own component.
-- Replaced `start_goto_without_mining` with `start_goto_with_opts`.
-- Rename `send_chat_packet` / `send_command_packet` to `write_chat_packet` / `write_command_packet` (for consistency with `write_packet`).
-- Split `ClientInformation` handling out of `BrandPlugin` to `ClientInformationPlugin`.
-- `ClientBuilder::start` and `SwarmBuilder::start` now return a `Result<AppExit>` instead of `Result<!>`.
+- Update to Minecraft 1.21.8.
+- Renamed `azalea_entity::EntityKind` to `EntityKindComponent` to disambiguate with `azalea_registry::EntityKind`.
+- Moved functions and types related to hit results from `azalea::interact` to `azalea::interact::pick`.
+- `Client::attack` now takes `Entity` instead of `MinecraftEntityId`.
+- `ItemStackData::components` was renamed to `component_patch`.
+- The fields in `LookDirection` have been replaced with getters.
+- Renamed `Client::entity_by` to `any_entity_by`, and `Client::entities_by` to `nearest_entities_by`.
+- `EyeHeight` was moved into `EntityDimensions`, and `EntityDimensions` is now its own component.
+- Replaced `start_goto_without_mining` with `start_goto_with_opts`.
+- Rename `send_chat_packet` / `send_command_packet` to `write_chat_packet` / `write_command_packet` (for consistency with `write_packet`).
+- Split `ClientInformation` handling out of `BrandPlugin` to `ClientInformationPlugin`.
+- `ClientBuilder::start` and `SwarmBuilder::start` now return a `Result<AppExit>` instead of `Result<!>`.
+- `ClientsideCloseContainerEvent`, `MenuOpenedEvent`, and `CloseContainerEvent` are now triggers instead of events.
### Fixed
-- Fix packet order for loading (`PlayerLoaded`/`MovePlayerPos`) and sprinting (`PlayerInput`/`PlayerCommand`).
-- Clients no longer send invalid look directions if the server teleports us with one.
-- Look directions are now rounded based on the default Minecraft sensitivity, which may help avoid flagging anticheats.
-- Movement code was updated with the changes from 1.21.5, so it no longer flags Grim.
-- Clients can no longer sprint if their food level is too low.
-- `azalea-chat` now handles arrays of integers in the `with` field. (@qwqawawow)
-- `azalea-chat` no longer incorrectly persists styles of components in the "extra" field.
-- Inventories now use the correct max stack sizes.
-- Clients now send the correct data component checksums when interacting with items.
-- Fix parsing some metadata fields of Display entities.
-- Mining blocks in creative mode now works. (@qwqawawow)
-- Improved matchers on the `ChatPacket` functions to work on more servers. (@ShayBox)
-- Bevy's `AppExit` Event is now handled by Azalea's ECS runner.
+- Fix packet order for loading (`PlayerLoaded`/`MovePlayerPos`) and sprinting (`PlayerInput`/`PlayerCommand`).
+- Clients no longer send invalid look directions if the server teleports us with one.
+- Look directions are now rounded based on the default Minecraft sensitivity, which may help avoid flagging anticheats.
+- Movement code was updated with the changes from 1.21.5, so it no longer flags Grim.
+- Clients can no longer sprint if their food level is too low.
+- `azalea-chat` now handles arrays of integers in the `with` field. (@qwqawawow)
+- `azalea-chat` no longer incorrectly persists styles of components in the "extra" field.
+- Inventories now use the correct max stack sizes.
+- Clients now send the correct data component checksums when interacting with items.
+- Fix parsing some metadata fields of Display entities.
+- Mining blocks in creative mode now works. (@qwqawawow)
+- Improved matchers on the `ChatPacket` functions to work on more servers. (@ShayBox)
+- Bevy's `AppExit` Event is now handled by Azalea's ECS runner.
## [0.13.0+mc1.21.5] - 2025-06-15
### Added
-- This changelog. To see changes before this update, look at the git commits.
-- azalea and azalea-client now have a `packet-event` feature, which can be disabled for efficiency if you're not using `Event::Packet`.
-- `StartJoinServerEvent` can now be used to join servers exclusively from the ECS without a Tokio runtime.
-- Add `FormattedText::to_html` and `FormattedText::to_custom_format`. (@Kumpelinus)
-- Non-standard legacy hex colors like `§#ff0000` are now supported in azalea-chat.
-- Chat signing.
-- Add auto-reconnecting which is enabled by default.
-- `ClientBuilder` and `SwarmBuilder` are now Send.
-- Add `Client::start_use_item`.
-- The pathfinder no longer avoids slabs, stairs, and dirt path blocks.
-- The pathfinder now immediately recalculates if blocks are placed in its path.
-- Bots that use custom pathfinder moves can now keep arbitrary persistent state by using the `CustomPathfinderState` component and `PathfinderCtx::custom_state`.
-- The reach distance for the pathfinder `ReachBlockPosGoal` is now configurable. (@x-osc)
-- There is now a `retry_on_no_path` option in `GotoEvent` that can be set to false to make the pathfinder give up if no path could be found.
-- azalea-brigadier now supports suggestions, command contexts, result consumers, and returning errors with `ArgumentBuilder::executes_result`.
-- Proper support for getting biomes at coordinates.
-- Add a new `Client::entities_by` which sorts entities that match a criteria by their distance to the client.
-- New client event `Event::ReceiveChunk`.
-- Several new functions for interacting with inventories (`Client::get_inventory`, `get_held_item`, `ContainerHandleRef::left_click`, `shift_click`, `right_click`, `slots`).
-- Add `Client::mine_with_auto_tool`.
-- Add `Client::set_selected_hotbar_slot` and `Client::selected_hotbar_slot`.
-- Add `Client::attack_cooldown_remaining_ticks` to complement `has_attack_cooldown`.
-- Add `BlockPos::length`, `distance_to`, and `center_bottom`.
+- This changelog. To see changes before this update, look at the git commits.
+- azalea and azalea-client now have a `packet-event` feature, which can be disabled for efficiency if you're not using `Event::Packet`.
+- `StartJoinServerEvent` can now be used to join servers exclusively from the ECS without a Tokio runtime.
+- Add `FormattedText::to_html` and `FormattedText::to_custom_format`. (@Kumpelinus)
+- Non-standard legacy hex colors like `§#ff0000` are now supported in azalea-chat.
+- Chat signing.
+- Add auto-reconnecting which is enabled by default.
+- `ClientBuilder` and `SwarmBuilder` are now Send.
+- Add `Client::start_use_item`.
+- The pathfinder no longer avoids slabs, stairs, and dirt path blocks.
+- The pathfinder now immediately recalculates if blocks are placed in its path.
+- Bots that use custom pathfinder moves can now keep arbitrary persistent state by using the `CustomPathfinderState` component and `PathfinderCtx::custom_state`.
+- The reach distance for the pathfinder `ReachBlockPosGoal` is now configurable. (@x-osc)
+- There is now a `retry_on_no_path` option in `GotoEvent` that can be set to false to make the pathfinder give up if no path could be found.
+- azalea-brigadier now supports suggestions, command contexts, result consumers, and returning errors with `ArgumentBuilder::executes_result`.
+- Proper support for getting biomes at coordinates.
+- Add a new `Client::entities_by` which sorts entities that match a criteria by their distance to the client.
+- New client event `Event::ReceiveChunk`.
+- Several new functions for interacting with inventories (`Client::get_inventory`, `get_held_item`, `ContainerHandleRef::left_click`, `shift_click`, `right_click`, `slots`).
+- Add `Client::mine_with_auto_tool`.
+- Add `Client::set_selected_hotbar_slot` and `Client::selected_hotbar_slot`.
+- Add `Client::attack_cooldown_remaining_ticks` to complement `has_attack_cooldown`.
+- Add `BlockPos::length`, `distance_to`, and `center_bottom`.
### Changed
-- `Client::goto` is now async and completes when the client reaches its destination. `Client::start_goto` should be used if the old behavior is desired.
-- The `BlockState::id` field is now private, use `.id()` instead.
-- Update to [Bevy 0.16](https://bevyengine.org/news/bevy-0-16/).
-- Rename `InstanceContainer::insert` to `get_or_insert`.
-- Replace `BlockInteractEvent` with the more general-purpose `StartUseItemEvent`.
-- Replace `wait_one_tick` and `wait_one_update` with `wait_ticks` and `wait_updates`.
-- Functions that took `&Vec3` or `&BlockPos` as arguments now only take them as owned types.
-- Rename `azalea_block::Block` to `BlockTrait` to disambiguate with `azalea_registry::Block`.
-- `GotoEvent` is now non-enhaustive and should instead be constructed by calling its methods.
+- `Client::goto` is now async and completes when the client reaches its destination. `Client::start_goto` should be used if the old behavior is desired.
+- The `BlockState::id` field is now private, use `.id()` instead.
+- Update to [Bevy 0.16](https://bevyengine.org/news/bevy-0-16/).
+- Rename `InstanceContainer::insert` to `get_or_insert`.
+- Replace `BlockInteractEvent` with the more general-purpose `StartUseItemEvent`.
+- Replace `wait_one_tick` and `wait_one_update` with `wait_ticks` and `wait_updates`.
+- Functions that took `&Vec3` or `&BlockPos` as arguments now only take them as owned types.
+- Rename `azalea_block::Block` to `BlockTrait` to disambiguate with `azalea_registry::Block`.
+- `GotoEvent` is now non-enhaustive and should instead be constructed by calling its methods.
### Fixed
-- Clients now validate incoming packets using the correct `MAXIMUM_UNCOMPRESSED_LENGTH` value.
-- Several protocol fixes, including for `ClientboundSetPlayerTeam` and a few data components.
-- No more chunk errors when the client joins another world with the same name but different height.
-- Update the `InstanceName` component correctly when we receive a respawn or second login packet.
-- azalea-chat now handles legacy color codes correctly when parsing from NBT.
-- Send the correct UUID to servers in `ClientboundHello` when we're joining in offline-mode.
-- Block shapes and some properties were using data from `1.20.3-pre4` due to using an old data generator (Pixlyzer), which has now been replaced with the data generator from [Pumpkin](https://github.com/Pumpkin-MC/Extractor).
-- When patching the path, don't replace the move we're currently executing.
-- The correct sequence number is now sent when interacting with blocks.
-- Mining is now generally more reliable and doesn't flag Grim.
-- Ghost blocks are now handled correctly due to implementing `ClientboundBlockChangedAck`.
-- Player eye height was wrong due to being calculated from height instead of being a special case (was 1.53, should've been 1.62).
-- The player inventory is now correctly updated when we close a container.
-- Inventory interactions are now predicted on the client-side again, and the remaining click operations were implemented.
-- `Client::open_container_at` now waits up to 10 ticks for the block to exist if you try to click air.
-- Wrong physics collision code resulted in `HitResult` sometimes containing the wrong coordinates and `inside` value.
-- Fix the client being unresponsive for a few seconds after joining due to not sending `ServerboundPlayerLoaded`.
-- Fix panic when a client received `ClientboundAddEntity` and `ClientboundStartConfiguration` at the same time.
-- Fix panic due to `ClientInformation` being inserted too late.
-- `ClientboundTeleportEntity` did not handle relative teleports correctly.
-- Pathfinder now gets stuck in water less by automatically trying to jump if it's in water.
+- Clients now validate incoming packets using the correct `MAXIMUM_UNCOMPRESSED_LENGTH` value.
+- Several protocol fixes, including for `ClientboundSetPlayerTeam` and a few data components.
+- No more chunk errors when the client joins another world with the same name but different height.
+- Update the `InstanceName` component correctly when we receive a respawn or second login packet.
+- azalea-chat now handles legacy color codes correctly when parsing from NBT.
+- Send the correct UUID to servers in `ClientboundHello` when we're joining in offline-mode.
+- Block shapes and some properties were using data from `1.20.3-pre4` due to using an old data generator (Pixlyzer), which has now been replaced with the data generator from [Pumpkin](https://github.com/Pumpkin-MC/Extractor).
+- When patching the path, don't replace the move we're currently executing.
+- The correct sequence number is now sent when interacting with blocks.
+- Mining is now generally more reliable and doesn't flag Grim.
+- Ghost blocks are now handled correctly due to implementing `ClientboundBlockChangedAck`.
+- Player eye height was wrong due to being calculated from height instead of being a special case (was 1.53, should've been 1.62).
+- The player inventory is now correctly updated when we close a container.
+- Inventory interactions are now predicted on the client-side again, and the remaining click operations were implemented.
+- `Client::open_container_at` now waits up to 10 ticks for the block to exist if you try to click air.
+- Wrong physics collision code resulted in `HitResult` sometimes containing the wrong coordinates and `inside` value.
+- Fix the client being unresponsive for a few seconds after joining due to not sending `ServerboundPlayerLoaded`.
+- Fix panic when a client received `ClientboundAddEntity` and `ClientboundStartConfiguration` at the same time.
+- Fix panic due to `ClientInformation` being inserted too late.
+- `ClientboundTeleportEntity` did not handle relative teleports correctly.
+- Pathfinder now gets stuck in water less by automatically trying to jump if it's in water.
diff --git a/azalea-client/src/plugins/inventory.rs b/azalea-client/src/plugins/inventory.rs
index 7dfe42c4..e6481577 100644
--- a/azalea-client/src/plugins/inventory.rs
+++ b/azalea-client/src/plugins/inventory.rs
@@ -28,7 +28,7 @@ use crate::{Client, packet::game::SendPacketEvent, respawn::perform_respawn};
pub struct InventoryPlugin;
impl Plugin for InventoryPlugin {
fn build(&self, app: &mut App) {
- app.add_event::<ClientSideCloseContainerEvent>()
+ app.add_event::<ClientsideCloseContainerEvent>()
.add_event::<MenuOpenedEvent>()
.add_event::<CloseContainerEvent>()
.add_event::<ContainerClickEvent>()
@@ -39,7 +39,6 @@ impl Plugin for InventoryPlugin {
(
handle_set_selected_hotbar_slot_event,
handle_menu_opened_event,
- handle_set_container_content_event,
handle_container_click_event,
handle_container_close_event,
handle_client_side_close_container_event,
@@ -51,7 +50,10 @@ impl Plugin for InventoryPlugin {
.add_systems(
GameTick,
ensure_has_sent_carried_item.after(super::mining::handle_mining_queued),
- );
+ )
+ .add_observer(handle_client_side_close_container_trigger)
+ .add_observer(handle_menu_opened_trigger)
+ .add_observer(handle_set_container_content_trigger);
}
}
@@ -728,24 +730,28 @@ impl Default for Inventory {
}
}
-/// Sent from the server when a menu (like a chest or crafting table) was
-/// opened by the client.
-#[derive(Event, Debug)]
+/// A Bevy trigger that's fired when our client should show a new screen (like a
+/// chest or crafting table).
+///
+/// To watch for the menu being closed, you could use
+/// [`ClientSideCloseContainerEvent`]. To close it manually, use
+/// [`CloseContainerEvent`].
+#[derive(Event, Debug, Clone)]
pub struct MenuOpenedEvent {
pub entity: Entity,
pub window_id: i32,
pub menu_type: MenuKind,
pub title: FormattedText,
}
-fn handle_menu_opened_event(
- mut events: EventReader<MenuOpenedEvent>,
- mut query: Query<&mut Inventory>,
-) {
+fn handle_menu_opened_trigger(event: Trigger<MenuOpenedEvent>, mut query: Query<&mut Inventory>) {
+ let mut inventory = query.get_mut(event.entity).unwrap();
+ inventory.id = event.window_id;
+ inventory.container_menu = Some(Menu::from_kind(event.menu_type));
+ inventory.container_menu_title = Some(event.title.clone());
+}
+pub fn handle_menu_opened_event(mut events: EventReader<MenuOpenedEvent>, mut commands: Commands) {
for event in events.read() {
- let mut inventory = query.get_mut(event.entity).unwrap();
- inventory.id = event.window_id;
- inventory.container_menu = Some(Menu::from_kind(event.menu_type));
- inventory.container_menu_title = Some(event.title.clone());
+ commands.trigger(event.clone());
}
}
@@ -763,7 +769,7 @@ pub struct CloseContainerEvent {
fn handle_container_close_event(
query: Query<(Entity, &Inventory)>,
mut events: EventReader<CloseContainerEvent>,
- mut client_side_events: EventWriter<ClientSideCloseContainerEvent>,
+ mut client_side_events: EventWriter<ClientsideCloseContainerEvent>,
mut commands: Commands,
) {
for event in events.read() {
@@ -782,52 +788,62 @@ fn handle_container_close_event(
container_id: inventory.id,
},
));
- client_side_events.write(ClientSideCloseContainerEvent {
+ client_side_events.write(ClientsideCloseContainerEvent {
entity: event.entity,
});
}
}
-/// Close a container without notifying the server.
+/// A Bevy trigger that's fired when our client closed a container.
///
-/// Note that this also gets fired when we get a [`CloseContainerEvent`].
-#[derive(Event)]
-pub struct ClientSideCloseContainerEvent {
+/// This can also be triggered directly to close a container silently without
+/// sending any packets to the server. You probably don't want that though, and
+/// should instead use [`CloseContainerEvent`].
+///
+/// If you want to watch for a container being opened, you should use
+/// [`MenuOpenedEvent`].
+#[derive(Event, Clone)]
+pub struct ClientsideCloseContainerEvent {
pub entity: Entity,
}
-pub fn handle_client_side_close_container_event(
- mut events: EventReader<ClientSideCloseContainerEvent>,
+pub fn handle_client_side_close_container_trigger(
+ event: Trigger<ClientsideCloseContainerEvent>,
mut query: Query<&mut Inventory>,
) {
- for event in events.read() {
- let mut inventory = query.get_mut(event.entity).unwrap();
-
- // copy the Player part of the container_menu to the inventory_menu
- if let Some(inventory_menu) = inventory.container_menu.take() {
- // this isn't the same as what vanilla does. i believe vanilla synchronizes the
- // slots between inventoryMenu and containerMenu by just having the player slots
- // point to the same ItemStack in memory, but emulating this in rust would
- // require us to wrap our `ItemStack`s as `Arc<Mutex<ItemStack>>` which would
- // have kinda terrible ergonomics.
-
- // the simpler solution i chose to go with here is to only copy the player slots
- // when the container is closed. this is perfectly fine for vanilla, but it
- // might cause issues if a server modifies id 0 while we have a container
- // open...
-
- // if we do encounter this issue in the wild then the simplest solution would
- // probably be to just add logic for updating the container_menu when the server
- // tries to modify id 0 for slots within `inventory`. not implemented for now
- // because i'm not sure if that's worth worrying about.
-
- let new_inventory =
- inventory_menu.slots()[inventory_menu.player_slots_range()].to_vec();
- let new_inventory = <[ItemStack; 36]>::try_from(new_inventory).unwrap();
- *inventory.inventory_menu.as_player_mut().inventory = new_inventory;
- }
+ let mut inventory = query.get_mut(event.entity).unwrap();
+
+ // copy the Player part of the container_menu to the inventory_menu
+ if let Some(inventory_menu) = inventory.container_menu.take() {
+ // this isn't the same as what vanilla does. i believe vanilla synchronizes the
+ // slots between inventoryMenu and containerMenu by just having the player slots
+ // point to the same ItemStack in memory, but emulating this in rust would
+ // require us to wrap our `ItemStack`s as `Arc<Mutex<ItemStack>>` which would
+ // have kinda terrible ergonomics.
+
+ // the simpler solution i chose to go with here is to only copy the player slots
+ // when the container is closed. this is perfectly fine for vanilla, but it
+ // might cause issues if a server modifies id 0 while we have a container
+ // open...
+
+ // if we do encounter this issue in the wild then the simplest solution would
+ // probably be to just add logic for updating the container_menu when the server
+ // tries to modify id 0 for slots within `inventory`. not implemented for now
+ // because i'm not sure if that's worth worrying about.
+
+ let new_inventory = inventory_menu.slots()[inventory_menu.player_slots_range()].to_vec();
+ let new_inventory = <[ItemStack; 36]>::try_from(new_inventory).unwrap();
+ *inventory.inventory_menu.as_player_mut().inventory = new_inventory;
+ }
- inventory.id = 0;
- inventory.container_menu_title = None;
+ inventory.id = 0;
+ inventory.container_menu_title = None;
+}
+pub fn handle_client_side_close_container_event(
+ mut commands: Commands,
+ mut events: EventReader<ClientsideCloseContainerEvent>,
+) {
+ for event in events.read() {
+ commands.trigger(event.clone());
}
}
@@ -900,34 +916,33 @@ pub fn handle_container_click_event(
}
}
-/// Sent from the server when the contents of a container are replaced. Usually
-/// triggered by the `ContainerSetContent` packet.
+/// Sent from the server when the contents of a container are replaced.
+///
+/// Usually triggered by the `ContainerSetContent` packet.
#[derive(Event)]
pub struct SetContainerContentEvent {
pub entity: Entity,
pub slots: Vec<ItemStack>,
pub container_id: i32,
}
-fn handle_set_container_content_event(
- mut events: EventReader<SetContainerContentEvent>,
+pub fn handle_set_container_content_trigger(
+ event: Trigger<SetContainerContentEvent>,
mut query: Query<&mut Inventory>,
) {
- for event in events.read() {
- let mut inventory = query.get_mut(event.entity).unwrap();
+ let mut inventory = query.get_mut(event.entity).unwrap();
- if event.container_id != inventory.id {
- warn!(
- "Got SetContainerContentEvent for container with ID {}, but the current container ID is {}",
- event.container_id, inventory.id
- );
- continue;
- }
+ if event.container_id != inventory.id {
+ warn!(
+ "Got SetContainerContentEvent for container with ID {}, but the current container ID is {}",
+ event.container_id, inventory.id
+ );
+ return;
+ }
- let menu = inventory.menu_mut();
- for (i, slot) in event.slots.iter().enumerate() {
- if let Some(slot_mut) = menu.slot_mut(i) {
- *slot_mut = slot.clone();
- }
+ let menu = inventory.menu_mut();
+ for (i, slot) in event.slots.iter().enumerate() {
+ if let Some(slot_mut) = menu.slot_mut(i) {
+ *slot_mut = slot.clone();
}
}
}
diff --git a/azalea-client/src/plugins/packet/game/mod.rs b/azalea-client/src/plugins/packet/game/mod.rs
index 49523002..bc1d1752 100644
--- a/azalea-client/src/plugins/packet/game/mod.rs
+++ b/azalea-client/src/plugins/packet/game/mod.rs
@@ -31,7 +31,7 @@ use crate::{
disconnect::DisconnectEvent,
interact::BlockStatePredictionHandler,
inventory::{
- ClientSideCloseContainerEvent, Inventory, MenuOpenedEvent, SetContainerContentEvent,
+ ClientsideCloseContainerEvent, Inventory, MenuOpenedEvent, SetContainerContentEvent,
},
local_player::{Hunger, InstanceHolder, LocalGameMode, TabList},
movement::{KnockbackEvent, KnockbackType},
@@ -1136,28 +1136,25 @@ impl GamePacketHandler<'_> {
pub fn container_set_content(&mut self, p: &ClientboundContainerSetContent) {
debug!("Got container set content packet {p:?}");
- as_system::<(Query<&mut Inventory>, EventWriter<_>)>(
- self.ecs,
- |(mut query, mut events)| {
- let mut inventory = query.get_mut(self.player).unwrap();
-
- // container id 0 is always the player's inventory
- if p.container_id == 0 {
- // this is just so it has the same type as the `else` block
- for (i, slot) in p.items.iter().enumerate() {
- if let Some(slot_mut) = inventory.inventory_menu.slot_mut(i) {
- *slot_mut = slot.clone();
- }
+ as_system::<(Commands, Query<&mut Inventory>)>(self.ecs, |(mut commands, mut query)| {
+ let mut inventory = query.get_mut(self.player).unwrap();
+
+ // container id 0 is always the player's inventory
+ if p.container_id == 0 {
+ // this is just so it has the same type as the `else` block
+ for (i, slot) in p.items.iter().enumerate() {
+ if let Some(slot_mut) = inventory.inventory_menu.slot_mut(i) {
+ *slot_mut = slot.clone();
}
- } else {
- events.write(SetContainerContentEvent {
- entity: self.player,
- slots: p.items.clone(),
- container_id: p.container_id,
- });
}
- },
- );
+ } else {
+ commands.trigger(SetContainerContentEvent {
+ entity: self.player,
+ slots: p.items.clone(),
+ container_id: p.container_id,
+ });
+ }
+ });
}
pub fn container_set_data(&mut self, p: &ClientboundContainerSetData) {
@@ -1215,8 +1212,8 @@ impl GamePacketHandler<'_> {
debug!("Got container close packet {p:?}");
- as_system::<EventWriter<_>>(self.ecs, |mut events| {
- events.write(ClientSideCloseContainerEvent {
+ as_system::<Commands>(self.ecs, |mut commands| {
+ commands.trigger(ClientsideCloseContainerEvent {
entity: self.player,
});
});
@@ -1266,8 +1263,8 @@ impl GamePacketHandler<'_> {
pub fn open_screen(&mut self, p: &ClientboundOpenScreen) {
debug!("Got open screen packet {p:?}");
- as_system::<EventWriter<_>>(self.ecs, |mut events| {
- events.write(MenuOpenedEvent {
+ as_system::<Commands>(self.ecs, |mut commands| {
+ commands.trigger(MenuOpenedEvent {
entity: self.player,
window_id: p.container_id,
menu_type: p.menu_type,