From e8451da55ee15b13e8a13d7b69a924af1c8692ca Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 3 Jul 2022 23:17:51 -0700 Subject: [PATCH] Add entity status codes --- examples/conway.rs | 6 ++-- src/client.rs | 62 +++++++++++++++++++++++++---------- src/client/event.rs | 2 +- src/protocol/packets.rs | 71 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 119 insertions(+), 22 deletions(-) diff --git a/examples/conway.rs b/examples/conway.rs index 1ebcbd9..3f1abdb 100644 --- a/examples/conway.rs +++ b/examples/conway.rs @@ -7,7 +7,7 @@ use std::sync::Mutex; use log::LevelFilter; use num::Integer; use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator}; -use valence::client::{ClientId, Event, GameMode}; +use valence::client::{ClientId, ClientEvent, GameMode, EntityEvent}; use valence::config::{Config, ServerListPing}; use valence::text::Color; use valence::{ @@ -169,7 +169,7 @@ impl Config for Game { .unwrap(); while let Some(event) = client.pop_event() { match event { - Event::Digging(e) => { + ClientEvent::Digging(e) => { let pos = e.position; if (0..SIZE_X as i32).contains(&pos.x) @@ -179,7 +179,7 @@ impl Config for Game { board[pos.x as usize + pos.z as usize * SIZE_X] = true; } } - Event::Movement { .. } => { + ClientEvent::Movement { .. } => { if client.position().y <= 0.0 { client.teleport(spawn_pos, client.yaw(), client.pitch()); } diff --git a/src/client.rs b/src/client.rs index 7d2def0..8b8d072 100644 --- a/src/client.rs +++ b/src/client.rs @@ -16,15 +16,17 @@ use crate::entity::types::Player; use crate::entity::{velocity_to_packet_units, EntityType}; use crate::player_textures::SignedPlayerTextures; use crate::protocol::packets::play::c2s::{C2sPlayPacket, DiggingStatus, InteractType}; +pub use crate::protocol::packets::play::s2c::EntityEventStatus as EntityEvent; use crate::protocol::packets::play::s2c::{ Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound, BiomeMusic, BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, BlockChangeAck, ChatType, ChatTypeChat, ChatTypeNarration, ChatTypeRegistry, ChatTypeRegistryEntry, DimensionType, - DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, ForgetLevelChunk, GameEvent, - GameEventReason, KeepAlive, Login, MoveEntityPosition, MoveEntityPositionAndRotation, - MoveEntityRotation, PlayerPosition, PlayerPositionFlags, RegistryCodec, RemoveEntities, - Respawn, RotateHead, S2cPlayPacket, SetChunkCacheCenter, SetChunkCacheRadius, - SetEntityMetadata, SetEntityMotion, SpawnPosition, SystemChat, TeleportEntity, + DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, + EntityEvent as EntityEventPacket, ForgetLevelChunk, GameEvent, GameEventReason, KeepAlive, + Login, MoveEntityPosition, MoveEntityPositionAndRotation, MoveEntityRotation, PlayerPosition, + PlayerPositionFlags, RegistryCodec, RemoveEntities, Respawn, RotateHead, S2cPlayPacket, + SetChunkCacheCenter, SetChunkCacheRadius, SetEntityMetadata, SetEntityMotion, SpawnPosition, + SystemChat, TeleportEntity, }; use crate::protocol::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt}; use crate::server::C2sPacketChannels; @@ -126,7 +128,7 @@ pub struct Client { /// If spawn_position or spawn_position_yaw were modified this tick. modified_spawn_position: bool, death_location: Option<(DimensionId, BlockPos)>, - events: VecDeque, + events: VecDeque, /// The ID of the last keepalive sent. last_keepalive_id: i64, /// If the last sent keepalive got a response. @@ -143,6 +145,7 @@ pub struct Client { settings: Option, dug_blocks: Vec, msgs_to_send: Vec, + entity_events: Vec<(Option, EntityEvent)>, /// The metadata for the client's own player entity. player_meta: Player, } @@ -188,6 +191,7 @@ impl Client { settings: None, dug_blocks: Vec::new(), msgs_to_send: Vec::new(), + entity_events: Vec::new(), player_meta: Player::new(), } } @@ -308,10 +312,14 @@ impl Client { self.send.is_none() } - pub fn pop_event(&mut self) -> Option { + pub fn pop_event(&mut self) -> Option { self.events.pop_front() } + pub fn push_entity_event(&mut self, target: Option, event: EntityEvent) { + self.entity_events.push((target, event)); + } + /// The current view distance of this client measured in chunks. pub fn view_distance(&self) -> u8 { self.settings @@ -384,7 +392,7 @@ impl Client { if client.pending_teleports == 0 { // TODO: validate movement using swept AABB collision with the blocks. // TODO: validate that the client is actually inside/outside the vehicle? - let event = Event::Movement { + let event = ClientEvent::Movement { position: client.new_position, yaw: client.yaw, pitch: client.pitch, @@ -427,7 +435,7 @@ impl Client { C2sPlayPacket::BlockEntityTagQuery(_) => {} C2sPlayPacket::ChangeDifficulty(_) => {} C2sPlayPacket::ChatCommand(_) => {} - C2sPlayPacket::Chat(p) => self.events.push_back(Event::ChatMessage { + C2sPlayPacket::Chat(p) => self.events.push_back(ClientEvent::ChatMessage { message: p.message.0, timestamp: Duration::from_millis(p.timestamp), }), @@ -444,7 +452,7 @@ impl Client { allow_server_listings: p.allow_server_listings, }); - self.events.push_back(Event::SettingsChanged(old)); + self.events.push_back(ClientEvent::SettingsChanged(old)); } C2sPlayPacket::CommandSuggestion(_) => {} C2sPlayPacket::ContainerButtonClick(_) => {} @@ -457,7 +465,7 @@ impl Client { // TODO: verify that the client has line of sight to the targeted entity and // that the distance is <=4 blocks. - self.events.push_back(Event::InteractWithEntity { + self.events.push_back(ClientEvent::InteractWithEntity { id, sneaking: p.sneaking, typ: match p.typ { @@ -510,7 +518,7 @@ impl Client { handle_movement_packet(self, true, p.position, p.yaw, p.pitch, self.on_ground); } C2sPlayPacket::PaddleBoat(p) => { - self.events.push_back(Event::SteerBoat { + self.events.push_back(ClientEvent::SteerBoat { left_paddle_turning: p.left_paddle_turning, right_paddle_turning: p.right_paddle_turning, }); @@ -527,17 +535,17 @@ impl Client { } self.events.push_back(match p.status { - DiggingStatus::StartedDigging => Event::Digging(Digging { + DiggingStatus::StartedDigging => ClientEvent::Digging(Digging { status: event::DiggingStatus::Start, position: p.location, face: p.face, }), - DiggingStatus::CancelledDigging => Event::Digging(Digging { + DiggingStatus::CancelledDigging => ClientEvent::Digging(Digging { status: event::DiggingStatus::Cancel, position: p.location, face: p.face, }), - DiggingStatus::FinishedDigging => Event::Digging(Digging { + DiggingStatus::FinishedDigging => ClientEvent::Digging(Digging { status: event::DiggingStatus::Finish, position: p.location, face: p.face, @@ -565,7 +573,7 @@ impl Client { C2sPlayPacket::SetJigsawBlock(_) => {} C2sPlayPacket::SetStructureBlock(_) => {} C2sPlayPacket::SignUpdate(_) => {} - C2sPlayPacket::Swing(p) => self.events.push_back(Event::ArmSwing(p.hand)), + C2sPlayPacket::Swing(p) => self.events.push_back(ClientEvent::ArmSwing(p.hand)), C2sPlayPacket::TeleportToEntity(_) => {} C2sPlayPacket::UseItemOn(_) => {} C2sPlayPacket::UseItem(_) => {} @@ -964,6 +972,28 @@ impl Client { }, ); + for (target, event) in self.entity_events.drain(..) { + if let Some(target) = target { + if self.loaded_entities.contains(&target) { + send_packet( + &mut self.send, + EntityEventPacket { + entity_id: target.to_network_id(), + entity_status: event, + }, + ) + } + } else { + send_packet( + &mut self.send, + EntityEventPacket { + entity_id: 0, + entity_status: event, + }, + ); + } + } + self.old_position = self.new_position; self.spawn = false; } diff --git a/src/client/event.rs b/src/client/event.rs index 9f428f8..340484e 100644 --- a/src/client/event.rs +++ b/src/client/event.rs @@ -8,7 +8,7 @@ pub use crate::protocol::packets::play::s2c::GameMode; use crate::{BlockPos, EntityId}; #[derive(Debug)] -pub enum Event { +pub enum ClientEvent { ChatMessage { message: String, timestamp: Duration, diff --git a/src/protocol/packets.rs b/src/protocol/packets.rs index 68e1edc..1170e17 100644 --- a/src/protocol/packets.rs +++ b/src/protocol/packets.rs @@ -744,8 +744,75 @@ pub mod play { def_struct! { EntityEvent 0x18 { entity_id: i32, - /// TODO: enum - entity_status: u8, + entity_status: EntityEventStatus, + } + } + + def_enum! { + #[derive(Copy, PartialEq, Eq)] + EntityEventStatus: u8 { + Jump = 1, + Hurt = 2, + Death = 3, + StartAttacking = 4, + StopAttacking = 5, + TamingFailed = 6, + TamingSucceeded = 7, + ShakeWetness = 8, + UseItemComplete = 9, + EatGrass = 10, + OfferFlower = 11, + LoveHearts = 12, + VillagerAngry = 13, + VillagerHappy = 14, + WitchHatMagic = 15, + ZombieConverting = 16, + FireworksExplode = 17, + InLoveHearts = 18, + SquidAnimSynch = 19, + SilverfishMergeAnim = 20, + GuardianAttackSound = 21, + ReducedDebugInfo = 22, + FullDebugInfo = 23, + PermissionLevelAll = 24, + PermissionLevelModerators = 25, + PermissionLevelGamemasters = 26, + PermissionLevelAdmins = 27, + PermissionLevelOwners = 28, + AttackBlocked = 29, + ShieldDisabled = 30, + FishingRodReelIn = 31, + ArmorstandWobble = 32, + Thorned = 33, + StopOfferFlower = 34, + TalismanActivate = 35, + Drowned = 36, + Burned = 37, + DolphinLookingForTreasure = 38, + RavagerStunned = 39, + TrustingFailed = 40, + TrustingSucceeded = 41, + VillagerSweat = 42, + BadOmenTriggered = 43, + Poked = 44, + FoxEat = 45, + Teleport = 46, + MainhandBreak = 47, + OffhandBreak = 48, + HeadBreak = 49, + ChestBreak = 50, + LegsBreak = 51, + FeetBreak = 52, + HoneySlide = 53, + HoneyJump = 54, + SwapHands = 55, + CancelShakeWetness = 56, + Frozen = 57, + StartRam = 58, + EndRam = 59, + Poof = 60, + TendrilsShiver = 61, + SonicCharge = 62, } }