Skip to content

Commit

Permalink
Added foundation
Browse files Browse the repository at this point in the history
  • Loading branch information
leobeg committed Dec 20, 2024
1 parent bab92b3 commit 19458f3
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 11 deletions.
6 changes: 5 additions & 1 deletion pumpkin-core/src/math/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::math::vector2::Vector2;
use num_traits::Euclid;
use serde::{Deserialize, Serialize};

#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
/// Aka Block Position
pub struct WorldPosition(pub Vector3<i32>);

Expand All @@ -27,6 +27,10 @@ impl WorldPosition {
};
(chunk_coordinate, relative)
}

pub fn from_xyz(x: i32, y: i32, z: i32) -> Self {
Self(Vector3::new(x, y, z))
}
}
impl Serialize for WorldPosition {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down
47 changes: 47 additions & 0 deletions pumpkin-world/src/block/block_entity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use serde::Deserialize;

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct BlockEntityItem {
count: Option<u8>,
slot: Option<u8>,
#[serde(rename = "id")]
id: String,
//tag - Currently not needed
}

#[derive(Debug, Clone, Deserialize)]
pub struct BlockEntity {
pub x: i32,
pub y: i32,
pub z: i32,
// #[serde(rename = "id")]
// pub id: String,
#[serde(flatten)]
pub data: BlockEntityType
}

#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "id")]
pub enum BlockEntityType {

#[serde(rename = "minecraft:jukebox")]
Jukebox {
#[serde(rename = "RecordItem")]
record_item: Option<RecordItem>,
ticks_since_song_started: Option<i64>,
},

#[serde(other)]
Unknown
}


/// --- Entity specific structs ---
/// Jukebox record item
#[derive(Debug, Clone, Deserialize)]
pub struct RecordItem {
pub count: u8,
pub id: String,
}
1 change: 1 addition & 0 deletions pumpkin-world/src/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use num_derive::FromPrimitive;

pub mod block_registry;
pub mod block_state;
pub mod block_entity;

use pumpkin_core::math::vector3::Vector3;

Expand Down
14 changes: 13 additions & 1 deletion pumpkin-world/src/chunk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ use std::cmp::max;
use std::collections::HashMap;
use std::ops::Index;
use thiserror::Error;

use pumpkin_core::math::position::WorldPosition;
use crate::{
block::BlockState,
coordinates::{ChunkRelativeBlockCoordinates, Height},
level::SaveFile,
WORLD_HEIGHT,
};
use crate::block::block_entity::BlockEntity;

pub mod anvil;

Expand Down Expand Up @@ -55,6 +56,7 @@ pub enum CompressionError {

pub struct ChunkData {
pub blocks: ChunkBlocks,
pub block_entities: HashMap<WorldPosition, BlockEntity>,
pub position: Vector2<i32>,
}
pub struct ChunkBlocks {
Expand Down Expand Up @@ -108,6 +110,9 @@ struct ChunkNbt {
#[serde(rename = "sections")]
sections: Vec<ChunkSection>,

#[serde(rename = "block_entities")]
block_entities: Vec<BlockEntity>,

heightmaps: ChunkHeightmaps,
}

Expand Down Expand Up @@ -310,9 +315,16 @@ impl ChunkData {
}
}

let mut block_entities: HashMap<WorldPosition, BlockEntity> = HashMap::new();
for block_entity in chunk_data.block_entities {
let position = WorldPosition::from_xyz(block_entity.x, block_entity.y, block_entity.z);
block_entities.insert(position, block_entity);
}

Ok(ChunkData {
blocks,
position: at,
block_entities,
})
}
}
Expand Down
17 changes: 17 additions & 0 deletions pumpkin-world/src/item/item_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@ pub fn get_item_by_id<'a>(id: u16) -> Option<&'a Item> {
None
}

pub fn get_record_item(name: &str) -> Option<&Item> {
let item = ITEMS.iter().find(|item| {
item.1
.components
.jukebox_playable
.as_ref()
.map(|playable| playable.song == name.to_string())
.unwrap_or(false)
});

if let Some(item) = item {
return Some(item.1);
}

None
}

#[derive(Deserialize, Clone, Debug)]
pub struct Item {
pub id: u16,
Expand Down
2 changes: 2 additions & 0 deletions pumpkin-world/src/world_gen/generic_generator.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use noise::{NoiseFn, Perlin};
use pumpkin_core::math::vector2::Vector2;

Expand Down Expand Up @@ -75,6 +76,7 @@ impl<B: BiomeGenerator, T: PerlinTerrainGenerator> WorldGenerator for GenericGen
ChunkData {
blocks,
position: at,
block_entities: HashMap::new(),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion pumpkin-world/src/world_gen/implementation/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{
num::Wrapping,
ops::{AddAssign, SubAssign},
};

use std::collections::HashMap;
use dashmap::{DashMap, Entry};
use num_traits::Zero;
use pumpkin_core::math::{vector2::Vector2, vector3::Vector3};
Expand Down Expand Up @@ -77,6 +77,7 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for TestGenerator<B,
ChunkData {
blocks,
position: at,
block_entities: HashMap::new(),
}
}
}
Expand Down
74 changes: 71 additions & 3 deletions pumpkin/src/block/blocks/jukebox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,49 @@ use crate::block::block_manager::BlockActionResult;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
use async_trait::async_trait;
use pumpkin_core::math::position::WorldPosition;
use pumpkin_macros::pumpkin_block;
use pumpkin_registry::SYNCED_REGISTRIES;
use pumpkin_world::item::item_registry::Item;
use pumpkin_world::block::block_entity::{BlockEntity, BlockEntityType, RecordItem};
use pumpkin_world::item::item_registry::{get_item, get_record_item, Item};
use std::sync::Arc;

