Skip to content

Commit

Permalink
Merge pull request #63 from DaniD3v/master
Browse files Browse the repository at this point in the history
Superflat Worldgeneration
  • Loading branch information
Snowiiii authored Aug 28, 2024
2 parents 3b43887 + ff06d05 commit 0ba9b37
Show file tree
Hide file tree
Showing 20 changed files with 812 additions and 277 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 7 additions & 11 deletions pumpkin-protocol/src/client/play/c_chunk_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,19 @@ pub struct CChunkData<'a>(pub &'a ChunkData);
impl<'a> ClientPacket for CChunkData<'a> {
fn write(&self, buf: &mut crate::bytebuf::ByteBuffer) {
// Chunk X
buf.put_i32(self.0.position.0);
buf.put_i32(self.0.position.x);
// Chunk Z
buf.put_i32(self.0.position.1);
buf.put_i32(self.0.position.z);

let heightmap_nbt =
fastnbt::to_bytes_with_opts(&self.0.heightmaps, fastnbt::SerOpts::network_nbt())
fastnbt::to_bytes_with_opts(&self.0.blocks.heightmap, fastnbt::SerOpts::network_nbt())
.unwrap();
// Heightmaps
buf.put_slice(&heightmap_nbt);

let mut data_buf = ByteBuffer::empty();
self.0.blocks.chunks(16 * 16 * 16).for_each(|chunk| {
let block_count = chunk
.iter()
.dedup()
.filter(|block| **block != 0 && **block != 12959 && **block != 12958)
.count() as i16;
self.0.blocks.iter_subchunks().for_each(|chunk| {
let block_count = chunk.iter().filter(|block| !block.is_air()).count() as i16;
// Block count
data_buf.put_i16(block_count);
//// Block states
Expand Down Expand Up @@ -63,7 +59,7 @@ impl<'a> ClientPacket for CChunkData<'a> {
palette.iter().enumerate().for_each(|(i, id)| {
palette_map.insert(*id, i);
// Palette
data_buf.put_var_int(&VarInt(**id));
data_buf.put_var_int(&VarInt(id.get_id_mojang_repr()));
});
for block_clump in chunk.chunks(64 / block_size as usize) {
let mut out_long: i64 = 0;
Expand All @@ -83,7 +79,7 @@ impl<'a> ClientPacket for CChunkData<'a> {
let mut out_long: i64 = 0;
let mut shift = 0;
for block in block_clump {
out_long |= (*block as i64) << shift;
out_long |= (block.get_id() as i64) << shift;
shift += DIRECT_PALETTE_BITS;
}
block_data_array.push(out_long);
Expand Down
2 changes: 2 additions & 0 deletions pumpkin-world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ flate2 = "1.0.33"
serde = { version = "1.0", features = ["derive"] }
lazy_static = "1.5.0"
serde_json = "1.0"
static_assertions = "1.1.0"
log.workspace = true

num-traits = "0.2"
num-derive = "0.4"
9 changes: 9 additions & 0 deletions pumpkin-world/src/biome.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};

// TODO make this work with the protocol
#[derive(Serialize, Deserialize, Clone, Copy)]
#[non_exhaustive]
pub enum Biome {
Plains,
// TODO list all Biomes
}
58 changes: 58 additions & 0 deletions pumpkin-world/src/block/block_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use std::collections::HashMap;

use serde::Deserialize;

use super::block_registry::BLOCKS;
use crate::level::WorldError;

// 0 is air -> reasonable default
#[derive(Default, Deserialize, Debug, Hash, Clone, Copy, PartialEq, Eq)]
#[serde(transparent)]
pub struct BlockId {
data: u16,
}

impl BlockId {
pub const AIR: Self = Self::from_id(0);

pub fn new(
text_id: &str,
properties: Option<&HashMap<String, String>>,
) -> Result<Self, WorldError> {
let mut block_states = BLOCKS
.get(text_id)
.ok_or(WorldError::BlockIdentifierNotFound)?
.states
.iter();

let block_state = match properties {
Some(properties) => match block_states.find(|state| &state.properties == properties) {
Some(state) => state,
None => return Err(WorldError::BlockStateIdNotFound),
},
None => block_states
.find(|state| state.is_default)
.expect("Every Block should have at least 1 default state"),
};

Ok(block_state.id)
}

pub const fn from_id(id: u16) -> Self {
// TODO: add check if the id is actually valid
Self { data: id }
}

pub fn is_air(&self) -> bool {
self.data == 0 || self.data == 12959 || self.data == 12958
}

pub fn get_id(&self) -> u16 {
self.data
}

/// An i32 is the way mojang internally represents their Blocks
pub fn get_id_mojang_repr(&self) -> i32 {
self.data as i32
}
}
82 changes: 38 additions & 44 deletions pumpkin-world/src/block/block_registry.rs
Original file line number Diff line number Diff line change
@@ -1,58 +1,52 @@
use std::collections::HashMap;

use lazy_static::lazy_static;
use serde::Deserialize;

use crate::level::WorldError;
use super::block_id::BlockId;

const BLOCKS_JSON: &str = include_str!("../../assets/blocks.json");
lazy_static! {
pub static ref BLOCKS: HashMap<String, RegistryBlockType> =
serde_json::from_str(include_str!("../../assets/blocks.json"))
.expect("Could not parse block.json registry.");
}

#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct BlockDefinition {
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct RegistryBlockDefinition {
/// e.g. minecraft:door or minecraft:button
#[serde(rename = "type")]
kind: String,
block_set_type: Option<String>,
}
pub category: String,

#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct BlockState {
default: Option<bool>,
id: i64,
properties: Option<HashMap<String, String>>,
/// Specifies the variant of the blocks category.
/// e.g. minecraft:iron_door has the variant iron
#[serde(rename = "block_set_type")]
pub variant: Option<String>,
}

#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct BlocksElement {
definition: BlockDefinition,
properties: Option<HashMap<String, Vec<String>>>,
states: Vec<BlockState>,
}
/// One possible state of a Block.
/// This could e.g. be an extended piston facing left.
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct RegistryBlockState {
pub id: BlockId,

lazy_static! {
pub static ref BLOCKS: HashMap<String, BlocksElement> =
serde_json::from_str(BLOCKS_JSON).expect("Could not parse block.json registry.");
/// Whether this is the default state of the Block
#[serde(default, rename = "default")]
pub is_default: bool,

/// The propertise active for this `BlockState`.
#[serde(default)]
pub properties: HashMap<String, String>,
}

pub fn block_id_and_properties_to_block_state_id(
block_id: &str,
properties: Option<&HashMap<String, String>>,
) -> Result<i64, WorldError> {
let block = match BLOCKS.get(block_id) {
Some(block) => block,
None => return Err(WorldError::BlockStateIdNotFound),
};
let block_state_id = match properties {
None => Ok(block
.states
.iter()
.find(|state| state.default.unwrap_or(false))
.expect("Each block should have at least one default state")
.id),
Some(properties) => block
.states
.iter()
.find(|state| state.properties.as_ref() == Some(properties))
.map(|state| state.id)
.ok_or(WorldError::BlockStateIdNotFound),
};
block_state_id
/// A fully-fledged block definition.
/// Stores the category, variant, all of the possible states and all of the possible properties.
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct RegistryBlockType {
pub definition: RegistryBlockDefinition,
pub states: Vec<RegistryBlockState>,

// TODO is this safe to remove? It's currently not used in the Project. @lukas0008 @Snowiiii
/// A list of valid property keys/values for a block.
#[serde(default, rename = "properties")]
valid_properties: HashMap<String, Vec<String>>,
}
8 changes: 5 additions & 3 deletions pumpkin-world/src/block/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::vector3::Vector3;
use num_derive::FromPrimitive;

use crate::vector3::Vector3;
pub mod block_id;
mod block_registry;

pub use block_id::BlockId;

pub mod block_registry;
pub use block_registry::BLOCKS;
#[derive(FromPrimitive)]
pub enum BlockFace {
Bottom = 0,
Expand Down
Loading

0 comments on commit 0ba9b37

Please sign in to comment.