aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/packet_handling.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-05-03 20:57:27 -0500
committerGitHub <noreply@github.com>2023-05-03 20:57:27 -0500
commit634cb8d72c6608512aedba19e5cd669104bc35ea (patch)
treef8e76ce9eb43403d29cc0cbcf9a4f51522419dc2 /azalea-client/src/packet_handling.rs
parent1fb4418f2c9cbd004c64c2f23d2d0352ee12c0e5 (diff)
downloadazalea-drasl-634cb8d72c6608512aedba19e5cd669104bc35ea.tar.xz
Inventory (#48)
* start adding azalea-inventory * design more of how inventories are defined * start working on az-inv-macros * inventory macro works * start adding inventory codegen * update some deps * add inventory codegen * manually write inventory menus * put the inventories in Client * start on containersetcontent * inventory menu should hopefully work * checks in containersetcontent * format a comment * move some variant matches * inventory.rs * inventory stuff * more inventory stuff * inventory/container tracking works * start adding interact function * sequence number * start adding HitResultComponent * implement traverse_blocks * start adding clip * add clip function * update_hit_result_component * start trying to fix * fix * make some stuff simpler * clippy * lever * chest * container handle * fix ambiguity * fix some doc tests * move some container stuff from az-client to azalea * clicking container * start implementing simulate_click * keep working on simulate click * implement more of simulate_click this is really boring * inventory fixes * start implementing shift clicking * fix panic in azalea-chat i hope * shift clicking implemented * more inventory stuff * fix items not showing in containers sometimes * fix test * fix all warnings * remove a println --------- Co-authored-by: mat <git@matdoes.dev>
Diffstat (limited to 'azalea-client/src/packet_handling.rs')
-rw-r--r--azalea-client/src/packet_handling.rs171
1 files changed, 148 insertions, 23 deletions
diff --git a/azalea-client/src/packet_handling.rs b/azalea-client/src/packet_handling.rs
index b9837dba..8ffff870 100644
--- a/azalea-client/src/packet_handling.rs
+++ b/azalea-client/src/packet_handling.rs
@@ -1,6 +1,6 @@
use std::{collections::HashSet, io::Cursor, sync::Arc};
-use azalea_core::{ChunkPos, ResourceLocation, Vec3};
+use azalea_core::{ChunkPos, GameMode, ResourceLocation, Vec3};
use azalea_protocol::{
connect::{ReadConnection, WriteConnection},
packets::game::{
@@ -16,7 +16,7 @@ use azalea_protocol::{
use azalea_world::{
entity::{
metadata::{apply_metadata, Health, PlayerMetadataBundle},
- set_rotation, Dead, EntityBundle, EntityKind, EntityUpdateSet, LastSentPosition,
+ Dead, EntityBundle, EntityKind, EntityUpdateSet, LastSentPosition, LookDirection,
MinecraftEntityId, Physics, PlayerBundle, Position, WorldName,
},
entity::{LoadedBy, RelativeEntityUpdate},
@@ -37,9 +37,13 @@ use tokio::sync::mpsc;
use crate::{
chat::{ChatPacket, ChatReceivedEvent},
- client::TabList,
+ client::{PlayerAbilities, TabList},
disconnect::DisconnectEvent,
- local_player::{GameProfileComponent, LocalPlayer},
+ inventory::{
+ ClientSideCloseContainerEvent, InventoryComponent, MenuOpenedEvent,
+ SetContainerContentEvent,
+ },
+ local_player::{GameProfileComponent, LocalGameMode, LocalPlayer},
ClientInformation, PlayerInfo,
};
@@ -194,7 +198,7 @@ fn process_packet_events(ecs: &mut World) {
)>,
ResMut<InstanceContainer>,
)> = SystemState::new(ecs);
- let (mut commands, mut query, mut world_container) = system_state.get_mut(ecs);
+ let (mut commands, mut query, mut instance_container) = system_state.get_mut(ecs);
let (mut local_player, world_name, game_profile, client_information) =
query.get_mut(player_entity).unwrap();
@@ -220,16 +224,16 @@ fn process_packet_events(ecs: &mut World) {
.entity(player_entity)
.insert(WorldName(new_world_name.clone()));
}
- // add this world to the world_container (or don't if it's already
+ // add this world to the instance_container (or don't if it's already
// there)
- let weak_world = world_container.insert(
+ let weak_world = instance_container.insert(
new_world_name.clone(),
dimension.height,
dimension.min_y,
);
// set the partial_world to an empty world
// (when we add chunks or entities those will be in the
- // world_container)
+ // instance_container)
*local_player.partial_instance.write() = PartialInstance::new(
client_information.view_distance.into(),
@@ -250,9 +254,14 @@ fn process_packet_events(ecs: &mut World) {
metadata: PlayerMetadataBundle::default(),
};
// insert our components into the ecs :)
- commands
- .entity(player_entity)
- .insert((MinecraftEntityId(p.player_id), player_bundle));
+ commands.entity(player_entity).insert((
+ MinecraftEntityId(p.player_id),
+ LocalGameMode {
+ current: p.game_type,
+ previous: p.previous_game_type.into(),
+ },
+ player_bundle,
+ ));
}
// send the client information that we have set
@@ -288,6 +297,12 @@ fn process_packet_events(ecs: &mut World) {
}
ClientboundGamePacket::PlayerAbilities(p) => {
debug!("Got player abilities packet {:?}", p);
+ let mut system_state: SystemState<Query<&mut PlayerAbilities>> =
+ SystemState::new(ecs);
+ let mut query = system_state.get_mut(ecs);
+ let mut player_abilities = query.get_mut(player_entity).unwrap();
+
+ *player_abilities = PlayerAbilities::from(p);
}
ClientboundGamePacket::SetCarriedItem(p) => {
debug!("Got set carried item packet {:?}", p);
@@ -319,16 +334,18 @@ fn process_packet_events(ecs: &mut World) {
// TODO: reply with teleport confirm
debug!("Got player position packet {:?}", p);
+ #[allow(clippy::type_complexity)]
let mut system_state: SystemState<
Query<(
&mut LocalPlayer,
&mut Physics,
+ &mut LookDirection,
&mut Position,
&mut LastSentPosition,
)>,
> = SystemState::new(ecs);
let mut query = system_state.get_mut(ecs);
- let Ok((mut local_player, mut physics, mut position, mut last_sent_position)) =
+ let Ok((local_player, mut physics, mut direction, mut position, mut last_sent_position)) =
query.get_mut(player_entity) else {
continue;
};
@@ -364,10 +381,10 @@ fn process_packet_events(ecs: &mut World) {
let mut y_rot = p.y_rot;
let mut x_rot = p.x_rot;
if p.relative_arguments.x_rot {
- x_rot += physics.x_rot;
+ x_rot += direction.x_rot;
}
if p.relative_arguments.y_rot {
- y_rot += physics.y_rot;
+ y_rot += direction.y_rot;
}
physics.delta = Vec3 {
@@ -378,7 +395,7 @@ fn process_packet_events(ecs: &mut World) {
// we call a function instead of setting the fields ourself since the
// function makes sure the rotations stay in their
// ranges
- set_rotation(&mut physics, y_rot, x_rot);
+ (direction.y_rot, direction.x_rot) = (y_rot, x_rot);
// TODO: minecraft sets "xo", "yo", and "zo" here but idk what that means
// so investigate that ig
let new_pos = Vec3 {
@@ -633,9 +650,6 @@ fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::SetDefaultSpawnPosition(p) => {
debug!("Got set default spawn position packet {:?}", p);
}
- ClientboundGamePacket::ContainerSetContent(p) => {
- debug!("Got container set content packet {:?}", p);
- }
ClientboundGamePacket::SetHealth(p) => {
debug!("Got set health packet {:?}", p);
@@ -765,7 +779,7 @@ fn process_packet_events(ecs: &mut World) {
id: p.id,
});
- let mut local_player = query.get_mut(player_entity).unwrap();
+ let local_player = query.get_mut(player_entity).unwrap();
local_player.write_packet(ServerboundKeepAlivePacket { id: p.id }.get());
debug!("Sent keep alive packet {p:?} for {player_entity:?}");
}
@@ -831,7 +845,23 @@ fn process_packet_events(ecs: &mut World) {
}
}
ClientboundGamePacket::GameEvent(p) => {
+ use azalea_protocol::packets::game::clientbound_game_event_packet::EventType;
+
debug!("Got game event packet {:?}", p);
+
+ #[allow(clippy::single_match)]
+ match p.event {
+ EventType::ChangeGameMode => {
+ let mut system_state: SystemState<Query<&mut LocalGameMode>> =
+ SystemState::new(ecs);
+ let mut query = system_state.get_mut(ecs);
+ let mut local_game_mode = query.get_mut(player_entity).unwrap();
+ if let Some(new_game_mode) = GameMode::from_id(p.param as u8) {
+ local_game_mode.current = new_game_mode;
+ }
+ }
+ _ => {}
+ }
}
ClientboundGamePacket::LevelParticles(p) => {
debug!("Got level particles packet {:?}", p);
@@ -855,8 +885,93 @@ fn process_packet_events(ecs: &mut World) {
}
ClientboundGamePacket::BossEvent(_) => {}
ClientboundGamePacket::CommandSuggestions(_) => {}
- ClientboundGamePacket::ContainerSetData(_) => {}
- ClientboundGamePacket::ContainerSetSlot(_) => {}
+ ClientboundGamePacket::ContainerSetContent(p) => {
+ debug!("Got container set content packet {:?}", p);
+
+ let mut system_state: SystemState<(
+ Query<&mut InventoryComponent>,
+ EventWriter<SetContainerContentEvent>,
+ )> = SystemState::new(ecs);
+ let (mut query, mut events) = system_state.get_mut(ecs);
+ let mut inventory = query.get_mut(player_entity).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.send(SetContainerContentEvent {
+ entity: player_entity,
+ slots: p.items.clone(),
+ container_id: p.container_id as u8,
+ });
+ }
+ }
+ ClientboundGamePacket::ContainerSetData(p) => {
+ debug!("Got container set data packet {:?}", p);
+ // let mut system_state: SystemState<Query<&mut
+ // InventoryComponent>> =
+ // SystemState::new(ecs);
+ // let mut query = system_state.get_mut(ecs);
+ // let mut inventory =
+ // query.get_mut(player_entity).unwrap();
+
+ // TODO: handle ContainerSetData packet
+ // this is used for various things like the furnace progress
+ // bar
+ // see https://wiki.vg/Protocol#Set_Container_Property
+ }
+ ClientboundGamePacket::ContainerSetSlot(p) => {
+ debug!("Got container set slot packet {:?}", p);
+
+ let mut system_state: SystemState<Query<&mut InventoryComponent>> =
+ SystemState::new(ecs);
+ let mut query = system_state.get_mut(ecs);
+ let mut inventory = query.get_mut(player_entity).unwrap();
+
+ if p.container_id == -1 {
+ // -1 means carried item
+ inventory.carried = p.item_stack.clone();
+ } else if p.container_id == -2 {
+ if let Some(slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
+ *slot = p.item_stack.clone();
+ }
+ } else {
+ let is_creative_mode_and_inventory_closed = false;
+ // technically minecraft has slightly different behavior here if you're in
+ // creative mode and have your inventory open
+ if p.container_id == 0
+ && azalea_inventory::Player::is_hotbar_slot(p.slot.into())
+ {
+ // minecraft also sets a "pop time" here which is used for an animation
+ // but that's not really necessary
+ if let Some(slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
+ *slot = p.item_stack.clone();
+ }
+ } else if p.container_id == (inventory.id as i8)
+ && (p.container_id != 0 || !is_creative_mode_and_inventory_closed)
+ {
+ // var2.containerMenu.setItem(var4, var1.getStateId(), var3);
+ if let Some(slot) = inventory.menu_mut().slot_mut(p.slot.into()) {
+ *slot = p.item_stack.clone();
+ inventory.state_id = p.state_id;
+ }
+ }
+ }
+ }
+ ClientboundGamePacket::ContainerClose(_p) => {
+ // there's p.container_id but minecraft doesn't actually check it
+ let mut system_state: SystemState<EventWriter<ClientSideCloseContainerEvent>> =
+ SystemState::new(ecs);
+ let mut client_side_close_container_events = system_state.get_mut(ecs);
+ client_side_close_container_events.send(ClientSideCloseContainerEvent {
+ entity: player_entity,
+ })
+ }
ClientboundGamePacket::Cooldown(_) => {}
ClientboundGamePacket::CustomChatCompletions(_) => {}
ClientboundGamePacket::DeleteChat(_) => {}
@@ -867,7 +982,18 @@ fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::MerchantOffers(_) => {}
ClientboundGamePacket::MoveVehicle(_) => {}
ClientboundGamePacket::OpenBook(_) => {}
- ClientboundGamePacket::OpenScreen(_) => {}
+ ClientboundGamePacket::OpenScreen(p) => {
+ debug!("Got open screen packet {:?}", p);
+ let mut system_state: SystemState<EventWriter<MenuOpenedEvent>> =
+ SystemState::new(ecs);
+ let mut menu_opened_events = system_state.get_mut(ecs);
+ menu_opened_events.send(MenuOpenedEvent {
+ entity: player_entity,
+ window_id: p.container_id,
+ menu_type: p.menu_type,
+ title: p.title,
+ })
+ }
ClientboundGamePacket::OpenSignEditor(_) => {}
ClientboundGamePacket::Ping(_) => {}
ClientboundGamePacket::PlaceGhostRecipe(_) => {}
@@ -935,7 +1061,6 @@ fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::TakeItemEntity(_) => {}
ClientboundGamePacket::DisguisedChat(_) => {}
ClientboundGamePacket::UpdateEnabledFeatures(_) => {}
- ClientboundGamePacket::ContainerClose(_) => {}
ClientboundGamePacket::Bundle(_) => {}
ClientboundGamePacket::DamageEvent(_) => {}
ClientboundGamePacket::HurtAnimation(_) => {}