Add more informations about blocks

Also fixed light for transparent blocks
This commit is contained in:
Snowiiii 2024-11-01 11:01:25 +01:00
parent 21dd9c194c
commit 460e9d3cae
11 changed files with 99601 additions and 27394 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,11 @@
# Done to increase the memory available to gradle. # Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G org.gradle.jvmargs=-Xmx1G
org.gradle.parallel=true
# Fabric Properties # Fabric Properties
# check these on https://modmuss50.me/fabric.html # check these on https://modmuss50.me/fabric.html
minecraft_version=1.21.3 minecraft_version=1.21.3
yarn_mappings=1.21.3+build.2 yarn_mappings=1.21.3+build.2
loader_version=0.16.7 loader_version=0.16.9
kotlin_loader_version=1.12.3+kotlin.2.0.21 kotlin_loader_version=1.12.3+kotlin.2.0.21
# Mod Properties # Mod Properties
mod_version=1.0-SNAPSHOT mod_version=1.0-SNAPSHOT

View File

@ -18,11 +18,11 @@ import java.nio.file.Paths
class Extractor : ModInitializer { class Extractor : ModInitializer {
val MOD_ID: String = "pumpkin_extractor" private val modID: String = "pumpkin_extractor"
val LOGGER: Logger = LoggerFactory.getLogger(MOD_ID) private val logger: Logger = LoggerFactory.getLogger(modID)
override fun onInitialize() { override fun onInitialize() {
LOGGER.info("Starting Pumpkin Extractor") logger.info("Starting Pumpkin Extractor")
val extractors = arrayOf( val extractors = arrayOf(
Sounds(), Sounds(),
Recipes(), Recipes(),
@ -36,7 +36,7 @@ class Extractor : ModInitializer {
try { try {
outputDirectory = Files.createDirectories(Paths.get("pumpkin_extractor_output")) outputDirectory = Files.createDirectories(Paths.get("pumpkin_extractor_output"))
} catch (e: IOException) { } catch (e: IOException) {
LOGGER.info("Failed to create output directory.", e) logger.info("Failed to create output directory.", e)
return return
} }
@ -49,9 +49,9 @@ class Extractor : ModInitializer {
val fileWriter = FileWriter(out.toFile(), StandardCharsets.UTF_8) val fileWriter = FileWriter(out.toFile(), StandardCharsets.UTF_8)
gson.toJson(ext.extract(server.registryManager), fileWriter) gson.toJson(ext.extract(server.registryManager), fileWriter)
fileWriter.close() fileWriter.close()
LOGGER.info("Wrote " + out.toAbsolutePath()) logger.info("Wrote " + out.toAbsolutePath())
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
LOGGER.error(("Extractor for \"" + ext.fileName()) + "\" failed.", e) logger.error(("Extractor for \"" + ext.fileName()) + "\" failed.", e)
} }
} }
}) })

View File

