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::config::{Config, ServerListPing};
use valence::entity::meta::Pose;
use valence::entity::EntityMeta;
use valence::entity::EntityData;
use valence::text::Color;
use valence::{
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());
}
ClientEvent::StartSneaking => {
if let EntityMeta::Player(e) = player.meta_mut() {
if let EntityData::Player(e) = player.data_mut() {
e.set_crouching(true);
e.set_pose(Pose::Sneaking);
}
}
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_crouching(false);
}
}
ClientEvent::StartSprinting => {
if let EntityMeta::Player(e) = player.meta_mut() {
if let EntityData::Player(e) = player.data_mut() {
e.set_sprinting(true);
}
}
ClientEvent::StopSprinting => {
if let EntityMeta::Player(e) = player.meta_mut() {
if let EntityData::Player(e) = player.data_mut() {
e.set_sprinting(false);
}
}
ClientEvent::ArmSwing(_) => {
if let EntityMeta::Player(_) = player.meta_mut() {
// TODO: swing arm.
if let EntityData::Player(e) = player.data_mut() {
e.trigger_swing_main_arm();
}
}
_ => {}

View file

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

View file

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

View file

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