#[pumpkin_block("minecraft:jukebox")]
pub struct JukeboxBlock;

#[async_trait]
impl PumpkinBlock for JukeboxBlock {
async fn on_use<'a>(&self, player: &Player, location: WorldPosition, _server: &Server) {
// For now just stop the music at this position
let world = &player.living_entity.entity.world;

world.stop_record(location).await;
let block_entity = world.get_block_entity(&location).await;
let Some(block_entity) = block_entity else {
return;
};

let record_item = match block_entity.data {
BlockEntityType::Jukebox { record_item, .. } => record_item,
_ => return,
};

dbg!(&record_item);

if let Some(record_item) = record_item {
//TODO: The record would drop here for now just give the disk to the player
let item = get_record_item(record_item.id.as_str());

let Some(item) = item else {
return;
};

player.give_items(item, 1).await;

world.stop_record(location).await;

Self::write_block_entity(world, location, None, None).await;
}
}

async fn on_use_with_item<'a>(
Expand Down Expand Up @@ -46,13 +73,54 @@ impl PumpkinBlock for JukeboxBlock {

world.play_record(jukebox_song as i32, location).await;

Self::write_block_entity(
world,
location,
Some(RecordItem {
count: 1,
id: jukebox_playable.song.clone(),
}),
Some(0),
)
.await;

BlockActionResult::Consume
}

async fn on_placed<'a>(&self, player: &Player, location: WorldPosition, _server: &Server) {
let world = &player.living_entity.entity.world;
Self::write_block_entity(world, location, None, None).await;
}

async fn on_broken<'a>(&self, player: &Player, location: WorldPosition, _server: &Server) {
// For now just stop the music at this position
let world = &player.living_entity.entity.world;

world.stop_record(location).await;

world.remove_block_entity(location).await;
}
}

impl JukeboxBlock {
pub async fn write_block_entity(
world: &Arc<World>,
location: WorldPosition,
record_item: Option<RecordItem>,
ticks_since_song_started: Option<i64>,
) {
let block_entity = BlockEntity {
x: location.0.x,
y: location.0.y,
z: location.0.z,
data: BlockEntityType::Jukebox {
record_item,
ticks_since_song_started,
},
};

world
.create_or_update_block_entity(location, block_entity)
.await;
}
}
27 changes: 22 additions & 5 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use pumpkin_protocol::{
use pumpkin_world::block::{block_registry::get_block_by_item, BlockFace};
use pumpkin_world::item::item_registry::get_item_by_id;
use thiserror::Error;
use pumpkin_protocol::client::play::CBlockUpdate;

fn modulus(a: f32, b: f32) -> f32 {
((a % b) + b) % b
Expand Down Expand Up @@ -652,6 +653,8 @@ impl Player {
// TODO: maybe log?
return Err(BlockPlacingError::BlockOutOfReach.into());
}

log::info!("Test");

if let Some(face) = BlockFace::from_i32(use_item_on.face.0) {
let inventory = self.inventory().lock().await;
Expand All @@ -672,6 +675,9 @@ impl Player {
match result {
BlockActionResult::Continue => {}
BlockActionResult::Consume => {
self.client
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
.await;
return Ok(());
}
}
Expand All @@ -687,6 +693,9 @@ impl Player {
let item_slot = inventory.held_item_mut();
// This should never be possible
let Some(item_stack) = item_slot else {
self.client
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
.await;
return Err(BlockPlacingError::InventoryInvalid.into());
};
item_stack.item_count -= 1;
Expand All @@ -706,6 +715,9 @@ impl Player {
let previous_block_state = world.get_block_state(world_pos).await?;

if !previous_block_state.replaceable {
self.client
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
.await;
return Ok(());
}

Expand All @@ -732,22 +744,27 @@ impl Player {
.on_placed(block, self, world_pos, server)
.await;
}

self.client
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
.await;
}
} else {
self.client
.send_packet(&CAcknowledgeBlockChange::new(use_item_on.sequence))
.await;
drop(inventory);
let block = world.get_block(location).await;
if let Ok(block) = block {
server
.block_manager
.on_use(block, self, location, server)
.on_use(block, self, location.clone(), server)
.await;
}
let block_state = world.get_block_state_id(location).await.unwrap();
self.client
.send_packet(&CBlockUpdate::new(&location, VarInt::from(block_state as u32)))
.await;
}



Ok(())
} else {
Err(BlockPlacingError::InvalidBlockFace.into())
Expand Down
Loading

0 comments on commit 19458f3

Please sign in to comment.