mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
move container to LivingEntity (#355)
This commit is contained in:
@@ -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>,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
@@ -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() {
|
||||
@@ -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(
|
||||
@@ -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,
|
||||
))
|
||||
@@ -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())
|
||||
@@ -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()));
|
||||
}
|
||||
@@ -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());
|
||||
(
|
||||
@@ -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() {
|
||||
@@ -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) {
|
||||
@@ -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) => {
|
||||
@@ -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 {
|
||||
@@ -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);
|
||||
|
||||
@@ -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()));
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
@@ -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
|
||||
@@ -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| {
|
||||
|
||||
@@ -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);
|
||||
@@ -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(
|
||||
@@ -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,
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
@@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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,
|
||||
@@ -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),
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user