Skip to content

Commit

Permalink
move container to LivingEntity (#355)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryntet authored Nov 30, 2024
1 parent 51365c4 commit f29cfbc
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 37 deletions.
28 changes: 28 additions & 0 deletions pumpkin-inventory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,34 @@ pub trait Container: Sync + Send {
fn recipe_used(&mut self) {}
}

pub struct EmptyContainer;

impl Container for EmptyContainer {
fn window_type(&self) -> &'static WindowType {
unreachable!(
"you should never be able to get here because this type is always wrapped in an option"
);
}

fn window_name(&self) -> &'static str {
unreachable!(
"you should never be able to get here because this type is always wrapped in an option"
);
}

fn all_slots(&mut self) -> Vec<&mut Option<ItemStack>> {
unreachable!(
"you should never be able to get here because this type is always wrapped in an option"
);
}

fn all_slots_ref(&self) -> Vec<Option<&ItemStack>> {
unreachable!(
"you should never be able to get here because this type is always wrapped in an option"
);
}
}

pub fn handle_item_take(
carried_item: &mut Option<ItemStack>,
item_slot: &mut Option<ItemStack>,
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/client/combat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl AttackType {
let sprinting = entity.sprinting.load(std::sync::atomic::Ordering::Relaxed);
let on_ground = entity.on_ground.load(std::sync::atomic::Ordering::Relaxed);
let sword = player
.inventory
.inventory()
.lock()
.await
.held_item()
Expand Down
34 changes: 17 additions & 17 deletions pumpkin/src/client/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::sync::Arc;

impl Player {
pub async fn open_container(&self, server: &Server, window_type: WindowType) {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
inventory.state_id = 0;
inventory.total_opened_containers += 1;
let mut container = self.get_open_container(server).await;
Expand All @@ -48,7 +48,7 @@ impl Player {
}

pub async fn set_container_content(&self, container: Option<&mut Box<dyn Container>>) {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;

let total_opened_containers = inventory.total_opened_containers;
let id = if container.is_some() {
Expand Down Expand Up @@ -83,7 +83,7 @@ impl Player {

/// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent
pub async fn close_container(&self) {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
inventory.total_opened_containers += 1;
self.client
.send_packet(&CCloseContainer::new(
Expand All @@ -99,7 +99,7 @@ impl Player {
let (id, value) = window_property.into_tuple();
self.client
.send_packet(&CSetContainerProperty::new(
self.inventory.lock().await.total_opened_containers.into(),
self.inventory().lock().await.total_opened_containers.into(),
id,
value,
))
Expand All @@ -118,7 +118,7 @@ impl Player {
};
let drag_handler = &server.drag_handler;

let state_id = self.inventory.lock().await.state_id;
let state_id = self.inventory().lock().await.state_id;
// This is just checking for regular desync, client hasn't done anything malicious
if state_id != packet.state_id.0 as u32 {
self.set_container_content(opened_container.as_deref_mut())
Expand All @@ -127,7 +127,7 @@ impl Player {
}

if opened_container.is_some() {
let total_containers = self.inventory.lock().await.total_opened_containers;
let total_containers = self.inventory().lock().await.total_opened_containers;
if packet.window_id.0 != total_containers {
return Err(InventoryError::ClosedContainerInteract(self.entity_id()));
}
Expand All @@ -145,7 +145,7 @@ impl Player {
packet.slot,
)?;
let (crafted_item, crafted_item_slot) = {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let combined =
OptionallyCombinedContainer::new(&mut inventory, opened_container.as_deref_mut());
(
Expand Down Expand Up @@ -173,7 +173,7 @@ impl Player {
.await?;
// Checks for if crafted item has been taken
{
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let mut combined =
OptionallyCombinedContainer::new(&mut inventory, opened_container.as_deref_mut());
if combined.crafted_item_slot().is_none() && crafted_item.is_some() {
Expand All @@ -191,7 +191,7 @@ impl Player {
drop(opened_container);
self.send_whole_container_change(server).await?;
} else if let container_click::Slot::Normal(slot_index) = click_slot {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let combined_container =
OptionallyCombinedContainer::new(&mut inventory, Some(&mut opened_container));
if let Some(slot) = combined_container.get_slot_excluding_inventory(slot_index) {
Expand Down Expand Up @@ -275,7 +275,7 @@ impl Player {
slot: container_click::Slot,
taking_crafted: bool,
) -> Result<(), InventoryError> {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);
match slot {
container_click::Slot::Normal(slot) => {
Expand All @@ -299,7 +299,7 @@ impl Player {
slot: container_click::Slot,
taking_crafted: bool,
) -> Result<(), InventoryError> {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);

match slot {
Expand Down Expand Up @@ -357,7 +357,7 @@ impl Player {
KeyClick::Slot(slot) => slot,
KeyClick::Offhand => 45,
};
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let mut changing_item_slot = inventory.get_slot(changing_slot as usize)?.to_owned();
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);

Expand All @@ -379,7 +379,7 @@ impl Player {
if self.gamemode.load() != GameMode::Creative {
return Err(InventoryError::PermissionError);
}
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);
if let Some(Some(item)) = container.all_slots().get_mut(slot) {
self.carried_item.store(Some(item.to_owned()));
Expand All @@ -392,7 +392,7 @@ impl Player {
opened_container: Option<&mut Box<dyn Container>>,
slot: usize,
) -> Result<(), InventoryError> {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);
let mut slots = container.all_slots();

Expand Down Expand Up @@ -451,7 +451,7 @@ impl Player {
drag_handler.add_slot(container_id, player_id, slot).await
}
MouseDragState::End => {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let mut container =
OptionallyCombinedContainer::new(&mut inventory, opened_container);
let mut carried_item = self.carried_item.load();
Expand Down Expand Up @@ -511,7 +511,7 @@ impl Player {
slot: Slot,
) -> Result<(), InventoryError> {
for player in self.get_current_players_in_container(server).await {
let mut inventory = player.inventory.lock().await;
let mut inventory = player.inventory().lock().await;
let total_opened_containers = inventory.total_opened_containers;

// Returns previous value
Expand Down Expand Up @@ -553,7 +553,7 @@ impl Player {

async fn pickup_items(&self, item: &Item, mut amount: u32) {
let max_stack = item.components.max_stack_size;
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let slots = inventory.slots_with_hotbar_first();

let matching_slots = slots.filter_map(|slot| {
Expand Down
8 changes: 4 additions & 4 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ impl Player {
}

if let Some(face) = BlockFace::from_i32(use_item_on.face.0) {
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;
let item_slot = inventory.held_item_mut();
if let Some(item) = item_slot {
let block = get_block_by_item(item.item_id);
Expand Down Expand Up @@ -691,7 +691,7 @@ impl Player {
self.kick(TextComponent::text("Invalid held slot")).await;
return;
}
self.inventory.lock().await.set_selected(slot as usize);
self.inventory().lock().await.set_selected(slot as usize);
}

pub async fn handle_set_creative_slot(
Expand All @@ -703,7 +703,7 @@ impl Player {
}
let valid_slot = packet.slot >= 0 && packet.slot <= 45;
if valid_slot {
self.inventory.lock().await.set_slot(
self.inventory().lock().await.set_slot(
packet.slot as usize,
packet.clicked_item.to_item(),
true,
Expand All @@ -722,7 +722,7 @@ impl Player {
return;
};
// window_id 0 represents both 9x1 Generic AND inventory here
let mut inventory = self.inventory.lock().await;
let mut inventory = self.inventory().lock().await;

inventory.state_id = 0;
let open_container = self.open_container.load();
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/command/commands/cmd_clear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const DESCRIPTION: &str = "Clear yours or targets inventory.";
const ARG_TARGET: &str = "target";

async fn clear_player(target: &Player) -> usize {
let mut inventory = target.inventory.lock().await;
let mut inventory = target.inventory().lock().await;

let slots = inventory.all_slots();
let items_count = slots
Expand Down
25 changes: 23 additions & 2 deletions pumpkin/src/entity/living.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@ use std::sync::atomic::AtomicI32;

use crossbeam::atomic::AtomicCell;
use pumpkin_core::math::vector3::Vector3;
use pumpkin_inventory::{Container, EmptyContainer};
use pumpkin_protocol::client::play::{CDamageEvent, CEntityStatus, CSetEntityMetadata, Metadata};
use tokio::sync::Mutex;

use super::Entity;

/// Represents a living entity within the game world.
///
/// This struct encapsulates the core properties and behaviors of living entities, including players, mobs, and other creatures.
pub struct LivingEntity {
pub struct LivingEntity<C = EmptyContainer>
where
C: Container,
{
/// The underlying entity object, providing basic entity information and functionality.
pub entity: Entity,
/// Previously last known position of the entity
Expand All @@ -22,8 +27,9 @@ pub struct LivingEntity {
pub health: AtomicCell<f32>,
/// The distance the entity has been falling
pub fall_distance: AtomicCell<f64>,
/// Inventory if it exists on the entity
pub inventory: Option<Mutex<C>>,
}

impl LivingEntity {
pub const fn new(entity: Entity) -> Self {
Self {
Expand All @@ -33,6 +39,21 @@ impl LivingEntity {
last_damage_taken: AtomicCell::new(0.0),
health: AtomicCell::new(20.0),
fall_distance: AtomicCell::new(0.0),
// This automatically gets inferred as Option::<EmptyContainer>::None
inventory: None,
}
}
}
impl<C: Container> LivingEntity<C> {
pub fn new_with_container(entity: Entity, inventory: C) -> Self {
Self {
entity,
last_pos: AtomicCell::new(Vector3::new(0.0, 0.0, 0.0)),
time_until_regen: AtomicI32::new(0),
last_damage_taken: AtomicCell::new(0.0),
health: AtomicCell::new(20.0),
fall_distance: AtomicCell::new(0.0),
inventory: Some(Mutex::new(inventory)),
}
}

Expand Down
31 changes: 19 additions & 12 deletions pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub type PlayerPendingChunks =
/// A `Player` is a special type of entity that represents a human player connected to the server.
pub struct Player {
/// The underlying living entity object that represents the player.
pub living_entity: LivingEntity,
pub living_entity: LivingEntity<PlayerInventory>,
/// The player's game profile information, including their username and UUID.
pub gameprofile: GameProfile,
/// The client connection associated with the player.
Expand All @@ -113,8 +113,6 @@ pub struct Player {
pub food: AtomicI32,
/// The player's food saturation level.
pub food_saturation: AtomicCell<f32>,
/// The player's inventory, containing items and equipment.
pub inventory: Mutex<PlayerInventory>,
/// The ID of the currently open container (if any).
pub open_container: AtomicCell<Option<u64>>,
/// The item currently being held by the player.
Expand Down Expand Up @@ -188,14 +186,17 @@ impl Player {
};

Self {
living_entity: LivingEntity::new(Entity::new(
entity_id,
world,
EntityType::Player,
1.62,
AtomicCell::new(BoundingBox::new_default(&bounding_box_size)),
AtomicCell::new(bounding_box_size),
)),
living_entity: LivingEntity::new_with_container(
Entity::new(
entity_id,
world,
EntityType::Player,
1.62,
AtomicCell::new(BoundingBox::new_default(&bounding_box_size)),
AtomicCell::new(bounding_box_size),
),
PlayerInventory::new(),
),
config: Mutex::new(config),
gameprofile,
client,
Expand All @@ -204,7 +205,6 @@ impl Player {
food: AtomicI32::new(20),
food_saturation: AtomicCell::new(20.0),
current_block_destroy_stage: AtomicU8::new(0),
inventory: Mutex::new(PlayerInventory::new()),
open_container: AtomicCell::new(None),
carried_item: AtomicCell::new(None),
teleport_id_count: AtomicI32::new(0),
Expand All @@ -223,6 +223,13 @@ impl Player {
}
}

pub fn inventory(&self) -> &Mutex<PlayerInventory> {
self.living_entity
.inventory
.as_ref()
.expect("Player always has inventory")
}

/// Removes the Player out of the current World
#[allow(unused_variables)]
pub async fn remove(&self) {
Expand Down

0 comments on commit f29cfbc

Please sign in to comment.