Skip to main content

azalea_core/
entity_id.rs

1use std::{
2    fmt::{self, Display},
3    hash::{Hash, Hasher},
4    io::{self, Cursor},
5};
6
7use azalea_buf::{AzBuf, AzBufVar, BufReadError};
8use derive_more::{Deref, DerefMut};
9
10// note: this is here instead of in azalea-entity because azalea-world depends
11// on it. and this isn't in azalea-world so azalea-protocol doesn't need to
12// depend on azalea-world.
13
14/// An entity ID used by Minecraft.
15///
16/// These IDs are picked by the server. Some server software (like Bungeecord)
17/// may pick entity IDs per-player, so you should avoid relying on them for
18/// identifying IDs (especially if you're using a shared world -- i.e. a swarm).
19///
20/// You might find [`Entity`] more useful, since that's an ID decided by us that
21/// is likely to be correct across shared worlds. You could also use the
22/// `EntityUuid` from `azalea_entity`, that one is unlikely to change even
23/// across server restarts.
24///
25/// This serializes as a i32. Usually it's a VarInt in the protocol, but not
26/// always. If you do need it to serialize as a VarInt, make sure to use use the
27/// `#[var]` attribute.
28///
29/// [`Entity`]: bevy_ecs::entity::Entity
30#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
31#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
32#[derive(Clone, Copy, Debug, Default, Deref, DerefMut, Eq, PartialEq)]
33pub struct MinecraftEntityId(pub i32);
34
35impl Hash for MinecraftEntityId {
36    fn hash<H: Hasher>(&self, hasher: &mut H) {
37        hasher.write_i32(self.0);
38    }
39}
40impl nohash_hasher::IsEnabled for MinecraftEntityId {}
41
42// we can't have the default be #[var] because mojang doesn't use varints for
43// entities sometimes :(
44impl AzBuf for MinecraftEntityId {
45    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
46        i32::azalea_read(buf).map(MinecraftEntityId)
47    }
48    fn azalea_write(&self, buf: &mut impl io::Write) -> io::Result<()> {
49        i32::azalea_write(&self.0, buf)
50    }
51}
52impl AzBufVar for MinecraftEntityId {
53    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
54        i32::azalea_read_var(buf).map(MinecraftEntityId)
55    }
56    fn azalea_write_var(&self, buf: &mut impl io::Write) -> io::Result<()> {
57        i32::azalea_write_var(&self.0, buf)
58    }
59}
60impl Display for MinecraftEntityId {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        write!(f, "eid({})", self.0)
63    }
64}
65impl From<i32> for MinecraftEntityId {
66    fn from(id: i32) -> Self {
67        Self(id)
68    }
69}
70impl From<u32> for MinecraftEntityId {
71    fn from(id: u32) -> Self {
72        Self(id as i32)
73    }
74}
75
76/// An entity ID that might not be present.
77///
78/// This is encoded as a single varint, where `None` is `0` and `Some` is
79/// written as `id-1`.
80#[derive(Clone, Debug, PartialEq)]
81pub struct OptionalEntityId(pub Option<MinecraftEntityId>);
82impl AzBuf for OptionalEntityId {
83    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
84        match i32::azalea_read_var(buf)? {
85            0 => Ok(OptionalEntityId(None)),
86            id => Ok(OptionalEntityId(Some(MinecraftEntityId(id - 1)))),
87        }
88    }
89    fn azalea_write(&self, buf: &mut impl io::Write) -> io::Result<()> {
90        match self.0 {
91            Some(id) => (id.0 + 1).azalea_write_var(buf),
92            None => 0u32.azalea_write_var(buf),
93        }
94    }
95}