Skip to content

Commit

Permalink
Merge pull request #36 from rimecraft-rs:world1
Browse files Browse the repository at this point in the history
world implementation part1
  • Loading branch information
JieningYu committed May 4, 2024
2 parents b4f67a2 + 2ecdb63 commit 25f32db
Show file tree
Hide file tree
Showing 41 changed files with 2,193 additions and 330 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
*/target
/target
/.tuffous/config_gui.json
/.vscode
/.idea
/.VSCodeCounter
Expand Down
28 changes: 28 additions & 0 deletions crates/core/block-entity/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "rimecraft-block-entity"
version = "0.1.0"
edition = "2021"
authors = ["JieningYu <[email protected]>"]
description = "Minecraft block entity primitives"
repository = "https://github.com/rimecraft-rs/rimecraft/"
license = "AGPL-3.0-or-later"
categories = []

[badges]
maintenance = { status = "passively-maintained" }

[dependencies]
rimecraft-global-cx = { path = "../global-cx" }
rimecraft-registry = { path = "../../util/registry" }
rimecraft-block = { path = "../block" }
rimecraft-voxel-math = { path = "../../util/voxel-math" }
rimecraft-downcast = { path = "../../util/downcast" }
ahash = "0.8"
serde = "1.0"
erased-serde = "0.4"
rimecraft-serde-update = { path = "../../util/serde-update", features = ["erased"] }

[features]

[lints]
workspace = true
229 changes: 229 additions & 0 deletions crates/core/block-entity/src/deser_nbt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
//! Helper module for deserializing NBT data into block entities.

use std::{fmt::Debug, hash::Hash, marker::PhantomData};

use rimecraft_block::{BlockState, ProvideBlockStateExtTy};
use rimecraft_global_cx::ProvideNbtTy;
use rimecraft_registry::ProvideRegistry;
use rimecraft_voxel_math::BlockPos;
use serde::{de::DeserializeSeed, Deserialize, Deserializer};

use crate::{BlockEntity, ProvideBlockEntity, RawBlockEntityTypeDyn};

/// The dummy value for block entity types.
pub const DUMMY: &str = "DUMMY";

/// A [`DeserializeSeed`] for [`BlockEntity`].
///
/// This deserializes the id of the block entity type and its data.
pub struct CreateFromNbt<'w, Cx>
where
Cx: ProvideBlockStateExtTy,
{
/// The position of the block entity.
pub pos: BlockPos,
/// The state of the [`Block`] the block entity belongs to.
pub state: BlockState<'w, Cx>,

/// Whether to respect the [`DUMMY`] value.
pub respect_dummy: bool,
}

impl<Cx> Debug for CreateFromNbt<'_, Cx>
where
Cx: ProvideBlockStateExtTy + Debug,
Cx::BlockStateExt: Debug,
Cx::Id: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CreateFromNbt")
.field("pos", &self.pos)
.field("state", &self.state)
.finish()
}
}

impl<'w, 'de, Cx> DeserializeSeed<'de> for CreateFromNbt<'w, Cx>
where
Cx: ProvideBlockStateExtTy
+ ProvideRegistry<'w, Cx::Id, RawBlockEntityTypeDyn<'w, Cx>>
+ ProvideNbtTy,
Cx::Id: Deserialize<'de> + Hash + Eq,
Cx::BlockStateExt: ProvideBlockEntity<'w, Cx>,
{
type Value = Option<Box<BlockEntity<'w, Cx>>>;

fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
struct Visitor<'w, Cx>(CreateFromNbt<'w, Cx>)
where
Cx: ProvideBlockStateExtTy;

impl<'de, 'w, Cx> serde::de::Visitor<'de> for Visitor<'w, Cx>
where
Cx: ProvideBlockStateExtTy
+ ProvideRegistry<'w, Cx::Id, RawBlockEntityTypeDyn<'w, Cx>>
+ ProvideNbtTy,
Cx::Id: Deserialize<'de> + Hash + Eq,
Cx::BlockStateExt: ProvideBlockEntity<'w, Cx>,
{
type Value = Option<Box<BlockEntity<'w, Cx>>>;

fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("a block entity")
}

fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
use serde::__private::de::Content;

let mut id: Option<Cx::Id> = None;
let mut is_dummy = false;
let mut collect: Vec<Option<(Content<'de>, Content<'de>)>> =
Vec::with_capacity(map.size_hint().map_or(0, |i| i - 1));

enum Field<'de> {
Id,
Other(Content<'de>),
}

impl<'de> Deserialize<'de> for Field<'de> {
fn deserialize<D>(deserializer: D) -> Result<Field<'de>, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;

impl<'de> serde::de::Visitor<'de> for FieldVisitor {
type Value = Field<'de>;

fn expecting(
&self,
formatter: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
formatter.write_str("a field")
}

fn visit_str<E>(self, v: &str) -> Result<Field<'de>, E>
where
E: serde::de::Error,
{
match v {
"id" => Ok(Field::Id),
_ => Ok(Field::Other(Content::String(v.into()))),
}
}
}

deserializer.deserialize_identifier(FieldVisitor)
}
}

#[derive(Deserialize)]
#[serde(untagged)]
enum MaybeDummy<T> {
Dummy(Dummy),
Value(T),
}

pub struct Dummy;

impl<'de> Deserialize<'de> for Dummy {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct DummyVisitor;

impl serde::de::Visitor<'_> for DummyVisitor {
type Value = Dummy;

fn expecting(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
write!(f, "a '{}' value", DUMMY)
}

#[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if v == DUMMY {
Ok(Dummy)
} else {
Err(serde::de::Error::custom("expected 'DUMMY'"))
}
}
}

deserializer.deserialize_str(DummyVisitor)
}
}

while let Some(key) = map.next_key()? {
match key {
Field::Id => {
if id.is_some() {
return Err(serde::de::Error::duplicate_field("id"));
}

if self.0.respect_dummy {
let dummy: MaybeDummy<Cx::Id> = map.next_value()?;
match dummy {
MaybeDummy::Dummy(Dummy) => {
is_dummy = true;
}
MaybeDummy::Value(i) => {
id = Some(i);
}
}
} else {
id = Some(map.next_value()?);
}
}
Field::Other(content) => {
collect.push(Some((content, map.next_value()?)));
}
}
}

if is_dummy {
let state = self.0.state.state;
let res = if let Some(constructor) =
ProvideBlockEntity::block_entity_constructor(state.data())
{
Ok(Some(constructor(self.0.pos)))
} else {
Ok(None)
};
res
} else {
let id = id.ok_or_else(|| serde::de::Error::missing_field("id"))?;
let registry: &rimecraft_registry::Registry<_, RawBlockEntityTypeDyn<'w, Cx>> =
Cx::registry();
let ty = registry.get(&id).ok_or_else(|| {
serde::de::Error::custom(format!("unknown block entity type: {}", id))
})?;

let mut be = ty.instantiate(self.0.pos, self.0.state);
// Update the block entity data.
if let Some(be) = &mut be {
rimecraft_serde_update::Update::update(
&mut be.data,
serde::__private::de::FlatMapDeserializer(&mut collect, PhantomData),
)?;
}
Ok(be)
}
}
}

deserializer.deserialize_map(Visitor(self))
}
}
Loading

0 comments on commit 25f32db

Please sign in to comment.