@ -54,8 +54,13 @@ class Blocks : Extractor.Extractor {
val id = stateIdCounter val id = stateIdCounter
stateIdCounter++ stateIdCounter++
stateJson.addProperty("id", id) stateJson.addProperty("id", id)
stateJson.addProperty("air", state.isAir)
stateJson.addProperty("luminance", state.luminance) stateJson.addProperty("luminance", state.luminance)
stateJson.addProperty("opaque", state.isOpaque) stateJson.addProperty("burnable", state.isBurnable)
if (state.isOpaque) {
stateJson.addProperty("opacity", state.opacity)
}
stateJson.addProperty("sided_transparency", state.hasSidedTransparency())
stateJson.addProperty("replaceable", state.isReplaceable) stateJson.addProperty("replaceable", state.isReplaceable)
if (block.defaultState == state) { if (block.defaultState == state) {

View File

@ -22,7 +22,7 @@ impl<'a> ClientPacket for CChunkData<'a> {
let mut data_buf = ByteBuffer::empty(); let mut data_buf = ByteBuffer::empty();
self.0.blocks.iter_subchunks().for_each(|chunk| { self.0.blocks.iter_subchunks().for_each(|chunk| {
let block_count = chunk.iter().filter(|block| !block.is_air()).count() as i16; let block_count = chunk.len() as i16;
// Block count // Block count
data_buf.put_i16(block_count); data_buf.put_i16(block_count);
//// Block states //// Block states
@ -56,7 +56,7 @@ impl<'a> ClientPacket for CChunkData<'a> {
palette.iter().for_each(|id| { palette.iter().for_each(|id| {
// Palette // Palette
data_buf.put_var_int(&VarInt(id.get_id_mojang_repr())); data_buf.put_var_int(&VarInt(**id as i32));
}); });
// Data array length // Data array length
let data_array_len = chunk.len().div_ceil(64 / block_size as usize); let data_array_len = chunk.len().div_ceil(64 / block_size as usize);
@ -87,7 +87,7 @@ impl<'a> ClientPacket for CChunkData<'a> {
let mut out_long: i64 = 0; let mut out_long: i64 = 0;
let mut shift = 0; let mut shift = 0;
for block in block_clump { for block in block_clump {
out_long |= (block.get_id() as i64) << shift; out_long |= (*block as i64) << shift;
shift += DIRECT_PALETTE_BITS; shift += DIRECT_PALETTE_BITS;
} }
data_buf.put_i64(out_long); data_buf.put_i64(out_long);
@ -124,10 +124,10 @@ impl<'a> ClientPacket for CChunkData<'a> {
buf.put_var_int(&VarInt(self.0.blocks.subchunks_len() as i32)); buf.put_var_int(&VarInt(self.0.blocks.subchunks_len() as i32));
self.0.blocks.iter_subchunks().for_each(|chunk| { self.0.blocks.iter_subchunks().for_each(|chunk| {
let mut chunk_light = [0u8; 2048]; let mut chunk_light = [0u8; 2048];
for (i, block) in chunk.iter().enumerate() { for (i, _) in chunk.iter().enumerate() {
if !block.is_air() { // if !block .is_air() {
continue; // continue;
} // }
let index = i / 2; let index = i / 2;
let mask = if i % 2 == 1 { 0xF0 } else { 0x0F }; let mask = if i % 2 == 1 { 0xF0 } else { 0x0F };
chunk_light[index] |= mask; chunk_light[index] |= mask;

View File

@ -2,8 +2,6 @@ use std::sync::LazyLock;
use serde::Deserialize; use serde::Deserialize;
use super::BlockState;
pub static BLOCKS: LazyLock<TopLevel> = LazyLock::new(|| { pub static BLOCKS: LazyLock<TopLevel> = LazyLock::new(|| {
serde_json::from_str(include_str!("../../../assets/blocks.json")) serde_json::from_str(include_str!("../../../assets/blocks.json"))
.expect("Could not parse blocks.json registry.") .expect("Could not parse blocks.json registry.")
@ -55,8 +53,10 @@ struct Property {
#[derive(Deserialize, Clone, Debug)] #[derive(Deserialize, Clone, Debug)]
struct State { struct State {
id: u16, id: u16,
air: bool,
luminance: u8, luminance: u8,
opaque: bool, burnable: bool,
opacity: Option<u32>,
replaceable: bool, replaceable: bool,
collision_shapes: Vec<u16>, collision_shapes: Vec<u16>,
block_entity_type: Option<u32>, block_entity_type: Option<u32>,
@ -71,27 +71,3 @@ struct Shape {
max_y: f64, max_y: f64,
max_z: f64, max_z: f64,
} }
#[derive(Default, Copy, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(transparent)]
pub struct BlockId(pub u16);
impl BlockId {
pub fn is_air(&self) -> bool {
self.0 == 0 || self.0 == 12959 || self.0 == 12958
}
pub fn get_id_mojang_repr(&self) -> i32 {
self.0 as i32
}
pub fn get_id(&self) -> u16 {
self.0
}
}
impl From<BlockState> for BlockId {
fn from(value: BlockState) -> Self {
Self(value.get_id())
}
}

View File

@ -5,7 +5,6 @@ pub mod block_state;
use pumpkin_core::math::vector3::Vector3; use pumpkin_core::math::vector3::Vector3;
pub use block_registry::BlockId;
pub use block_state::BlockState; pub use block_state::BlockState;
#[derive(FromPrimitive)] #[derive(FromPrimitive)]

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
block::{BlockId, BlockState}, block::BlockState,
coordinates::{ChunkRelativeBlockCoordinates, Height}, coordinates::{ChunkRelativeBlockCoordinates, Height},
level::SaveFile, level::SaveFile,
WORLD_HEIGHT, WORLD_HEIGHT,
@ -63,7 +63,7 @@ pub struct ChunkBlocks {
// The packet relies on this ordering -> leave it like this for performance // The packet relies on this ordering -> leave it like this for performance
/// Ordering: yzx (y being the most significant) /// Ordering: yzx (y being the most significant)
blocks: Box<[BlockId; CHUNK_VOLUME]>, blocks: Box<[u16; CHUNK_VOLUME]>,
/// See `https://minecraft.fandom.com/wiki/Heightmap` for more info /// See `https://minecraft.fandom.com/wiki/Heightmap` for more info
pub heightmap: ChunkHeightmaps, pub heightmap: ChunkHeightmaps,
@ -152,7 +152,7 @@ impl Default for ChunkHeightmaps {
impl Default for ChunkBlocks { impl Default for ChunkBlocks {
fn default() -> Self { fn default() -> Self {
Self { Self {
blocks: Box::new([BlockId::default(); CHUNK_VOLUME]), blocks: Box::new([0; CHUNK_VOLUME]),
heightmap: ChunkHeightmaps::default(), heightmap: ChunkHeightmaps::default(),
} }
} }
@ -173,24 +173,20 @@ impl ChunkBlocks {
pub fn empty_with_heightmap(heightmap: ChunkHeightmaps) -> Self { pub fn empty_with_heightmap(heightmap: ChunkHeightmaps) -> Self {
Self { Self {
blocks: Box::new([BlockId::default(); CHUNK_VOLUME]), blocks: Box::new([0; CHUNK_VOLUME]),
heightmap, heightmap,
} }
} }
/// Gets the given block in the chunk /// Gets the given block in the chunk
pub fn get_block(&self, position: ChunkRelativeBlockCoordinates) -> BlockId { pub fn get_block(&self, position: ChunkRelativeBlockCoordinates) -> u16 {
self.blocks[Self::convert_index(position)] self.blocks[Self::convert_index(position)]
} }
/// Sets the given block in the chunk, returning the old block /// Sets the given block in the chunk, returning the old block
pub fn set_block( pub fn set_block(&mut self, position: ChunkRelativeBlockCoordinates, block_id: u16) -> u16 {
&mut self,
position: ChunkRelativeBlockCoordinates,
block: BlockId,
) -> BlockId {
// TODO @LUK_ESC? update the heightmap // TODO @LUK_ESC? update the heightmap
self.set_block_no_heightmap_update(position, block) self.set_block_no_heightmap_update(position, block_id)
} }
/// Sets the given block in the chunk, returning the old block /// Sets the given block in the chunk, returning the old block
@ -201,12 +197,12 @@ impl ChunkBlocks {
pub fn set_block_no_heightmap_update( pub fn set_block_no_heightmap_update(
&mut self, &mut self,
position: ChunkRelativeBlockCoordinates, position: ChunkRelativeBlockCoordinates,
block: BlockId, block: u16,
) -> BlockId { ) -> u16 {
std::mem::replace(&mut self.blocks[Self::convert_index(position)], block) std::mem::replace(&mut self.blocks[Self::convert_index(position)], block)
} }
pub fn iter_subchunks(&self) -> impl Iterator<Item = &[BlockId; SUBCHUNK_VOLUME]> { pub fn iter_subchunks(&self) -> impl Iterator<Item = &[u16; SUBCHUNK_VOLUME]> {
self.blocks self.blocks
.chunks(SUBCHUNK_VOLUME) .chunks(SUBCHUNK_VOLUME)
.map(|subchunk| subchunk.try_into().unwrap()) .map(|subchunk| subchunk.try_into().unwrap())
@ -226,7 +222,7 @@ impl ChunkBlocks {
} }
impl Index<ChunkRelativeBlockCoordinates> for ChunkBlocks { impl Index<ChunkRelativeBlockCoordinates> for ChunkBlocks {
type Output = BlockId; type Output = u16;
fn index(&self, index: ChunkRelativeBlockCoordinates) -> &Self::Output { fn index(&self, index: ChunkRelativeBlockCoordinates) -> &Self::Output {
&self.blocks[Self::convert_index(index)] &self.blocks[Self::convert_index(index)]
@ -299,7 +295,7 @@ impl ChunkData {
y: Height::from_absolute((block_index / CHUNK_AREA) as u16), y: Height::from_absolute((block_index / CHUNK_AREA) as u16),
x: (block_index % 16).into(), x: (block_index % 16).into(),
}, },
BlockId(block.get_id()), block.get_id(),
); );
block_index += 1; block_index += 1;

View File

@ -57,22 +57,22 @@ impl PerlinTerrainGenerator for PlainsTerrainGenerator {
if y == -64 { if y == -64 {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:bedrock").unwrap().into(), BlockState::new("minecraft:bedrock").unwrap().state_id,
); );
} else if y >= -63 && y <= begin_stone_height { } else if y >= -63 && y <= begin_stone_height {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:stone").unwrap().into(), BlockState::new("minecraft:stone").unwrap().state_id,
); );
} else if y >= begin_stone_height && y < begin_dirt_height { } else if y >= begin_stone_height && y < begin_dirt_height {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:dirt").unwrap().into(), BlockState::new("minecraft:dirt").unwrap().state_id,
); );
} else if y == chunk_height - 2 { } else if y == chunk_height - 2 {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:grass_block").unwrap().into(), BlockState::new("minecraft:grass_block").unwrap().state_id,
); );
} else if y == chunk_height - 1 { } else if y == chunk_height - 1 {
// TODO: generate flowers and grass // TODO: generate flowers and grass
@ -84,31 +84,31 @@ impl PerlinTerrainGenerator for PlainsTerrainGenerator {
0 => { 0 => {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:dandelion").unwrap().into(), BlockState::new("minecraft:dandelion").unwrap().state_id,
); );
} }
1 => { 1 => {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:oxeye_daisy").unwrap().into(), BlockState::new("minecraft:oxeye_daisy").unwrap().state_id,
); );
} }
2 => { 2 => {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:cornflower").unwrap().into(), BlockState::new("minecraft:cornflower").unwrap().state_id,
); );
} }
3 => { 3 => {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:poppy").unwrap().into(), BlockState::new("minecraft:poppy").unwrap().state_id,
); );
} }
_ => { _ => {
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:azure_bluet").unwrap().into(), BlockState::new("minecraft:azure_bluet").unwrap().state_id,
); );
} }
} }
@ -116,7 +116,7 @@ impl PerlinTerrainGenerator for PlainsTerrainGenerator {
// TODO: Tall grass, Tall grass data called `half`, There is `upper` and `lower` // TODO: Tall grass, Tall grass data called `half`, There is `upper` and `lower`
blocks.set_block( blocks.set_block(
coordinates, coordinates,
BlockState::new("minecraft:short_grass").unwrap().into(), BlockState::new("minecraft:short_grass").unwrap().state_id,
); );
} }
} }

View File

@ -34,7 +34,6 @@ use pumpkin_protocol::{
server::play::{SCloseContainer, SKeepAlive, SSetPlayerGround, SUseItem}, server::play::{SCloseContainer, SKeepAlive, SSetPlayerGround, SUseItem},
VarInt, VarInt,
}; };
use pumpkin_world::block::BlockId;
use pumpkin_world::block::{block_registry::get_block_by_item, BlockFace}; use pumpkin_world::block::{block_registry::get_block_by_item, BlockFace};
use super::{ use super::{
@ -624,7 +623,7 @@ impl Player {
world world
.set_block( .set_block(
WorldPosition(location.0 + face.to_offset()), WorldPosition(location.0 + face.to_offset()),
BlockId(block.default_state_id), block.default_state_id,
) )
.await; .await;
} }

View File

@ -26,7 +26,6 @@ use pumpkin_protocol::{
}, },
ClientPacket, VarInt, ClientPacket, VarInt,
}; };
use pumpkin_world::block::BlockId;
use pumpkin_world::chunk::ChunkData; use pumpkin_world::chunk::ChunkData;
use pumpkin_world::coordinates::ChunkRelativeBlockCoordinates; use pumpkin_world::coordinates::ChunkRelativeBlockCoordinates;
use pumpkin_world::level::Level; use pumpkin_world::level::Level;
@ -575,7 +574,7 @@ impl World {
self.broadcast_packet_all(&CRemoveEntities::new(&[entity.entity_id.into()])) self.broadcast_packet_all(&CRemoveEntities::new(&[entity.entity_id.into()]))
.await; .await;
} }
pub async fn set_block(&self, position: WorldPosition, block_id: BlockId) { pub async fn set_block(&self, position: WorldPosition, block_id: u16) {
let (chunk_coordinate, relative_coordinates) = position.chunk_and_chunk_relative_position(); let (chunk_coordinate, relative_coordinates) = position.chunk_and_chunk_relative_position();
// Since we divide by 16 remnant can never exceed u8 // Since we divide by 16 remnant can never exceed u8
@ -584,7 +583,7 @@ impl World {
let chunk = self.receive_chunk(chunk_coordinate).await; let chunk = self.receive_chunk(chunk_coordinate).await;
chunk.write().await.blocks.set_block(relative, block_id); chunk.write().await.blocks.set_block(relative, block_id);
self.broadcast_packet_all(&CBlockUpdate::new(&position, i32::from(block_id.0).into())) self.broadcast_packet_all(&CBlockUpdate::new(&position, i32::from(block_id).into()))
.await; .await;
} }
@ -604,13 +603,13 @@ impl World {
} }
pub async fn break_block(&self, position: WorldPosition) { pub async fn break_block(&self, position: WorldPosition) {
self.set_block(position, BlockId(0)).await; self.set_block(position, 0).await;
self.broadcast_packet_all(&CWorldEvent::new(2001, &position, 11, false)) self.broadcast_packet_all(&CWorldEvent::new(2001, &position, 11, false))
.await; .await;
} }
pub async fn get_block(&self, position: WorldPosition) -> BlockId { pub async fn get_block(&self, position: WorldPosition) -> u16 {
let (chunk, relative) = position.chunk_and_chunk_relative_position(); let (chunk, relative) = position.chunk_and_chunk_relative_position();
let relative = ChunkRelativeBlockCoordinates::from(relative); let relative = ChunkRelativeBlockCoordinates::from(relative);
let chunk = self.receive_chunk(chunk).await; let chunk = self.receive_chunk(chunk).await;