azalea_world/
world.rs

1use std::fmt::{self, Display, Formatter};
2use std::hash::{Hash, Hasher};
3use std::io::{self, Cursor};
4use std::{
5    collections::{HashMap, HashSet},
6    fmt::Debug,
7};
8
9use azalea_block::BlockState;
10use azalea_block::fluid_state::FluidState;
11use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
12use azalea_core::position::{BlockPos, ChunkPos};
13use azalea_core::registry_holder::RegistryHolder;
14use bevy_ecs::{component::Component, entity::Entity};
15use derive_more::{Deref, DerefMut};
16use nohash_hasher::IntMap;
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19
20use crate::{ChunkStorage, PartialChunkStorage};
21
22/// PartialInstances are usually owned by clients, and hold strong references to
23/// chunks and entities in [`Instance`]s.
24///
25/// Basically, they hold the chunks and entities that are within render
26/// distance but can still access chunks and entities owned by other
27/// `PartialInstance`s that have the same `Instance`.
28///
29/// This is primarily useful for having multiple clients in the same Instance.
30pub struct PartialInstance {
31    pub chunks: PartialChunkStorage,
32    /// Some metadata about entities, like what entities are in certain chunks.
33    /// This does not contain the entity data itself, that's in the ECS.
34    pub entity_infos: PartialEntityInfos,
35}
36
37impl PartialInstance {
38    pub fn new(chunk_radius: u32, owner_entity: Option<Entity>) -> Self {
39        PartialInstance {
40            chunks: PartialChunkStorage::new(chunk_radius),
41            entity_infos: PartialEntityInfos::new(owner_entity),
42        }
43    }
44
45    /// Clears the internal references to chunks in the PartialInstance and
46    /// resets the view center.
47    pub fn reset(&mut self) {
48        self.chunks = PartialChunkStorage::new(self.chunks.chunk_radius);
49    }
50}
51
52/// An entity ID used by Minecraft.
53///
54/// These IDs are picked by the server. Some server softwares (like Bungeecord)
55/// may pick entity IDs per-player, so you should avoid relying on them for
56/// identifying IDs (especially if you're using a shared world -- i.e. a swarm).
57///
58/// You might find [`Entity`] more useful, since that's an ID decided by us that
59/// is likely to be correct across shared worlds. You could also use the
60/// `EntityUuid` from `azalea_entity`, that one is unlikely to change even
61/// across server restarts.
62///
63/// This serializes as a i32. Usually it's a VarInt in the protocol, but not
64/// always. If you do need it to serialize as a VarInt, make sure to use use the
65/// `#[var]` attribute.
66///
67/// [`Entity`]: bevy_ecs::entity::Entity
68#[derive(Component, Copy, Clone, Debug, Default, PartialEq, Eq, Deref, DerefMut)]
69#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
70pub struct MinecraftEntityId(pub i32);
71
72impl Hash for MinecraftEntityId {
73    fn hash<H: Hasher>(&self, hasher: &mut H) {
74        hasher.write_i32(self.0);
75    }
76}
77impl nohash_hasher::IsEnabled for MinecraftEntityId {}
78
79// we can't have the default be #[var] because mojang doesn't use varints for
80// entities sometimes :(
81impl AzaleaRead for MinecraftEntityId {
82    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
83        i32::azalea_read(buf).map(MinecraftEntityId)
84    }
85}
86impl AzaleaWrite for MinecraftEntityId {
87    fn azalea_write(&self, buf: &mut impl io::Write) -> Result<(), io::Error> {
88        i32::azalea_write(&self.0, buf)
89    }
90}
91impl AzaleaReadVar for MinecraftEntityId {
92    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
93        i32::azalea_read_var(buf).map(MinecraftEntityId)
94    }
95}
96impl AzaleaWriteVar for MinecraftEntityId {
97    fn azalea_write_var(&self, buf: &mut impl io::Write) -> Result<(), io::Error> {
98        i32::azalea_write_var(&self.0, buf)
99    }
100}
101impl Display for MinecraftEntityId {
102    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
103        write!(f, "eid({})", self.0)
104    }
105}
106impl From<i32> for MinecraftEntityId {
107    fn from(id: i32) -> Self {
108        Self(id)
109    }
110}
111impl From<u32> for MinecraftEntityId {
112    fn from(id: u32) -> Self {
113        Self(id as i32)
114    }
115}
116
117/// Keep track of certain metadatas that are only relevant for this partial
118/// world.
119#[derive(Debug, Default)]
120pub struct PartialEntityInfos {
121    // note: using MinecraftEntityId for entity ids is acceptable here since
122    // there's no chance of collisions here
123    /// The entity id of the player that owns this partial world. This will
124    /// make `RelativeEntityUpdate` pretend this entity doesn't exist so
125    /// it doesn't get modified from outside sources.
126    pub owner_entity: Option<Entity>,
127    /// A counter for each entity that tracks how many updates we've observed
128    /// for it.
129    ///
130    /// This is used for shared worlds (i.e. swarms), to make sure we don't
131    /// update entities twice on accident.
132    pub updates_received: IntMap<MinecraftEntityId, u32>,
133}
134
135impl PartialEntityInfos {
136    pub fn new(owner_entity: Option<Entity>) -> Self {
137        Self {
138            owner_entity,
139            updates_received: IntMap::default(),
140        }
141    }
142}
143
144/// A world where the chunks are stored as weak pointers. This is used for
145/// shared worlds.
146#[derive(Default, Debug)]
147pub struct Instance {
148    pub chunks: ChunkStorage,
149
150    /// An index of all the entities we know are in the chunks of the world
151    pub entities_by_chunk: HashMap<ChunkPos, HashSet<Entity>>,
152
153    /// An index of Minecraft entity IDs to Azalea ECS entities.
154    ///
155    /// You should avoid using this (particularly if you're using swarms) and
156    /// instead use `azalea_entity::EntityIdIndex`, since some servers may
157    /// give different entity IDs for the same entities to different
158    /// players.
159    pub entity_by_id: IntMap<MinecraftEntityId, Entity>,
160
161    pub registries: RegistryHolder,
162}
163
164impl Instance {
165    pub fn get_block_state(&self, pos: &BlockPos) -> Option<BlockState> {
166        self.chunks.get_block_state(pos)
167    }
168
169    pub fn get_fluid_state(&self, pos: &BlockPos) -> Option<FluidState> {
170        self.chunks.get_block_state(pos).map(FluidState::from)
171    }
172
173    pub fn set_block_state(&self, pos: &BlockPos, state: BlockState) -> Option<BlockState> {
174        self.chunks.set_block_state(pos, state)
175    }
176}
177
178impl Debug for PartialInstance {
179    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
180        f.debug_struct("PartialInstance")
181            .field("chunks", &self.chunks)
182            .field("entity_infos", &self.entity_infos)
183            .finish()
184    }
185}
186
187impl Default for PartialInstance {
188    /// Creates a completely self-contained `PartialInstance`. This is only for
189    /// testing and shouldn't be used in actual code!
190    fn default() -> Self {
191        let chunk_storage = PartialChunkStorage::default();
192        let entity_storage = PartialEntityInfos::default();
193        Self {
194            chunks: chunk_storage,
195            entity_infos: entity_storage,
196        }
197    }
198}
199
200impl From<ChunkStorage> for Instance {
201    /// Make an empty world from this `ChunkStorage`. This is meant to be a
202    /// convenience function for tests.
203    fn from(chunks: ChunkStorage) -> Self {
204        Self {
205            chunks,
206            entities_by_chunk: HashMap::new(),
207            entity_by_id: IntMap::default(),
208            registries: RegistryHolder::default(),
209        }
210    }
211}