Skip to content

Commit

Permalink
Added chest opening and closing animation (#421)
Browse files Browse the repository at this point in the history
* Added basic chest opening and closing

* Added number tracking

* Added play chest action function
  • Loading branch information
OfficialKris authored Dec 28, 2024
1 parent 205191b commit ad2fd3c
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 15 deletions.
4 changes: 4 additions & 0 deletions pumpkin-inventory/src/open_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ impl OpenContainer {
self.players.clone()
}

pub fn get_number_of_players(&self) -> usize {
self.players.len()
}

pub fn get_location(&self) -> Option<WorldPosition> {
self.location
}
Expand Down
31 changes: 31 additions & 0 deletions pumpkin-protocol/src/client/play/c_block_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use pumpkin_core::math::position::WorldPosition;

use pumpkin_macros::client_packet;
use serde::Serialize;

use crate::VarInt;

#[derive(Serialize)]
#[client_packet("play:block_event")]
pub struct CBlockAction<'a> {
location: &'a WorldPosition,
action_id: u8,
action_parameter: u8,
block_type: VarInt,
}

impl<'a> CBlockAction<'a> {
pub fn new(
location: &'a WorldPosition,
action_id: u8,
action_parameter: u8,
block_type: VarInt,
) -> Self {
Self {
location,
action_id,
action_parameter,
block_type,
}
}
}
2 changes: 2 additions & 0 deletions pumpkin-protocol/src/client/play/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod bossevent_action;
mod c_acknowledge_block;
mod c_actionbar;
mod c_block_destroy_stage;
mod c_block_event;
mod c_block_update;
mod c_boss_event;
mod c_center_chunk;
Expand Down Expand Up @@ -72,6 +73,7 @@ pub use bossevent_action::*;
pub use c_acknowledge_block::*;
pub use c_actionbar::*;
pub use c_block_destroy_stage::*;
pub use c_block_event::*;
pub use c_block_update::*;
pub use c_boss_event::*;
pub use c_center_chunk::*;
Expand Down
71 changes: 58 additions & 13 deletions pumpkin/src/block/blocks/chest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@ use async_trait::async_trait;
use pumpkin_core::math::position::WorldPosition;
use pumpkin_inventory::{Chest, OpenContainer, WindowType};
use pumpkin_macros::{pumpkin_block, sound};
use pumpkin_world::{block::block_registry::Block, item::item_registry::Item};
use pumpkin_protocol::{client::play::CBlockAction, codec::var_int::VarInt};
use pumpkin_world::{
block::block_registry::{get_block, Block},
item::item_registry::Item,
};

use crate::{
block::{block_manager::BlockActionResult, pumpkin_block::PumpkinBlock},
entity::player::Player,
server::Server,
};

#[derive(PartialEq)]
pub enum ChestState {
IsOpened,
IsClosed,
}

#[pumpkin_block("minecraft:chest")]
pub struct ChestBlock;

Expand All @@ -24,10 +34,6 @@ impl PumpkinBlock for ChestBlock {
) {
self.open_chest_block(block, player, _location, server)
.await;
player
.world()
.play_block_sound(sound!("block.chest.open"), _location)
.await;
}

async fn on_use_with_item<'a>(
Expand Down Expand Up @@ -57,15 +63,14 @@ impl PumpkinBlock for ChestBlock {
&self,
_block: &Block,
player: &Player,
_location: WorldPosition,
_server: &Server,
_container: &OpenContainer,
location: WorldPosition,
server: &Server,
container: &mut OpenContainer,
) {
player
.world()
.play_block_sound(sound!("block.chest.close"), _location)
container.remove_player(player.entity_id());

self.play_chest_action(container, player, location, server, ChestState::IsClosed)
.await;
// TODO: send entity updates close
}
}

Expand All @@ -86,6 +91,46 @@ impl ChestBlock {
WindowType::Generic9x3,
)
.await;
// TODO: send entity updates open

if let Some(container_id) = server.get_container_id(location, block.clone()).await {
let open_containers = server.open_containers.read().await;
if let Some(container) = open_containers.get(&u64::from(container_id)) {
self.play_chest_action(container, player, location, server, ChestState::IsOpened)
.await;
}
}
}

pub async fn play_chest_action(
&self,
container: &OpenContainer,
player: &Player,
location: WorldPosition,
server: &Server,
state: ChestState,
) {
let num_players = container.get_number_of_players() as u8;
if state == ChestState::IsClosed && num_players == 0 {
player
.world()
.play_block_sound(sound!("block.chest.close"), location)
.await;
} else if state == ChestState::IsOpened && num_players == 1 {
player
.world()
.play_block_sound(sound!("block.chest.open"), location)
.await;
}

if let Some(e) = get_block("minecraft:chest").cloned() {
server
.broadcast_packet_all(&CBlockAction::new(
&location,
1,
num_players,
VarInt(e.id.into()),
))
.await;
}
}
}
4 changes: 3 additions & 1 deletion pumpkin/src/block/blocks/crafting_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl PumpkinBlock for CraftingTableBlock {
player: &Player,
_location: WorldPosition,
_server: &Server,
container: &OpenContainer,
container: &mut OpenContainer,
) {
let entity_id = player.entity_id();
for player_id in container.all_player_ids() {
Expand All @@ -62,6 +62,8 @@ impl PumpkinBlock for CraftingTableBlock {
}
}

container.remove_player(entity_id);

// TODO: items should be re-added to player inventory or dropped dependending on if they are in movement.
// TODO: unique containers should be implemented as a separate stack internally (optimizes large player servers for example)
// TODO: ephemeral containers (crafting tables) might need to be separate data structure than stored (ender chest)
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/block/pumpkin_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub trait PumpkinBlock: Send + Sync {
_player: &Player,
_location: WorldPosition,
_server: &Server,
_container: &OpenContainer,
_container: &mut OpenContainer,
) {
}
}

0 comments on commit ad2fd3c

Please sign in to comment.