2022-04-29 17:48:41 +10:00
|
|
|
pub mod meta;
|
|
|
|
pub mod types;
|
|
|
|
|
2022-04-15 07:55:45 +10:00
|
|
|
use std::collections::hash_map::Entry;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::iter::FusedIterator;
|
2022-05-16 19:36:14 +10:00
|
|
|
use std::ops::Deref;
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
use bitfield_struct::bitfield;
|
2022-04-29 17:48:41 +10:00
|
|
|
use rayon::iter::ParallelIterator;
|
2022-04-15 07:55:45 +10:00
|
|
|
use uuid::Uuid;
|
2022-05-16 21:09:51 +10:00
|
|
|
use vek::{Aabb, Vec3};
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
use crate::byte_angle::ByteAngle;
|
|
|
|
use crate::packets::play::{
|
|
|
|
ClientPlayPacket, EntityMetadata, SpawnEntity, SpawnExperienceOrb, SpawnLivingEntity,
|
|
|
|
SpawnPainting, SpawnPlayer,
|
|
|
|
};
|
|
|
|
use crate::protocol::ReadToEnd;
|
2022-04-29 17:48:41 +10:00
|
|
|
use crate::slotmap::{Key, SlotMap};
|
2022-05-16 21:09:51 +10:00
|
|
|
use crate::util::aabb_from_bottom_and_size;
|
2022-05-16 19:36:14 +10:00
|
|
|
use crate::var_int::VarInt;
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub struct Entities {
|
2022-04-29 17:48:41 +10:00
|
|
|
sm: SlotMap<Entity>,
|
2022-04-15 07:55:45 +10:00
|
|
|
uuid_to_entity: HashMap<Uuid, EntityId>,
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub struct EntitiesMut<'a>(&'a mut Entities);
|
2022-04-29 17:48:41 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
impl<'a> Deref for EntitiesMut<'a> {
|
|
|
|
type Target = Entities;
|
2022-04-29 17:48:41 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
self.0
|
2022-04-29 17:48:41 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
impl Entities {
|
|
|
|
pub(crate) fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
sm: SlotMap::new(),
|
|
|
|
uuid_to_entity: HashMap::new(),
|
|
|
|
}
|
2022-04-29 17:48:41 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Returns the number of live entities.
|
|
|
|
pub fn count(&self) -> usize {
|
|
|
|
self.sm.count()
|
2022-04-29 17:48:41 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Gets the [`EntityId`] of the entity with the given UUID in an efficient
|
|
|
|
/// manner.
|
|
|
|
///
|
|
|
|
/// Returns `None` if there is no entity with the provided UUID. Returns
|
|
|
|
/// `Some` otherwise.
|
|
|
|
pub fn get_with_uuid(&self, uuid: Uuid) -> Option<EntityId> {
|
|
|
|
self.uuid_to_entity.get(&uuid).cloned()
|
2022-04-29 17:48:41 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub fn get(&self, entity: EntityId) -> Option<&Entity> {
|
|
|
|
self.sm.get(entity.0)
|
2022-04-29 17:48:41 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub fn iter(&self) -> impl FusedIterator<Item = (EntityId, &Entity)> + Clone + '_ {
|
|
|
|
self.sm.iter().map(|(k, v)| (EntityId(k), v))
|
|
|
|
}
|
2022-04-29 17:48:41 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub fn par_iter(&self) -> impl ParallelIterator<Item = (EntityId, &Entity)> + Clone + '_ {
|
|
|
|
self.sm.par_iter().map(|(k, v)| (EntityId(k), v))
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
2022-05-16 19:36:14 +10:00
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
impl<'a> EntitiesMut<'a> {
|
|
|
|
pub(crate) fn new(entities: &'a mut Entities) -> Self {
|
|
|
|
Self(entities)
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Spawns a new entity with the default data. The new entity's [`EntityId`]
|
2022-04-29 17:48:41 +10:00
|
|
|
/// is returned.
|
|
|
|
///
|
|
|
|
/// To actually see the new entity, set its position to somewhere nearby and
|
2022-05-16 19:36:14 +10:00
|
|
|
/// [set its type](EntityData::set_type) to something visible.
|
2022-04-29 17:48:41 +10:00
|
|
|
pub fn create(&mut self) -> EntityId {
|
2022-04-15 07:55:45 +10:00
|
|
|
loop {
|
|
|
|
let uuid = Uuid::from_bytes(rand::random());
|
2022-04-29 17:48:41 +10:00
|
|
|
if let Some(entity) = self.create_with_uuid(uuid) {
|
|
|
|
return entity;
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Like [`create`](Entities::create), but requires specifying the new
|
|
|
|
/// entity's UUID. This is useful for deserialization.
|
|
|
|
///
|
2022-05-16 19:36:14 +10:00
|
|
|
/// The provided UUID must not conflict with an existing entity UUID in this
|
|
|
|
/// world. If it does, `None` is returned and the entity is not spawned.
|
2022-04-29 17:48:41 +10:00
|
|
|
pub fn create_with_uuid(&mut self, uuid: Uuid) -> Option<EntityId> {
|
2022-05-16 19:36:14 +10:00
|
|
|
match self.0.uuid_to_entity.entry(uuid) {
|
2022-04-15 07:55:45 +10:00
|
|
|
Entry::Occupied(_) => None,
|
|
|
|
Entry::Vacant(ve) => {
|
2022-05-16 19:36:14 +10:00
|
|
|
let entity = EntityId(self.0.sm.insert(Entity {
|
|
|
|
flags: EntityFlags(0),
|
|
|
|
meta: EntityMeta::new(EntityType::Marker),
|
2022-05-16 21:09:51 +10:00
|
|
|
new_position: Vec3::default(),
|
|
|
|
old_position: Vec3::default(),
|
2022-05-16 19:36:14 +10:00
|
|
|
yaw: 0.0,
|
|
|
|
pitch: 0.0,
|
|
|
|
head_yaw: 0.0,
|
|
|
|
head_pitch: 0.0,
|
|
|
|
velocity: Vec3::default(),
|
2022-04-29 17:48:41 +10:00
|
|
|
uuid,
|
|
|
|
}));
|
2022-04-15 07:55:45 +10:00
|
|
|
|
|
|
|
ve.insert(entity);
|
|
|
|
|
2022-04-29 17:48:41 +10:00
|
|
|
// TODO: insert into partition.
|
2022-04-15 07:55:45 +10:00
|
|
|
|
|
|
|
Some(entity)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-29 17:48:41 +10:00
|
|
|
pub fn delete(&mut self, entity: EntityId) -> bool {
|
2022-05-16 19:36:14 +10:00
|
|
|
if let Some(e) = self.0.sm.remove(entity.0) {
|
|
|
|
self.0
|
|
|
|
.uuid_to_entity
|
2022-04-29 17:48:41 +10:00
|
|
|
.remove(&e.uuid)
|
2022-04-15 07:55:45 +10:00
|
|
|
.expect("UUID should have been in UUID map");
|
|
|
|
|
2022-04-29 17:48:41 +10:00
|
|
|
// TODO: remove entity from partition.
|
2022-04-15 07:55:45 +10:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub fn retain(&mut self, mut f: impl FnMut(EntityId, EntityMut) -> bool) {
|
|
|
|
// TODO
|
|
|
|
self.0.sm.retain(|k, v| f(EntityId(k), EntityMut(v)))
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub fn get_mut(&mut self, entity: EntityId) -> Option<EntityMut> {
|
|
|
|
self.0.sm.get_mut(entity.0).map(EntityMut)
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub fn iter_mut(&mut self) -> impl FusedIterator<Item = (EntityId, EntityMut)> + '_ {
|
|
|
|
self.0
|
|
|
|
.sm
|
|
|
|
.iter_mut()
|
|
|
|
.map(|(k, v)| (EntityId(k), EntityMut(v)))
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = (EntityId, EntityMut)> + '_ {
|
|
|
|
self.0
|
|
|
|
.sm
|
|
|
|
.par_iter_mut()
|
|
|
|
.map(|(k, v)| (EntityId(k), EntityMut(v)))
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub(crate) fn update(&mut self) {
|
|
|
|
for (_, e) in self.iter_mut() {
|
|
|
|
e.0.old_position = e.new_position;
|
|
|
|
e.0.meta.clear_modifications();
|
|
|
|
e.0.flags = EntityFlags(0);
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
2022-05-16 19:36:14 +10:00
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
|
|
|
pub struct EntityId(Key);
|
|
|
|
|
|
|
|
impl EntityId {
|
|
|
|
pub(crate) fn to_network_id(self) -> i32 {
|
|
|
|
// TODO: is ID 0 reserved?
|
|
|
|
self.0.index() as i32
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
2022-05-16 19:36:14 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Entity {
|
|
|
|
flags: EntityFlags,
|
|
|
|
meta: EntityMeta,
|
2022-05-16 21:09:51 +10:00
|
|
|
new_position: Vec3<f64>,
|
|
|
|
old_position: Vec3<f64>,
|
2022-05-16 19:36:14 +10:00
|
|
|
yaw: f32,
|
|
|
|
pitch: f32,
|
|
|
|
head_yaw: f32,
|
|
|
|
head_pitch: f32,
|
2022-05-16 21:09:51 +10:00
|
|
|
velocity: Vec3<f32>,
|
2022-05-16 19:36:14 +10:00
|
|
|
uuid: Uuid,
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub struct EntityMut<'a>(&'a mut Entity);
|
|
|
|
|
|
|
|
impl<'a> Deref for EntityMut<'a> {
|
|
|
|
type Target = Entity;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
self.0
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
2022-05-16 19:36:14 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Contains a bit for certain fields in [`Entity`] to track if they have been
|
|
|
|
/// modified.
|
|
|
|
#[bitfield(u8)]
|
|
|
|
pub(crate) struct EntityFlags {
|
|
|
|
meta_modified: bool,
|
|
|
|
yaw_or_pitch_modified: bool,
|
|
|
|
head_yaw_modified: bool,
|
|
|
|
head_pitch_modified: bool,
|
|
|
|
velocity_modified: bool,
|
|
|
|
#[bits(3)]
|
|
|
|
_pad: u8,
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
impl Entity {
|
|
|
|
pub(crate) fn flags(&self) -> EntityFlags {
|
|
|
|
self.flags
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Returns a reference to this entity's [`EntityMeta`].
|
|
|
|
pub fn meta(&self) -> &EntityMeta {
|
|
|
|
&self.meta
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Returns the [`EntityType`] of this entity.
|
|
|
|
pub fn typ(&self) -> EntityType {
|
|
|
|
self.meta.typ()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the position of this entity in the world it inhabits.
|
2022-05-16 21:09:51 +10:00
|
|
|
pub fn position(&self) -> Vec3<f64> {
|
2022-05-16 19:36:14 +10:00
|
|
|
self.new_position
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the position of this entity as it existed at the end of the
|
|
|
|
/// previous tick.
|
2022-05-16 21:09:51 +10:00
|
|
|
pub fn old_position(&self) -> Vec3<f64> {
|
2022-05-16 19:36:14 +10:00
|
|
|
self.old_position
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the yaw of this entity (in degrees).
|
|
|
|
pub fn yaw(&self) -> f32 {
|
|
|
|
self.yaw
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the pitch of this entity (in degrees).
|
|
|
|
pub fn pitch(&self) -> f32 {
|
|
|
|
self.pitch
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the head yaw of this entity (in degrees).
|
|
|
|
pub fn head_yaw(&self) -> f32 {
|
|
|
|
self.head_yaw
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the head pitch of this entity (in degrees).
|
|
|
|
pub fn head_pitch(&self) -> f32 {
|
|
|
|
self.head_pitch
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the velocity of this entity in meters per second.
|
2022-05-16 21:09:51 +10:00
|
|
|
pub fn velocity(&self) -> Vec3<f32> {
|
2022-05-16 19:36:14 +10:00
|
|
|
self.velocity
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the metadata packet to send to clients after this entity has been
|
|
|
|
/// spawned.
|
|
|
|
///
|
|
|
|
/// Is `None` if there is no initial metadata.
|
|
|
|
pub(crate) fn initial_metadata_packet(&self, this_id: EntityId) -> Option<EntityMetadata> {
|
|
|
|
self.meta.initial_metadata().map(|meta| EntityMetadata {
|
|
|
|
entity_id: VarInt(this_id.to_network_id()),
|
|
|
|
metadata: ReadToEnd(meta),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the metadata packet to send to clients when the entity is modified.
|
|
|
|
///
|
|
|
|
/// Is `None` if this entity's metadata has not been modified.
|
|
|
|
pub(crate) fn updated_metadata_packet(&self, this_id: EntityId) -> Option<EntityMetadata> {
|
|
|
|
self.meta.updated_metadata().map(|meta| EntityMetadata {
|
|
|
|
entity_id: VarInt(this_id.to_network_id()),
|
|
|
|
metadata: ReadToEnd(meta),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn spawn_packet(&self, this_id: EntityId) -> Option<EntitySpawnPacket> {
|
|
|
|
use EntityMeta::*;
|
|
|
|
match &self.meta {
|
|
|
|
Marker(_) => None,
|
|
|
|
ExperienceOrb(_) => Some(EntitySpawnPacket::SpawnExperienceOrb(SpawnExperienceOrb {
|
|
|
|
entity_id: VarInt(this_id.to_network_id()),
|
|
|
|
position: self.new_position,
|
|
|
|
count: 0, // TODO
|
|
|
|
})),
|
|
|
|
Painting(_) => todo!(),
|
|
|
|
Player(_) => todo!(),
|
|
|
|
AreaEffectCloud(_)
|
|
|
|
| Arrow(_)
|
|
|
|
| Boat(_)
|
|
|
|
| DragonFireball(_)
|
|
|
|
| EndCrystal(_)
|
|
|
|
| EvokerFangs(_)
|
|
|
|
| EyeOfEnder(_)
|
|
|
|
| FallingBlock(_)
|
|
|
|
| FireworkRocket(_)
|
|
|
|
| GlowItemFrame(_)
|
|
|
|
| Item(_)
|
|
|
|
| ItemFrame(_)
|
|
|
|
| Fireball(_)
|
|
|
|
| LeashKnot(_)
|
|
|
|
| LightningBolt(_)
|
|
|
|
| LlamaSpit(_)
|
|
|
|
| Minecart(_)
|
|
|
|
| ChestMinecart(_)
|
|
|
|
| CommandBlockMinecart(_)
|
|
|
|
| FurnaceMinecart(_)
|
|
|
|
| HopperMinecart(_)
|
|
|
|
| SpawnerMinecart(_)
|
|
|
|
| TntMinecart(_)
|
|
|
|
| Tnt(_)
|
|
|
|
| ShulkerBullet(_)
|
|
|
|
| SmallFireball(_)
|
|
|
|
| Snowball(_)
|
|
|
|
| SpectralArrow(_)
|
|
|
|
| Egg(_)
|
|
|
|
| EnderPearl(_)
|
|
|
|
| ExperienceBottle(_)
|
|
|
|
| Potion(_)
|
|
|
|
| Trident(_)
|
|
|
|
| WitherSkull(_)
|
|
|
|
| FishingBobber(_) => Some(EntitySpawnPacket::SpawnEntity(SpawnEntity {
|
|
|
|
entity_id: VarInt(this_id.to_network_id()),
|
|
|
|
object_uuid: self.uuid,
|
|
|
|
typ: VarInt(self.typ() as i32),
|
|
|
|
position: self.new_position,
|
|
|
|
pitch: ByteAngle::from_degrees(self.pitch),
|
|
|
|
yaw: ByteAngle::from_degrees(self.yaw),
|
|
|
|
data: 1, // TODO
|
|
|
|
velocity: velocity_to_packet_units(self.velocity),
|
|
|
|
})),
|
|
|
|
|
|
|
|
ArmorStand(_) | Axolotl(_) | Bat(_) | Bee(_) | Blaze(_) | Cat(_) | CaveSpider(_)
|
|
|
|
| Chicken(_) | Cod(_) | Cow(_) | Creeper(_) | Dolphin(_) | Donkey(_) | Drowned(_)
|
|
|
|
| ElderGuardian(_) | EnderDragon(_) | Enderman(_) | Endermite(_) | Evoker(_)
|
|
|
|
| Fox(_) | Ghast(_) | Giant(_) | GlowSquid(_) | Goat(_) | Guardian(_) | Hoglin(_)
|
|
|
|
| Horse(_) | Husk(_) | Illusioner(_) | IronGolem(_) | Llama(_) | MagmaCube(_)
|
|
|
|
| Mule(_) | Mooshroom(_) | Ocelot(_) | Panda(_) | Parrot(_) | Phantom(_) | Pig(_)
|
|
|
|
| Piglin(_) | PiglinBrute(_) | Pillager(_) | PolarBear(_) | Pufferfish(_)
|
|
|
|
| Rabbit(_) | Ravager(_) | Salmon(_) | Sheep(_) | Shulker(_) | Silverfish(_)
|
|
|
|
| Skeleton(_) | SkeletonHorse(_) | Slime(_) | SnowGolem(_) | Spider(_) | Squid(_)
|
|
|
|
| Stray(_) | Strider(_) | TraderLlama(_) | TropicalFish(_) | Turtle(_) | Vex(_)
|
|
|
|
| Villager(_) | Vindicator(_) | WanderingTrader(_) | Witch(_) | Wither(_)
|
|
|
|
| WitherSkeleton(_) | Wolf(_) | Zoglin(_) | Zombie(_) | ZombieHorse(_)
|
|
|
|
| ZombieVillager(_) | ZombifiedPiglin(_) => {
|
|
|
|
Some(EntitySpawnPacket::SpawnLivingEntity(SpawnLivingEntity {
|
|
|
|
entity_id: VarInt(this_id.to_network_id()),
|
|
|
|
entity_uuid: self.uuid,
|
|
|
|
typ: VarInt(self.typ() as i32),
|
|
|
|
position: self.new_position,
|
|
|
|
yaw: ByteAngle::from_degrees(self.yaw),
|
|
|
|
pitch: ByteAngle::from_degrees(self.pitch),
|
|
|
|
head_pitch: ByteAngle::from_degrees(self.head_pitch),
|
|
|
|
velocity: velocity_to_packet_units(self.velocity),
|
|
|
|
}))
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 21:09:51 +10:00
|
|
|
pub fn hitbox(&self) -> Aabb<f64> {
|
2022-05-16 19:36:14 +10:00
|
|
|
let dims = match &self.meta {
|
|
|
|
EntityMeta::AreaEffectCloud(e) => [
|
|
|
|
e.get_radius() as f64 * 2.0,
|
|
|
|
0.5,
|
|
|
|
e.get_radius() as f64 * 2.0,
|
|
|
|
],
|
|
|
|
EntityMeta::ArmorStand(e) => {
|
|
|
|
if e.get_marker() {
|
|
|
|
[0.0, 0.0, 0.0]
|
|
|
|
} else if e.get_small() {
|
|
|
|
[0.5, 0.9875, 0.5]
|
|
|
|
} else {
|
|
|
|
[0.5, 1.975, 0.5]
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
2022-05-16 19:36:14 +10:00
|
|
|
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(e) => [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) => {
|
|
|
|
let s = e.get_size() as f64 * 0.51000005;
|
|
|
|
[s, s, s]
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
2022-05-16 19:36:14 +10:00
|
|
|
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) => {
|
|
|
|
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],
|
|
|
|
};
|
|
|
|
|
2022-05-16 21:09:51 +10:00
|
|
|
aabb_from_bottom_and_size(self.new_position, dims.into())
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
2022-05-16 19:36:14 +10:00
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 21:09:51 +10:00
|
|
|
fn velocity_to_packet_units(vel: Vec3<f32>) -> Vec3<i16> {
|
2022-05-16 19:36:14 +10:00
|
|
|
// The saturating cast to i16 is desirable.
|
2022-05-16 21:09:51 +10:00
|
|
|
(vel * 400.0).as_()
|
2022-05-16 19:36:14 +10:00
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
impl<'a> EntityMut<'a> {
|
|
|
|
// TODO: exposing &mut EntityMeta is unsound?
|
|
|
|
/// Returns a mutable reference to this entity's [`EntityMeta`].
|
|
|
|
///
|
|
|
|
/// **NOTE:** Never call [`std::mem::swap`] on the returned reference or any
|
|
|
|
/// part of `EntityMeta` as this would break invariants within the
|
|
|
|
/// library.
|
|
|
|
pub fn meta_mut(&mut self) -> &mut EntityMeta {
|
|
|
|
&mut self.0.meta
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Changes the [`EntityType`] of this entity to the provided type.
|
|
|
|
///
|
|
|
|
/// All metadata of this entity is reset to the default values.
|
|
|
|
pub fn set_type(&mut self, typ: EntityType) {
|
|
|
|
self.0.meta = EntityMeta::new(typ);
|
|
|
|
// All metadata is lost, so we must mark it as modified unconditionally.
|
|
|
|
self.0.flags.set_meta_modified(true);
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Sets the position of this entity in the world it inhabits.
|
2022-05-16 21:09:51 +10:00
|
|
|
pub fn set_position(&mut self, pos: impl Into<Vec3<f64>>) {
|
2022-05-16 19:36:14 +10:00
|
|
|
self.0.new_position = pos.into();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the yaw of this entity (in degrees).
|
|
|
|
pub fn set_yaw(&mut self, yaw: f32) {
|
|
|
|
self.0.yaw = yaw;
|
|
|
|
if ByteAngle::from_degrees(self.yaw) != ByteAngle::from_degrees(yaw) {
|
|
|
|
self.0.flags.set_yaw_or_pitch_modified(true);
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Sets the pitch of this entity (in degrees).
|
|
|
|
pub fn set_pitch(&mut self, pitch: f32) {
|
|
|
|
self.0.pitch = pitch;
|
|
|
|
if ByteAngle::from_degrees(self.pitch) != ByteAngle::from_degrees(pitch) {
|
|
|
|
self.0.flags.set_yaw_or_pitch_modified(true);
|
|
|
|
}
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Sets the head yaw of this entity (in degrees).
|
|
|
|
pub fn set_head_yaw(&mut self, head_yaw: f32) {
|
|
|
|
self.0.head_yaw = head_yaw;
|
|
|
|
if ByteAngle::from_degrees(self.head_yaw) != ByteAngle::from_degrees(head_yaw) {
|
|
|
|
self.0.flags.set_head_yaw_modified(true);
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
/// Sets the head pitch of this entity (in degrees).
|
|
|
|
pub fn set_head_pitch(&mut self, head_pitch: f32) {
|
|
|
|
self.0.head_pitch = head_pitch;
|
|
|
|
if ByteAngle::from_degrees(self.head_pitch) != ByteAngle::from_degrees(head_pitch) {
|
|
|
|
self.0.flags.set_head_pitch_modified(true);
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
|
2022-05-16 21:09:51 +10:00
|
|
|
pub fn set_velocity(&mut self, velocity: impl Into<Vec3<f32>>) {
|
|
|
|
let new_vel = velocity.into();
|
|
|
|
self.0.velocity = new_vel;
|
|
|
|
if velocity_to_packet_units(self.velocity) != velocity_to_packet_units(new_vel) {
|
2022-05-16 19:36:14 +10:00
|
|
|
self.0.flags.set_velocity_modified(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) enum EntitySpawnPacket {
|
|
|
|
SpawnEntity(SpawnEntity),
|
|
|
|
SpawnExperienceOrb(SpawnExperienceOrb),
|
|
|
|
SpawnLivingEntity(SpawnLivingEntity),
|
|
|
|
SpawnPainting(SpawnPainting),
|
|
|
|
SpawnPlayer(SpawnPlayer),
|
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
impl From<EntitySpawnPacket> for ClientPlayPacket {
|
|
|
|
fn from(pkt: EntitySpawnPacket) -> Self {
|
|
|
|
match pkt {
|
|
|
|
EntitySpawnPacket::SpawnEntity(pkt) => pkt.into(),
|
|
|
|
EntitySpawnPacket::SpawnExperienceOrb(pkt) => pkt.into(),
|
|
|
|
EntitySpawnPacket::SpawnLivingEntity(pkt) => pkt.into(),
|
|
|
|
EntitySpawnPacket::SpawnPainting(pkt) => pkt.into(),
|
|
|
|
EntitySpawnPacket::SpawnPlayer(pkt) => pkt.into(),
|
2022-04-29 17:48:41 +10:00
|
|
|
}
|
2022-04-15 07:55:45 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:36:14 +10:00
|
|
|
pub use types::{EntityMeta, EntityType};
|