Improve entity event API

This commit is contained in:
Ryan 2022-07-05 18:08:40 -07:00
parent 0f8b906265
commit fcda380f2a
7 changed files with 526 additions and 310 deletions

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelI
use valence::client::{ClientEvent, ClientId, GameMode}; use valence::client::{ClientEvent, ClientId, GameMode};
use valence::config::{Config, ServerListPing}; use valence::config::{Config, ServerListPing};
use valence::entity::meta::Pose; use valence::entity::meta::Pose;
use valence::entity::EntityMeta; use valence::entity::EntityData;
use valence::text::Color; use valence::text::Color;
use valence::{ use valence::{
async_trait, ident, Biome, BlockState, Dimension, DimensionId, EntityId, EntityType, Server, async_trait, ident, Biome, BlockState, Dimension, DimensionId, EntityId, EntityType, Server,
@ -197,30 +197,30 @@ impl Config for Game {
player.set_on_ground(client.on_ground()); player.set_on_ground(client.on_ground());
} }
ClientEvent::StartSneaking => { ClientEvent::StartSneaking => {
if let EntityMeta::Player(e) = player.meta_mut() { if let EntityData::Player(e) = player.data_mut() {
e.set_crouching(true); e.set_crouching(true);
e.set_pose(Pose::Sneaking); e.set_pose(Pose::Sneaking);
} }
} }
ClientEvent::StopSneaking => { ClientEvent::StopSneaking => {
if let EntityMeta::Player(e) = player.meta_mut() { if let EntityData::Player(e) = player.data_mut() {
e.set_pose(Pose::Standing); e.set_pose(Pose::Standing);
e.set_crouching(false); e.set_crouching(false);
} }
} }
ClientEvent::StartSprinting => { ClientEvent::StartSprinting => {
if let EntityMeta::Player(e) = player.meta_mut() { if let EntityData::Player(e) = player.data_mut() {
e.set_sprinting(true); e.set_sprinting(true);
} }
} }
ClientEvent::StopSprinting => { ClientEvent::StopSprinting => {
if let EntityMeta::Player(e) = player.meta_mut() { if let EntityData::Player(e) = player.data_mut() {
e.set_sprinting(false); e.set_sprinting(false);
} }
} }
ClientEvent::ArmSwing(_) => { ClientEvent::ArmSwing(_) => {
if let EntityMeta::Player(_) = player.meta_mut() { if let EntityData::Player(e) = player.data_mut() {
// TODO: swing arm. e.trigger_swing_main_arm();
} }
} }
_ => {} _ => {}

View file

@ -13,31 +13,30 @@ use vek::Vec3;
use crate::biome::{Biome, BiomeGrassColorModifier, BiomePrecipitation}; use crate::biome::{Biome, BiomeGrassColorModifier, BiomePrecipitation};
use crate::dimension::{Dimension, DimensionEffects}; use crate::dimension::{Dimension, DimensionEffects};
use crate::entity::types::Player; use crate::entity::data::Player;
use crate::entity::{velocity_to_packet_units, EntityType}; use crate::entity::{velocity_to_packet_units, EntityType};
use crate::player_textures::SignedPlayerTextures; use crate::player_textures::SignedPlayerTextures;
use crate::protocol::packets::play::c2s::{ use crate::protocol::packets::play::c2s::{
C2sPlayPacket, DiggingStatus, InteractType, PlayerCommandId, C2sPlayPacket, DiggingStatus, InteractType, PlayerCommandId,
}; };
pub use crate::protocol::packets::play::s2c::EntityEvent;
use crate::protocol::packets::play::s2c::{ use crate::protocol::packets::play::s2c::{
Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound, BiomeMusic, Animate, Biome as BiomeRegistryBiome, BiomeAdditionsSound, BiomeEffects, BiomeMoodSound,
BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, BlockChangeAck, ChatType, BiomeMusic, BiomeParticle, BiomeParticleOptions, BiomeProperty, BiomeRegistry, BlockChangeAck,
ChatTypeChat, ChatTypeNarration, ChatTypeRegistry, ChatTypeRegistryEntry, DimensionType, ChatType, ChatTypeChat, ChatTypeNarration, ChatTypeRegistry, ChatTypeRegistryEntry,
DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, DoEntityEvent, ForgetLevelChunk, DimensionType, DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, EntityEvent,
GameEvent, GameEventReason, KeepAlive, Login, MoveEntityPosition, ForgetLevelChunk, GameEvent, GameEventReason, KeepAlive, Login, MoveEntityPosition,
MoveEntityPositionAndRotation, MoveEntityRotation, PlayerPosition, PlayerPositionFlags, MoveEntityPositionAndRotation, MoveEntityRotation, PlayerPosition, PlayerPositionFlags,
RegistryCodec, RemoveEntities, Respawn, RotateHead, S2cPlayPacket, SetChunkCacheCenter, RegistryCodec, RemoveEntities, Respawn, RotateHead, S2cPlayPacket, SetChunkCacheCenter,
SetChunkCacheRadius, SetEntityMetadata, SetEntityMotion, SpawnPosition, SystemChat, SetChunkCacheRadius, SetEntityMetadata, SetEntityMotion, SpawnPosition, SystemChat,
TeleportEntity, TeleportEntity, ENTITY_EVENT_MAX_BOUND,
}; };
use crate::protocol::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt}; use crate::protocol::{BoundedInt, ByteAngle, Nbt, RawBytes, VarInt};
use crate::server::C2sPacketChannels; use crate::server::C2sPacketChannels;
use crate::slotmap::{Key, SlotMap}; use crate::slotmap::{Key, SlotMap};
use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance}; use crate::util::{chunks_in_view_distance, is_chunk_in_view_distance};
use crate::{ use crate::{
ident, BlockPos, ChunkPos, DimensionId, Entities, EntityId, NewClientData, SharedServer, Text, ident, BlockPos, ChunkPos, DimensionId, Entities, Entity, EntityId, NewClientData,
Ticks, WorldId, Worlds, LIBRARY_NAMESPACE, SharedServer, Text, Ticks, WorldId, Worlds, LIBRARY_NAMESPACE,
}; };
pub struct Clients { pub struct Clients {
@ -101,7 +100,7 @@ impl ClientId {
/// Represents a client connected to the server after logging in. /// Represents a client connected to the server after logging in.
pub struct Client { pub struct Client {
/// Setting this to `None` disconnects the client. /// Setting this to `None` disconnects the client.
send: Option<Sender<S2cPlayPacket>>, send: SendOpt,
recv: Receiver<C2sPlayPacket>, recv: Receiver<C2sPlayPacket>,
/// The tick this client was created. /// The tick this client was created.
created_tick: Ticks, created_tick: Ticks,
@ -139,10 +138,9 @@ pub struct Client {
settings: Option<Settings>, settings: Option<Settings>,
dug_blocks: Vec<i32>, dug_blocks: Vec<i32>,
msgs_to_send: Vec<Text>, msgs_to_send: Vec<Text>,
entity_events: Vec<EntityEvent>,
flags: ClientFlags, flags: ClientFlags,
/// The metadata for the client's own player entity. /// The data for the client's own player entity.
player_meta: Player, player_data: Player,
} }
#[bitfield(u8)] #[bitfield(u8)]
@ -197,11 +195,10 @@ impl Client {
settings: None, settings: None,
dug_blocks: Vec::new(), dug_blocks: Vec::new(),
msgs_to_send: Vec::new(), msgs_to_send: Vec::new(),
entity_events: Vec::new(),
flags: ClientFlags::new() flags: ClientFlags::new()
.with_modified_spawn_position(true) .with_modified_spawn_position(true)
.with_got_keepalive(true), .with_got_keepalive(true),
player_meta: Player::new(), player_data: Player::new(),
} }
} }
@ -325,10 +322,6 @@ impl Client {
self.events.pop_front() self.events.pop_front()
} }
pub fn push_entity_event(&mut self, event: EntityEvent) {
self.entity_events.push(event);
}
/// The current view distance of this client measured in chunks. /// The current view distance of this client measured in chunks.
pub fn view_distance(&self) -> u8 { pub fn view_distance(&self) -> u8 {
self.settings self.settings
@ -368,12 +361,12 @@ impl Client {
} }
} }
pub fn meta(&self) -> &Player { pub fn data(&self) -> &Player {
&self.player_meta &self.player_data
} }
pub fn meta_mut(&mut self) -> &mut Player { pub fn data_mut(&mut self) -> &mut Player {
&mut self.player_meta &mut self.player_data
} }
/// Attempts to enqueue a play packet to be sent to this client. The client /// Attempts to enqueue a play packet to be sent to this client. The client
@ -971,15 +964,7 @@ impl Client {
) )
} }
for &e in entity.events() { send_entity_events(&mut self.send, id, entity);
send_packet(
&mut self.send,
DoEntityEvent {
entity_id: id.to_network_id(),
entity_status: e,
},
);
}
return true; return true;
} }
@ -997,7 +982,7 @@ impl Client {
// Update the client's own player metadata. // Update the client's own player metadata.
let mut data = Vec::new(); let mut data = Vec::new();
self.player_meta.updated_metadata(&mut data); self.player_data.updated_metadata(&mut data);
if !data.is_empty() { if !data.is_empty() {
data.push(0xff); data.push(0xff);
@ -1007,7 +992,7 @@ impl Client {
metadata: RawBytes(data), metadata: RawBytes(data),
}); });
} }
self.player_meta.clear_modifications(); self.player_data.clear_modifications();
// Spawn new entities within the view distance. // Spawn new entities within the view distance.
let pos = self.position(); let pos = self.position();
@ -1031,29 +1016,24 @@ impl Client {
self.send_packet(meta); self.send_packet(meta);
} }
for &e in entity.events() { send_entity_events(&mut self.send, id, entity);
send_packet(
&mut self.send,
DoEntityEvent {
entity_id: id.to_network_id(),
entity_status: e,
},
);
}
} }
None None
}, },
); );
// Send entity events for the client's own player entity. for &code in self.player_data.event_codes() {
for event in self.entity_events.drain(..) { if code <= ENTITY_EVENT_MAX_BOUND as u8 {
send_packet( send_packet(
&mut self.send, &mut self.send,
DoEntityEvent { EntityEvent {
entity_id: 0, entity_id: 0,
entity_status: event, entity_status: BoundedInt(code),
}, },
); );
}
// Don't bother sending animations since it shouldn't be visible to
// the client.
} }
self.old_position = self.new_position; self.old_position = self.new_position;
@ -1061,7 +1041,9 @@ impl Client {
} }
} }
fn send_packet(send_opt: &mut Option<Sender<S2cPlayPacket>>, pkt: impl Into<S2cPlayPacket>) { type SendOpt = Option<Sender<S2cPlayPacket>>;
fn send_packet(send_opt: &mut SendOpt, pkt: impl Into<S2cPlayPacket>) {
if let Some(send) = send_opt { if let Some(send) = send_opt {
match send.try_send(pkt.into()) { match send.try_send(pkt.into()) {
Err(TrySendError::Full(_)) => { Err(TrySendError::Full(_)) => {
@ -1076,6 +1058,28 @@ fn send_packet(send_opt: &mut Option<Sender<S2cPlayPacket>>, pkt: impl Into<S2cP
} }
} }
fn send_entity_events(send_opt: &mut SendOpt, id: EntityId, entity: &Entity) {
for &code in entity.data().event_codes() {
if code <= ENTITY_EVENT_MAX_BOUND as u8 {
send_packet(
send_opt,
EntityEvent {
entity_id: id.to_network_id(),
entity_status: BoundedInt(code),
},
);
} else {
send_packet(
send_opt,
Animate {
entity_id: VarInt(id.to_network_id()),
animation: BoundedInt(code - ENTITY_EVENT_MAX_BOUND as u8 - 1),
},
)
}
}
}
fn make_dimension_codec(shared: &SharedServer) -> RegistryCodec { fn make_dimension_codec(shared: &SharedServer) -> RegistryCodec {
let mut dims = Vec::new(); let mut dims = Vec::new();
for (id, dim) in shared.dimensions() { for (id, dim) in shared.dimensions() {

View file

@ -1,5 +1,5 @@
pub mod data;
pub mod meta; pub mod meta;
pub mod types;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::collections::HashMap; use std::collections::HashMap;
@ -7,12 +7,11 @@ use std::iter::FusedIterator;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use bitfield_struct::bitfield; use bitfield_struct::bitfield;
pub use data::{EntityData, EntityType};
use rayon::iter::ParallelIterator; use rayon::iter::ParallelIterator;
pub use types::{EntityMeta, EntityType};
use uuid::Uuid; use uuid::Uuid;
use vek::{Aabb, Vec3}; use vek::{Aabb, Vec3};
pub use crate::protocol::packets::play::s2c::EntityEvent;
use crate::protocol::packets::play::s2c::{ use crate::protocol::packets::play::s2c::{
AddEntity, AddExperienceOrb, AddPlayer, S2cPlayPacket, SetEntityMetadata, AddEntity, AddExperienceOrb, AddPlayer, S2cPlayPacket, SetEntityMetadata,
}; };
@ -58,7 +57,7 @@ impl Entities {
Entry::Vacant(ve) => { Entry::Vacant(ve) => {
let (k, e) = self.sm.insert(Entity { let (k, e) = self.sm.insert(Entity {
flags: EntityFlags(0), flags: EntityFlags(0),
meta: EntityMeta::new(typ), data: EntityData::new(typ),
world: None, world: None,
new_position: Vec3::default(), new_position: Vec3::default(),
old_position: Vec3::default(), old_position: Vec3::default(),
@ -67,7 +66,6 @@ impl Entities {
head_yaw: 0.0, head_yaw: 0.0,
velocity: Vec3::default(), velocity: Vec3::default(),
uuid, uuid,
events: Vec::new(),
}); });
// TODO check for overflowing version? // TODO check for overflowing version?
@ -161,8 +159,7 @@ impl Entities {
pub(crate) fn update(&mut self) { pub(crate) fn update(&mut self) {
for (_, e) in self.iter_mut() { for (_, e) in self.iter_mut() {
e.old_position = e.new_position; e.old_position = e.new_position;
e.meta.clear_modifications(); e.data.clear_modifications();
e.events.clear();
e.flags.set_yaw_or_pitch_modified(false); e.flags.set_yaw_or_pitch_modified(false);
e.flags.set_head_yaw_modified(false); e.flags.set_head_yaw_modified(false);
@ -184,7 +181,7 @@ impl EntityId {
pub struct Entity { pub struct Entity {
flags: EntityFlags, flags: EntityFlags,
meta: EntityMeta, data: EntityData,
world: Option<WorldId>, world: Option<WorldId>,
new_position: Vec3<f64>, new_position: Vec3<f64>,
old_position: Vec3<f64>, old_position: Vec3<f64>,
@ -193,7 +190,6 @@ pub struct Entity {
head_yaw: f32, head_yaw: f32,
velocity: Vec3<f32>, velocity: Vec3<f32>,
uuid: Uuid, uuid: Uuid,
events: Vec<EntityEvent>,
} }
/// Contains a bit for certain fields in [`Entity`] to track if they have been /// Contains a bit for certain fields in [`Entity`] to track if they have been
@ -213,19 +209,19 @@ impl Entity {
self.flags self.flags
} }
/// Returns a reference to this entity's [`EntityMeta`]. /// Returns a reference to this entity's [`EntityData`].
pub fn meta(&self) -> &EntityMeta { pub fn data(&self) -> &EntityData {
&self.meta &self.data
} }
/// Returns a mutable reference to this entity's [`EntityMeta`]. /// Returns a mutable reference to this entity's [`EntityData`].
pub fn meta_mut(&mut self) -> &mut EntityMeta { pub fn data_mut(&mut self) -> &mut EntityData {
&mut self.meta &mut self.data
} }
/// Returns the [`EntityType`] of this entity. /// Returns the [`EntityType`] of this entity.
pub fn typ(&self) -> EntityType { pub fn typ(&self) -> EntityType {
self.meta.typ() self.data.typ()
} }
pub fn world(&self) -> Option<WorldId> { pub fn world(&self) -> Option<WorldId> {
@ -317,27 +313,19 @@ impl Entity {
self.uuid self.uuid
} }
pub fn push_event(&mut self, event: EntityEvent) {
self.events.push(event);
}
pub(crate) fn events(&self) -> &[EntityEvent] {
&self.events
}
pub fn hitbox(&self) -> Aabb<f64> { pub fn hitbox(&self) -> Aabb<f64> {
let dims = match &self.meta { let dims = match &self.data {
EntityMeta::Allay(_) => [0.6, 0.35, 0.6], EntityData::Allay(_) => [0.6, 0.35, 0.6],
EntityMeta::ChestBoat(_) => [1.375, 0.5625, 1.375], EntityData::ChestBoat(_) => [1.375, 0.5625, 1.375],
EntityMeta::Frog(_) => [0.5, 0.5, 0.5], EntityData::Frog(_) => [0.5, 0.5, 0.5],
EntityMeta::Tadpole(_) => [0.4, 0.3, 0.4], EntityData::Tadpole(_) => [0.4, 0.3, 0.4],
EntityMeta::Warden(_) => [0.9, 2.9, 0.9], EntityData::Warden(_) => [0.9, 2.9, 0.9],
EntityMeta::AreaEffectCloud(e) => [ EntityData::AreaEffectCloud(e) => [
e.get_radius() as f64 * 2.0, e.get_radius() as f64 * 2.0,
0.5, 0.5,
e.get_radius() as f64 * 2.0, e.get_radius() as f64 * 2.0,
], ],
EntityMeta::ArmorStand(e) => { EntityData::ArmorStand(e) => {
if e.get_marker() { if e.get_marker() {
[0.0, 0.0, 0.0] [0.0, 0.0, 0.0]
} else if e.get_small() { } else if e.get_small() {
@ -346,123 +334,123 @@ impl Entity {
[0.5, 1.975, 0.5] [0.5, 1.975, 0.5]
} }
} }
EntityMeta::Arrow(_) => [0.5, 0.5, 0.5], EntityData::Arrow(_) => [0.5, 0.5, 0.5],
EntityMeta::Axolotl(_) => [1.3, 0.6, 1.3], EntityData::Axolotl(_) => [1.3, 0.6, 1.3],
EntityMeta::Bat(_) => [0.5, 0.9, 0.5], EntityData::Bat(_) => [0.5, 0.9, 0.5],
EntityMeta::Bee(_) => [0.7, 0.6, 0.7], // TODO: baby size? EntityData::Bee(_) => [0.7, 0.6, 0.7], // TODO: baby size?
EntityMeta::Blaze(_) => [0.6, 1.8, 0.6], EntityData::Blaze(_) => [0.6, 1.8, 0.6],
EntityMeta::Boat(_) => [1.375, 0.5625, 1.375], EntityData::Boat(_) => [1.375, 0.5625, 1.375],
EntityMeta::Cat(_) => [0.6, 0.7, 0.6], EntityData::Cat(_) => [0.6, 0.7, 0.6],
EntityMeta::CaveSpider(_) => [0.7, 0.5, 0.7], EntityData::CaveSpider(_) => [0.7, 0.5, 0.7],
EntityMeta::Chicken(_) => [0.4, 0.7, 0.4], // TODO: baby size? EntityData::Chicken(_) => [0.4, 0.7, 0.4], // TODO: baby size?
EntityMeta::Cod(_) => [0.5, 0.3, 0.5], EntityData::Cod(_) => [0.5, 0.3, 0.5],
EntityMeta::Cow(_) => [0.9, 1.4, 0.9], // TODO: baby size? EntityData::Cow(_) => [0.9, 1.4, 0.9], // TODO: baby size?
EntityMeta::Creeper(_) => [0.6, 1.7, 0.6], EntityData::Creeper(_) => [0.6, 1.7, 0.6],
EntityMeta::Dolphin(_) => [0.9, 0.6, 0.9], EntityData::Dolphin(_) => [0.9, 0.6, 0.9],
EntityMeta::Donkey(_) => [1.5, 1.39648, 1.5], // TODO: baby size? EntityData::Donkey(_) => [1.5, 1.39648, 1.5], // TODO: baby size?
EntityMeta::DragonFireball(_) => [1.0, 1.0, 1.0], EntityData::DragonFireball(_) => [1.0, 1.0, 1.0],
EntityMeta::Drowned(_) => [0.6, 1.95, 0.6], // TODO: baby size? EntityData::Drowned(_) => [0.6, 1.95, 0.6], // TODO: baby size?
EntityMeta::ElderGuardian(_) => [1.9975, 1.9975, 1.9975], EntityData::ElderGuardian(_) => [1.9975, 1.9975, 1.9975],
EntityMeta::EndCrystal(_) => [2.0, 2.0, 2.0], EntityData::EndCrystal(_) => [2.0, 2.0, 2.0],
EntityMeta::EnderDragon(_) => [16.0, 8.0, 16.0], EntityData::EnderDragon(_) => [16.0, 8.0, 16.0],
EntityMeta::Enderman(_) => [0.6, 2.9, 0.6], EntityData::Enderman(_) => [0.6, 2.9, 0.6],
EntityMeta::Endermite(_) => [0.4, 0.3, 0.4], EntityData::Endermite(_) => [0.4, 0.3, 0.4],
EntityMeta::Evoker(_) => [0.6, 1.95, 0.6], EntityData::Evoker(_) => [0.6, 1.95, 0.6],
EntityMeta::EvokerFangs(_) => [0.5, 0.8, 0.5], EntityData::EvokerFangs(_) => [0.5, 0.8, 0.5],
EntityMeta::ExperienceOrb(_) => [0.5, 0.5, 0.5], EntityData::ExperienceOrb(_) => [0.5, 0.5, 0.5],
EntityMeta::EyeOfEnder(_) => [0.25, 0.25, 0.25], EntityData::EyeOfEnder(_) => [0.25, 0.25, 0.25],
EntityMeta::FallingBlock(_) => [0.98, 0.98, 0.98], EntityData::FallingBlock(_) => [0.98, 0.98, 0.98],
EntityMeta::FireworkRocket(_) => [0.25, 0.25, 0.25], EntityData::FireworkRocket(_) => [0.25, 0.25, 0.25],
EntityMeta::Fox(_) => [0.6, 0.7, 0.6], // TODO: baby size? EntityData::Fox(_) => [0.6, 0.7, 0.6], // TODO: baby size?
EntityMeta::Ghast(_) => [4.0, 4.0, 4.0], EntityData::Ghast(_) => [4.0, 4.0, 4.0],
EntityMeta::Giant(_) => [3.6, 12.0, 3.6], EntityData::Giant(_) => [3.6, 12.0, 3.6],
EntityMeta::GlowItemFrame(_) => todo!("account for rotation"), EntityData::GlowItemFrame(_) => todo!("account for rotation"),
EntityMeta::GlowSquid(_) => [0.8, 0.8, 0.8], EntityData::GlowSquid(_) => [0.8, 0.8, 0.8],
EntityMeta::Goat(_) => [1.3, 0.9, 1.3], // TODO: baby size? EntityData::Goat(_) => [1.3, 0.9, 1.3], // TODO: baby size?
EntityMeta::Guardian(_) => [0.85, 0.85, 0.85], EntityData::Guardian(_) => [0.85, 0.85, 0.85],
EntityMeta::Hoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size? EntityData::Hoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size?
EntityMeta::Horse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size? EntityData::Horse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
EntityMeta::Husk(_) => [0.6, 1.95, 0.6], // TODO: baby size? EntityData::Husk(_) => [0.6, 1.95, 0.6], // TODO: baby size?
EntityMeta::Illusioner(_) => [0.6, 1.95, 0.6], EntityData::Illusioner(_) => [0.6, 1.95, 0.6],
EntityMeta::IronGolem(_) => [1.4, 2.7, 1.4], EntityData::IronGolem(_) => [1.4, 2.7, 1.4],
EntityMeta::Item(_) => [0.25, 0.25, 0.25], EntityData::Item(_) => [0.25, 0.25, 0.25],
EntityMeta::ItemFrame(_) => todo!("account for rotation"), EntityData::ItemFrame(_) => todo!("account for rotation"),
EntityMeta::Fireball(_) => [1.0, 1.0, 1.0], EntityData::Fireball(_) => [1.0, 1.0, 1.0],
EntityMeta::LeashKnot(_) => [0.375, 0.5, 0.375], EntityData::LeashKnot(_) => [0.375, 0.5, 0.375],
EntityMeta::LightningBolt(_) => [0.0, 0.0, 0.0], EntityData::LightningBolt(_) => [0.0, 0.0, 0.0],
EntityMeta::Llama(_) => [0.9, 1.87, 0.9], // TODO: baby size? EntityData::Llama(_) => [0.9, 1.87, 0.9], // TODO: baby size?
EntityMeta::LlamaSpit(_) => [0.25, 0.25, 0.25], EntityData::LlamaSpit(_) => [0.25, 0.25, 0.25],
EntityMeta::MagmaCube(e) => { EntityData::MagmaCube(e) => {
let s = e.get_size() as f64 * 0.51000005; let s = e.get_size() as f64 * 0.51000005;
[s, s, s] [s, s, s]
} }
EntityMeta::Marker(_) => [0.0, 0.0, 0.0], EntityData::Marker(_) => [0.0, 0.0, 0.0],
EntityMeta::Minecart(_) => [0.98, 0.7, 0.98], EntityData::Minecart(_) => [0.98, 0.7, 0.98],
EntityMeta::ChestMinecart(_) => [0.98, 0.7, 0.98], EntityData::ChestMinecart(_) => [0.98, 0.7, 0.98],
EntityMeta::CommandBlockMinecart(_) => [0.98, 0.7, 0.98], EntityData::CommandBlockMinecart(_) => [0.98, 0.7, 0.98],
EntityMeta::FurnaceMinecart(_) => [0.98, 0.7, 0.98], EntityData::FurnaceMinecart(_) => [0.98, 0.7, 0.98],
EntityMeta::HopperMinecart(_) => [0.98, 0.7, 0.98], EntityData::HopperMinecart(_) => [0.98, 0.7, 0.98],
EntityMeta::SpawnerMinecart(_) => [0.98, 0.7, 0.98], EntityData::SpawnerMinecart(_) => [0.98, 0.7, 0.98],
EntityMeta::TntMinecart(_) => [0.98, 0.7, 0.98], EntityData::TntMinecart(_) => [0.98, 0.7, 0.98],
EntityMeta::Mule(_) => [1.39648, 1.6, 1.39648], // TODO: baby size? EntityData::Mule(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
EntityMeta::Mooshroom(_) => [0.9, 1.4, 0.9], // TODO: baby size? EntityData::Mooshroom(_) => [0.9, 1.4, 0.9], // TODO: baby size?
EntityMeta::Ocelot(_) => [0.6, 0.7, 0.6], // TODO: baby size? EntityData::Ocelot(_) => [0.6, 0.7, 0.6], // TODO: baby size?
EntityMeta::Painting(_) => todo!("account for rotation and type"), EntityData::Painting(_) => todo!("account for rotation and type"),
EntityMeta::Panda(_) => [0.6, 0.7, 0.6], // TODO: baby size? EntityData::Panda(_) => [0.6, 0.7, 0.6], // TODO: baby size?
EntityMeta::Parrot(_) => [0.5, 0.9, 0.5], EntityData::Parrot(_) => [0.5, 0.9, 0.5],
EntityMeta::Phantom(_) => [0.9, 0.5, 0.9], EntityData::Phantom(_) => [0.9, 0.5, 0.9],
EntityMeta::Pig(_) => [0.9, 0.9, 0.9], // TODO: baby size? EntityData::Pig(_) => [0.9, 0.9, 0.9], // TODO: baby size?
EntityMeta::Piglin(_) => [0.6, 1.95, 0.6], // TODO: baby size? EntityData::Piglin(_) => [0.6, 1.95, 0.6], // TODO: baby size?
EntityMeta::PiglinBrute(_) => [0.6, 1.95, 0.6], EntityData::PiglinBrute(_) => [0.6, 1.95, 0.6],
EntityMeta::Pillager(_) => [0.6, 1.95, 0.6], EntityData::Pillager(_) => [0.6, 1.95, 0.6],
EntityMeta::PolarBear(_) => [1.4, 1.4, 1.4], // TODO: baby size? EntityData::PolarBear(_) => [1.4, 1.4, 1.4], // TODO: baby size?
EntityMeta::Tnt(_) => [0.98, 0.98, 0.98], EntityData::Tnt(_) => [0.98, 0.98, 0.98],
EntityMeta::Pufferfish(_) => [0.7, 0.7, 0.7], EntityData::Pufferfish(_) => [0.7, 0.7, 0.7],
EntityMeta::Rabbit(_) => [0.4, 0.5, 0.4], // TODO: baby size? EntityData::Rabbit(_) => [0.4, 0.5, 0.4], // TODO: baby size?
EntityMeta::Ravager(_) => [1.95, 2.2, 1.95], EntityData::Ravager(_) => [1.95, 2.2, 1.95],
EntityMeta::Salmon(_) => [0.7, 0.4, 0.7], EntityData::Salmon(_) => [0.7, 0.4, 0.7],
EntityMeta::Sheep(_) => [0.9, 1.3, 0.9], // TODO: baby size? EntityData::Sheep(_) => [0.9, 1.3, 0.9], // TODO: baby size?
EntityMeta::Shulker(_) => [1.0, 1.0, 1.0], // TODO: how is height calculated? EntityData::Shulker(_) => [1.0, 1.0, 1.0], // TODO: how is height calculated?
EntityMeta::ShulkerBullet(_) => [0.3125, 0.3125, 0.3125], EntityData::ShulkerBullet(_) => [0.3125, 0.3125, 0.3125],
EntityMeta::Silverfish(_) => [0.4, 0.3, 0.4], EntityData::Silverfish(_) => [0.4, 0.3, 0.4],
EntityMeta::Skeleton(_) => [0.6, 1.99, 0.6], EntityData::Skeleton(_) => [0.6, 1.99, 0.6],
EntityMeta::SkeletonHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size? EntityData::SkeletonHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
EntityMeta::Slime(e) => { EntityData::Slime(e) => {
let s = 0.51000005 * e.get_size() as f64; let s = 0.51000005 * e.get_size() as f64;
[s, s, s] [s, s, s]
} }
EntityMeta::SmallFireball(_) => [0.3125, 0.3125, 0.3125], EntityData::SmallFireball(_) => [0.3125, 0.3125, 0.3125],
EntityMeta::SnowGolem(_) => [0.7, 1.9, 0.7], EntityData::SnowGolem(_) => [0.7, 1.9, 0.7],
EntityMeta::Snowball(_) => [0.25, 0.25, 0.25], EntityData::Snowball(_) => [0.25, 0.25, 0.25],
EntityMeta::SpectralArrow(_) => [0.5, 0.5, 0.5], EntityData::SpectralArrow(_) => [0.5, 0.5, 0.5],
EntityMeta::Spider(_) => [1.4, 0.9, 1.4], EntityData::Spider(_) => [1.4, 0.9, 1.4],
EntityMeta::Squid(_) => [0.8, 0.8, 0.8], EntityData::Squid(_) => [0.8, 0.8, 0.8],
EntityMeta::Stray(_) => [0.6, 1.99, 0.6], EntityData::Stray(_) => [0.6, 1.99, 0.6],
EntityMeta::Strider(_) => [0.9, 1.7, 0.9], // TODO: baby size? EntityData::Strider(_) => [0.9, 1.7, 0.9], // TODO: baby size?
EntityMeta::Egg(_) => [0.25, 0.25, 0.25], EntityData::Egg(_) => [0.25, 0.25, 0.25],
EntityMeta::EnderPearl(_) => [0.25, 0.25, 0.25], EntityData::EnderPearl(_) => [0.25, 0.25, 0.25],
EntityMeta::ExperienceBottle(_) => [0.25, 0.25, 0.25], EntityData::ExperienceBottle(_) => [0.25, 0.25, 0.25],
EntityMeta::Potion(_) => [0.25, 0.25, 0.25], EntityData::Potion(_) => [0.25, 0.25, 0.25],
EntityMeta::Trident(_) => [0.5, 0.5, 0.5], EntityData::Trident(_) => [0.5, 0.5, 0.5],
EntityMeta::TraderLlama(_) => [0.9, 1.87, 0.9], EntityData::TraderLlama(_) => [0.9, 1.87, 0.9],
EntityMeta::TropicalFish(_) => [0.5, 0.4, 0.5], EntityData::TropicalFish(_) => [0.5, 0.4, 0.5],
EntityMeta::Turtle(_) => [1.2, 0.4, 1.2], // TODO: baby size? EntityData::Turtle(_) => [1.2, 0.4, 1.2], // TODO: baby size?
EntityMeta::Vex(_) => [0.4, 0.8, 0.4], EntityData::Vex(_) => [0.4, 0.8, 0.4],
EntityMeta::Villager(_) => [0.6, 1.95, 0.6], // TODO: baby size? EntityData::Villager(_) => [0.6, 1.95, 0.6], // TODO: baby size?
EntityMeta::Vindicator(_) => [0.6, 1.95, 0.6], EntityData::Vindicator(_) => [0.6, 1.95, 0.6],
EntityMeta::WanderingTrader(_) => [0.6, 1.95, 0.6], EntityData::WanderingTrader(_) => [0.6, 1.95, 0.6],
EntityMeta::Witch(_) => [0.6, 1.95, 0.6], EntityData::Witch(_) => [0.6, 1.95, 0.6],
EntityMeta::Wither(_) => [0.9, 3.5, 0.9], EntityData::Wither(_) => [0.9, 3.5, 0.9],
EntityMeta::WitherSkeleton(_) => [0.7, 2.4, 0.7], EntityData::WitherSkeleton(_) => [0.7, 2.4, 0.7],
EntityMeta::WitherSkull(_) => [0.3125, 0.3125, 0.3125], EntityData::WitherSkull(_) => [0.3125, 0.3125, 0.3125],
EntityMeta::Wolf(_) => [0.6, 0.85, 0.6], // TODO: baby size? EntityData::Wolf(_) => [0.6, 0.85, 0.6], // TODO: baby size?
EntityMeta::Zoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size? EntityData::Zoglin(_) => [1.39648, 1.4, 1.39648], // TODO: baby size?
EntityMeta::Zombie(_) => [0.6, 1.95, 0.6], // TODO: baby size? EntityData::Zombie(_) => [0.6, 1.95, 0.6], // TODO: baby size?
EntityMeta::ZombieHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size? EntityData::ZombieHorse(_) => [1.39648, 1.6, 1.39648], // TODO: baby size?
EntityMeta::ZombieVillager(_) => [0.6, 1.95, 0.6], // TODO: baby size? EntityData::ZombieVillager(_) => [0.6, 1.95, 0.6], // TODO: baby size?
EntityMeta::ZombifiedPiglin(_) => [0.6, 1.95, 0.6], // TODO: baby size? EntityData::ZombifiedPiglin(_) => [0.6, 1.95, 0.6], // TODO: baby size?
EntityMeta::Player(_) => [0.6, 1.8, 0.6], // TODO: changes depending on the pose. EntityData::Player(_) => [0.6, 1.8, 0.6], // TODO: changes depending on the pose.
EntityMeta::FishingBobber(_) => [0.25, 0.25, 0.25], EntityData::FishingBobber(_) => [0.25, 0.25, 0.25],
}; };
aabb_from_bottom_and_size(self.new_position, dims.into()) aabb_from_bottom_and_size(self.new_position, dims.into())
@ -473,7 +461,7 @@ impl Entity {
/// ///
/// Is `None` if there is no initial metadata. /// Is `None` if there is no initial metadata.
pub(crate) fn initial_metadata_packet(&self, this_id: EntityId) -> Option<SetEntityMetadata> { pub(crate) fn initial_metadata_packet(&self, this_id: EntityId) -> Option<SetEntityMetadata> {
self.meta.initial_metadata().map(|meta| SetEntityMetadata { self.data.initial_metadata().map(|meta| SetEntityMetadata {
entity_id: VarInt(this_id.to_network_id()), entity_id: VarInt(this_id.to_network_id()),
metadata: RawBytes(meta), metadata: RawBytes(meta),
}) })
@ -483,23 +471,23 @@ impl Entity {
/// ///
/// Is `None` if this entity's metadata has not been modified. /// Is `None` if this entity's metadata has not been modified.
pub(crate) fn updated_metadata_packet(&self, this_id: EntityId) -> Option<SetEntityMetadata> { pub(crate) fn updated_metadata_packet(&self, this_id: EntityId) -> Option<SetEntityMetadata> {
self.meta.updated_metadata().map(|meta| SetEntityMetadata { self.data.updated_metadata().map(|meta| SetEntityMetadata {
entity_id: VarInt(this_id.to_network_id()), entity_id: VarInt(this_id.to_network_id()),
metadata: RawBytes(meta), metadata: RawBytes(meta),
}) })
} }
pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option<EntitySpawnPacket> { pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option<EntitySpawnPacket> {
match &self.meta { match &self.data {
EntityMeta::Marker(_) => None, EntityData::Marker(_) => None,
EntityMeta::ExperienceOrb(_) => { EntityData::ExperienceOrb(_) => {
Some(EntitySpawnPacket::SpawnExperienceOrb(AddExperienceOrb { Some(EntitySpawnPacket::SpawnExperienceOrb(AddExperienceOrb {
entity_id: VarInt(this_id.to_network_id()), entity_id: VarInt(this_id.to_network_id()),
position: self.new_position, position: self.new_position,
count: 0, // TODO count: 0, // TODO
})) }))
} }
EntityMeta::Player(_) => Some(EntitySpawnPacket::SpawnPlayer(AddPlayer { EntityData::Player(_) => Some(EntitySpawnPacket::SpawnPlayer(AddPlayer {
entity_id: VarInt(this_id.to_network_id()), entity_id: VarInt(this_id.to_network_id()),
player_uuid: self.uuid, player_uuid: self.uuid,
position: self.new_position, position: self.new_position,

View file

@ -272,6 +272,16 @@ impl Decode for Box<str> {
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct BoundedInt<T, const MIN: i64, const MAX: i64>(pub T); pub struct BoundedInt<T, const MIN: i64, const MAX: i64>(pub T);
impl<T, const MIN: i64, const MAX: i64> BoundedInt<T, MIN, MAX> {
pub const fn min_bound(&self) -> i64 {
MIN
}
pub const fn max_bound(&self) -> i64 {
MAX
}
}
impl<T, const MIN: i64, const MAX: i64> From<T> for BoundedInt<T, MIN, MAX> { impl<T, const MIN: i64, const MAX: i64> From<T> for BoundedInt<T, MIN, MAX> {
fn from(t: T) -> Self { fn from(t: T) -> Self {
Self(t) Self(t)
@ -334,6 +344,16 @@ impl Decode for String {
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash, Debug)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash, Debug)]
pub struct BoundedString<const MIN: usize, const MAX: usize>(pub String); pub struct BoundedString<const MIN: usize, const MAX: usize>(pub String);
impl<const MIN: usize, const MAX: usize> BoundedString<MIN, MAX> {
pub const fn min_bound(&self) -> usize {
MIN
}
pub const fn max_bound(&self) -> usize {
MAX
}
}
impl<const MIN: usize, const MAX: usize> Encode for BoundedString<MIN, MAX> { impl<const MIN: usize, const MAX: usize> Encode for BoundedString<MIN, MAX> {
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> { fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
encode_string_bounded(&self.0, MIN, MAX, w) encode_string_bounded(&self.0, MIN, MAX, w)

View file

@ -619,18 +619,7 @@ pub mod play {
def_struct! { def_struct! {
Animate 0x03 { Animate 0x03 {
entity_id: VarInt, entity_id: VarInt,
animation: Animation, animation: BoundedInt<u8, 0, 5>,
}
}
def_enum! {
Animation: u8 {
SwingMainArm = 0,
TakeDamage = 1,
LeaveBed = 2,
SwingOffhand = 3,
CriticalEffect = 4,
MagicCriticalEffect = 5,
} }
} }
@ -741,78 +730,12 @@ pub mod play {
} }
} }
def_struct! { pub const ENTITY_EVENT_MAX_BOUND: i64 = 62;
DoEntityEvent 0x18 {
entity_id: i32,
entity_status: EntityEvent,
}
}
def_enum! { def_struct! {
#[derive(Copy, PartialEq, Eq)] EntityEvent 0x18 {
EntityEvent: u8 { entity_id: i32,
Jump = 1, entity_status: BoundedInt<u8, 1, ENTITY_EVENT_MAX_BOUND>,
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,
} }
} }
@ -1294,7 +1217,7 @@ pub mod play {
BlockUpdate, BlockUpdate,
BossEvent, BossEvent,
Disconnect, Disconnect,
DoEntityEvent, EntityEvent,
ForgetLevelChunk, ForgetLevelChunk,
GameEvent, GameEvent,
KeepAlive, KeepAlive,