mirror of
https://github.com/italicsjenga/valence.git
synced 2024-12-23 22:41:30 +11:00
153cde1a04
The current approach to managing chunk data is misconceived. This new approach uses genuine paletted containers and does not suffer from complexities caused by caching. As a result, memory usage (according to htop) in the terrain example with render distance = 32 has gone from 785 megs to 137 megs. That's 17.4% of the memory it used to use. Terrain generation speed was not affected.
157 lines
5 KiB
Rust
157 lines
5 KiB
Rust
//! A space on a server for objects to occupy.
|
|
|
|
use std::iter::FusedIterator;
|
|
|
|
use rayon::iter::ParallelIterator;
|
|
|
|
use crate::chunk::Chunks;
|
|
use crate::config::Config;
|
|
use crate::dimension::DimensionId;
|
|
use crate::server::SharedServer;
|
|
use crate::slab_versioned::{Key, VersionedSlab};
|
|
use crate::spatial_index::SpatialIndex;
|
|
|
|
/// A container for all [`World`]s on a [`Server`](crate::server::Server).
|
|
pub struct Worlds<C: Config> {
|
|
slab: VersionedSlab<World<C>>,
|
|
shared: SharedServer<C>,
|
|
}
|
|
|
|
/// An identifier for a [`World`] on the server.
|
|
///
|
|
/// World IDs are either _valid_ or _invalid_. Valid world IDs point to
|
|
/// worlds that have not been deleted, while invalid IDs point to those that
|
|
/// have. Once an ID becomes invalid, it will never become valid again.
|
|
///
|
|
/// The [`Ord`] instance on this type is correct but otherwise unspecified. This
|
|
/// is useful for storing IDs in containers such as
|
|
/// [`BTreeMap`](std::collections::BTreeMap).
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
|
|
pub struct WorldId(Key);
|
|
|
|
impl WorldId {
|
|
/// The value of the default world ID which is always invalid.
|
|
pub const NULL: Self = Self(Key::NULL);
|
|
}
|
|
|
|
impl<C: Config> Worlds<C> {
|
|
pub(crate) fn new(shared: SharedServer<C>) -> Self {
|
|
Self {
|
|
slab: VersionedSlab::new(),
|
|
shared,
|
|
}
|
|
}
|
|
|
|
/// Creates a new world on the server with the provided dimension. A
|
|
/// reference to the world along with its ID is returned.
|
|
pub fn insert(
|
|
&mut self,
|
|
dimension: DimensionId,
|
|
state: C::WorldState,
|
|
) -> (WorldId, &mut World<C>) {
|
|
let dim = self.shared.dimension(dimension);
|
|
|
|
let (id, world) = self.slab.insert(World {
|
|
state,
|
|
spatial_index: SpatialIndex::new(),
|
|
chunks: Chunks::new(dim.height, dim.min_y),
|
|
meta: WorldMeta { dimension },
|
|
});
|
|
|
|
(WorldId(id), world)
|
|
}
|
|
|
|
/// Deletes a world from the server.
|
|
///
|
|
/// Note that any entities located in the world are not deleted.
|
|
/// Additionally, clients that are still in the deleted world at the end
|
|
/// of the tick are disconnected.
|
|
///
|
|
/// Returns `true` if the world was deleted. Otherwise, `false` is returned
|
|
/// and the function has no effect.
|
|
pub fn remove(&mut self, world: WorldId) -> bool {
|
|
self.slab.remove(world.0).is_some()
|
|
}
|
|
|
|
/// Removes all worlds from the server for which `f` returns `false`.
|
|
///
|
|
/// All worlds are visited in an unspecified order.
|
|
pub fn retain(&mut self, mut f: impl FnMut(WorldId, &mut World<C>) -> bool) {
|
|
self.slab.retain(|k, v| f(WorldId(k), v))
|
|
}
|
|
|
|
/// Returns the number of worlds on the server.
|
|
pub fn len(&self) -> usize {
|
|
self.slab.len()
|
|
}
|
|
|
|
/// Returns `true` if there are no worlds on the server.
|
|
pub fn is_empty(&self) -> bool {
|
|
self.slab.len() == 0
|
|
}
|
|
|
|
/// Returns a shared reference to the world with the given ID. If
|
|
/// the ID is invalid, then `None` is returned.
|
|
pub fn get(&self, world: WorldId) -> Option<&World<C>> {
|
|
self.slab.get(world.0)
|
|
}
|
|
|
|
/// Returns an exclusive reference to the world with the given ID. If the
|
|
/// ID is invalid, then `None` is returned.
|
|
pub fn get_mut(&mut self, world: WorldId) -> Option<&mut World<C>> {
|
|
self.slab.get_mut(world.0)
|
|
}
|
|
|
|
/// Returns an iterator over all worlds on the server in an unspecified
|
|
/// order.
|
|
pub fn iter(
|
|
&self,
|
|
) -> impl ExactSizeIterator<Item = (WorldId, &World<C>)> + FusedIterator + Clone + '_ {
|
|
self.slab.iter().map(|(k, v)| (WorldId(k), v))
|
|
}
|
|
|
|
/// Returns a mutable iterator over all worlds on the server in an
|
|
/// unspecified order.
|
|
pub fn iter_mut(
|
|
&mut self,
|
|
) -> impl ExactSizeIterator<Item = (WorldId, &mut World<C>)> + FusedIterator + '_ {
|
|
self.slab.iter_mut().map(|(k, v)| (WorldId(k), v))
|
|
}
|
|
|
|
/// Returns a parallel iterator over all worlds on the server in an
|
|
/// unspecified order.
|
|
pub fn par_iter(&self) -> impl ParallelIterator<Item = (WorldId, &World<C>)> + Clone + '_ {
|
|
self.slab.par_iter().map(|(k, v)| (WorldId(k), v))
|
|
}
|
|
|
|
/// Returns a parallel mutable iterator over all worlds on the server in an
|
|
/// unspecified order.
|
|
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = (WorldId, &mut World<C>)> + '_ {
|
|
self.slab.par_iter_mut().map(|(k, v)| (WorldId(k), v))
|
|
}
|
|
}
|
|
|
|
/// A space for chunks, entities, and clients to occupy.
|
|
pub struct World<C: Config> {
|
|
/// Custom state.
|
|
pub state: C::WorldState,
|
|
/// Contains all of the entities in this world.
|
|
pub spatial_index: SpatialIndex,
|
|
/// All of the chunks in this world.
|
|
pub chunks: Chunks<C>,
|
|
/// This world's metadata.
|
|
pub meta: WorldMeta,
|
|
}
|
|
|
|
/// Contains miscellaneous data about the world.
|
|
pub struct WorldMeta {
|
|
dimension: DimensionId,
|
|
}
|
|
|
|
impl WorldMeta {
|
|
/// Gets the dimension the world was created with.
|
|
pub fn dimension(&self) -> DimensionId {
|
|
self.dimension
|
|
}
|
|
}
|