Skip to content

Commit

Permalink
bimap palettes
Browse files Browse the repository at this point in the history
  • Loading branch information
JieningYu committed Aug 18, 2023
1 parent 2b67a64 commit 3aea2a9
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[workspace]
[workspace]
resolver = "2"
members = ["core"]
1 change: 1 addition & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ lazy-regex = "2"
cesu8 = "*"
hashbrown = "0.14"
dashmap = "5.4"
bimap = "0.6"
6 changes: 3 additions & 3 deletions core/src/world/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{block, fluid, prelude::*, util::math::ChunkPos};

use super::{biome, palette};

pub trait Chunk<'w>: super::BlockView + super::LightSourceView + std::any::Any {
pub trait Chunk<'w>: super::Blocks + super::LightSources + std::any::Any {
fn pos(&self) -> ChunkPos;

fn sections(&self) -> &[Option<Section<'w>>];
Expand Down Expand Up @@ -37,7 +37,7 @@ pub trait Chunk<'w>: super::BlockView + super::LightSourceView + std::any::Any {

pub struct WorldChunk<'w> {
sections: Vec<Section<'w>>,
height_limit_view: *const dyn super::HeightLimitView,
height_limit_view: *const dyn super::HeightLimit,
}

mod chunk_imp {
Expand Down Expand Up @@ -219,7 +219,7 @@ pub struct UpgradeData {
impl UpgradeData {
const INDICES_KEY: &str = "Indices";

pub fn new(nbt: &crate::nbt::NbtCompound, world: &impl super::HeightLimitView) -> Self {
pub fn new(nbt: &crate::nbt::NbtCompound, world: &impl super::HeightLimit) -> Self {
let mut this = Self {
sides_to_upgrade: Vec::new(),
block_ticks: Vec::new(),
Expand Down
6 changes: 3 additions & 3 deletions core/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod tick;
use crate::prelude::*;

/// A view with a height limit specification.
pub trait HeightLimitView {
pub trait HeightLimit {
/// The difference in the [`Self::bottom_y`] and [`Self::top_y`] height.
///
/// This is the number of blocks that can be modified in any vertical column
Expand Down Expand Up @@ -38,7 +38,7 @@ pub trait HeightLimitView {

/// Represents a scoped, read-only view of block states,
/// fluid states and block entities.
pub trait BlockView: HeightLimitView {
pub trait Blocks: HeightLimit {
/// Default max light level in Rimecraft.
const DEFAULT_MAX_LIGHT_LEVEL: u8 = 15;

Expand All @@ -52,7 +52,7 @@ pub trait BlockView: HeightLimitView {
}

/// Represents a view describing lights.
pub trait LightSourceView: BlockView {
pub trait LightSources: Blocks {
/// Perform for each light sources in this view.
fn for_each_sources<T: Fn(BlockPos, &crate::block::BlockState)>(&self, f: T);
}
Expand Down
112 changes: 97 additions & 15 deletions core/src/world/palette.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::hash::Hash;

use crate::net::{Decode, Encode};

/// A palette maps objects from and to small integer IDs that uses less
Expand All @@ -6,12 +8,18 @@ use crate::net::{Decode, Encode};
/// While the objects palettes handle are already represented by integer
/// IDs, shrinking IDs in cases where only a few appear can further reduce
/// storage space and network traffic volume.
pub struct Palette<'a, T: PartialEq + Eq + Copy + 'a> {
pub struct Palette<'a, T>
where
T: Eq + Copy + Hash + 'a,
{
ids: crate::Ref<'a, dyn crate::collections::Indexed<T> + Send + Sync>,
inner: Inner<'a, T>,
}

impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
impl<'a, T> Palette<'a, T>
where
T: Eq + Copy + Hash + 'a,
{
/// Returns the ID of an object in this palette.
pub fn index(&self, value: T) -> Option<usize> {
match &self.inner {
Expand All @@ -22,6 +30,7 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
Inner::Singular(option) => option
.map(|e| if e == value { Some(0) } else { None })
.flatten(),
Inner::BiMap(bimap) => bimap.get_by_right(&value).copied(),
}
}

Expand All @@ -41,6 +50,11 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
*option = Some(value);
0
}
Inner::BiMap(bimap) => bimap.get_by_right(&value).copied().unwrap_or_else(|| {
let id = bimap.len();
bimap.insert(id, value);
id
}),
})
}

Expand All @@ -53,6 +67,7 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
Inner::Vector(vec) => vec.iter().any(|e| e.map_or(false, |ee| predicate(ee))),
Inner::Indexed(_) => true,
Inner::Singular(option) => predicate(option.expect("use of an uninitialized palette")),
Inner::BiMap(bimap) => bimap.iter().any(|entry| predicate(*entry.1)),
}
}

Expand All @@ -68,6 +83,13 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
panic!("missing palette entry for id {index}")
}
}
Inner::BiMap(bimap) => {
if let Some(value) = bimap.get_by_left(&index) {
Some(*value)
} else {
panic!("missing palette entry for id {index}")
}
}
}
}

Expand Down Expand Up @@ -101,6 +123,20 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
})?,
);
}
Inner::BiMap(bimap) => {
*bimap = {
let mut map = bimap::BiMap::new();

for j in 0..crate::VarInt::decode(buf)? {
map.insert(
map.len(),
*self.ids.get(crate::VarInt::decode(buf)? as usize).unwrap(),
);
}

map
}
}
}

Ok(())
Expand Down Expand Up @@ -145,6 +181,15 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
panic!("use of an uninitialized palette");
}
}
Inner::BiMap(bimap) => {
let i = self.len();
crate::VarInt(i as i32).encode(buf)?;

for entry in bimap.iter() {
crate::VarInt(self.ids.get_raw_id(entry.1).map(|e| e as i32).unwrap_or(-1))
.encode(buf)?;
}
}
}

Ok(())
Expand Down Expand Up @@ -186,6 +231,18 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
panic!("use of an uninitialized palette");
}
}
Inner::BiMap(bimap) => {
crate::VarInt(self.len() as i32).len()
+ bimap
.iter()
.map(|entry| {
crate::VarInt(
self.ids.get_raw_id(entry.1).map(|e| e as i32).unwrap_or(-1),
)
.len()
})
.sum::<usize>()
}
}
}

Expand All @@ -195,11 +252,15 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Palette<'a, T> {
Inner::Vector(vec) => vec.len(),
Inner::Indexed(ids) => ids.len(),
Inner::Singular(_) => 1,
Inner::BiMap(bimap) => bimap.len(),
}
}
}

impl<'a, T: 'a + PartialEq + Eq + Copy> Encode for Palette<'a, T> {
impl<'a, T> Encode for Palette<'a, T>
where
T: Eq + Copy + Hash + 'a,
{
fn encode<B>(&self, buf: &mut B) -> anyhow::Result<()>
where
B: bytes::BufMut,
Expand All @@ -208,7 +269,10 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Encode for Palette<'a, T> {
}
}

impl<'a, T: 'a + PartialEq + Eq + Copy> Clone for Palette<'a, T> {
impl<'a, T> Clone for Palette<'a, T>
where
T: Eq + Copy + Hash + 'a,
{
fn clone(&self) -> Self {
Self {
ids: self.ids,
Expand All @@ -217,18 +281,26 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Clone for Palette<'a, T> {
}
}

enum Inner<'a, T: 'a + Copy> {
enum Inner<'a, T>
where
T: Eq + Copy + Hash + 'a,
{
Indexed(crate::Ref<'a, dyn crate::collections::Indexed<T> + Send + Sync>),
Vector(Vec<Option<T>>),
Singular(Option<T>),
BiMap(bimap::BiMap<usize, T>),
}

impl<'a, T: 'a + Copy> Clone for Inner<'a, T> {
impl<'a, T> Clone for Inner<'a, T>
where
T: Eq + Copy + Hash + 'a,
{
fn clone(&self) -> Self {
match self {
Inner::Vector(vec) => Self::Vector(vec.clone()),
Inner::Indexed(ids) => Self::Indexed(*ids),
Inner::Vector(vec) => Self::Vector(vec.clone()),
Inner::Singular(value) => Self::Singular(*value),
Inner::BiMap(bimap) => Self::BiMap(bimap.clone()),
}
}
}
Expand All @@ -248,7 +320,7 @@ impl Variant {
entries: Vec<A>,
) -> Palette<'a, A>
where
A: 'a + PartialEq + Eq + Copy,
A: Eq + Copy + Hash + 'a,
{
match self {
Variant::Indexed => Palette {
Expand Down Expand Up @@ -279,7 +351,7 @@ pub type Storage = crate::collections::PackedArray;

struct Data<'a, T: 'a>(DataProvider, Storage, Palette<'a, T>)
where
T: PartialEq + Eq + Copy;
T: Eq + Copy + Hash;

#[derive(Clone, Copy, PartialEq, Eq)]
struct DataProvider(Variant, usize);
Expand All @@ -291,7 +363,7 @@ impl DataProvider {
len: usize,
) -> Data<'a, T>
where
T: 'a + PartialEq + Eq + Copy,
T: Eq + Copy + Hash,
{
Data(
self,
Expand All @@ -305,6 +377,7 @@ impl DataProvider {
}
}

//TODO: don't make this an enum
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Provider {
BlockState,
Expand Down Expand Up @@ -356,11 +429,14 @@ impl Provider {

/// A paletted container stores objects in 3D voxels as small integer indices,
/// governed by "palettes" that map between these objects and indices.
pub struct Container<'a, T>(parking_lot::RwLock<ContainerInner<'a, T>>)
pub struct Container<'a, T: 'a>(parking_lot::RwLock<ContainerInner<'a, T>>)
where
T: 'a + PartialEq + Eq + Copy;
T: Eq + Copy + Hash;

impl<'a, T: 'a + PartialEq + Eq + Copy> Container<'a, T> {
impl<'a, T: 'a> Container<'a, T>
where
T: Eq + Copy + Hash,
{
pub fn new(
ids: &'a (dyn crate::collections::Indexed<T> + Send + Sync),
provider: Provider,
Expand Down Expand Up @@ -514,13 +590,19 @@ impl<'a, T: 'a + PartialEq + Eq + Copy> Container<'a, T> {
}
}

struct ContainerInner<'a, T: 'a + PartialEq + Eq + Copy> {
struct ContainerInner<'a, T: 'a>
where
T: Eq + Copy + Hash,
{
ids: crate::Ref<'a, dyn crate::collections::Indexed<T> + Send + Sync>,
data: Option<Data<'a, T>>,
provider: Provider,
}

impl<'a, T: 'a + PartialEq + Eq + Copy> ContainerInner<'a, T> {
impl<'a, T: 'a> ContainerInner<'a, T>
where
T: Eq + Copy + Hash,
{
fn get_compatible_data(&self, previous: Option<Data<'a, T>>, bits: usize) -> Data<'a, T> {
let data_provider = self.provider.create_provider(self.ids.0, bits);

Expand Down

0 comments on commit 3aea2a9

Please sign in to comment.