Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor global block container system #427

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 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, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
/// Aka Block Position
pub struct WorldPosition(pub Vector3<i32>);

Expand Down
2 changes: 2 additions & 0 deletions pumpkin-inventory/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ thiserror.workspace = true

num-traits.workspace = true
num-derive.workspace = true
rand = "0.8.5"
uuid = { version = "1.11.0", features = ["v4"] }
53 changes: 49 additions & 4 deletions pumpkin-inventory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,18 @@ pub trait Container: Sync + Send {

fn all_slots_ref(&self) -> Vec<Option<&ItemStack>>;

fn clear_all_slots(&mut self) {
let all_slots = self.all_slots();
for stack in all_slots {
*stack = None;
fn destroy_container(
&mut self,
player_inventory: &mut PlayerInventory,
carried_item: &mut Option<ItemStack>,
unique: bool,
) {
if unique {
self.combine_container_with_player_inventory(player_inventory)
}
// TODO: Add drop for these remaining things
self.all_slots().into_iter().for_each(|slot| *slot = None);
*carried_item = None;
}

fn all_combinable_slots(&self) -> Vec<Option<&ItemStack>> {
Expand Down Expand Up @@ -132,6 +139,44 @@ pub trait Container: Sync + Send {
}

fn recipe_used(&mut self) {}

fn combine_container_with_player_inventory(&mut self, player_inventory: &mut PlayerInventory) {
let slots = self
.all_slots()
.into_iter()
.filter_map(|slot| {
if let Some(stack) = slot {
let stack = *stack;
Some((slot, stack))
} else {
None
}
})
.collect::<Vec<_>>();
let mut receiving_slots = player_inventory
.slots_with_hotbar_first()
.collect::<Vec<_>>();

for (slot, stack) in slots {
let matches = receiving_slots.iter_mut().filter_map(|slot| {
if let Some(receiving_stack) = slot {
if receiving_stack.item_id == stack.item_id {
Some(receiving_stack)
} else {
None
}
} else {
None
}
});
for receiving_slot in matches {
if slot.is_none() {
break;
}
combine_stacks(slot, receiving_slot, MouseClick::Left);
}
}
}
}

pub struct EmptyContainer;
Expand Down
146 changes: 108 additions & 38 deletions pumpkin-inventory/src/open_container.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,111 @@
use crate::crafting::check_if_matches_crafting;
use crate::player::PlayerInventory;
use crate::{Container, WindowType};
use pumpkin_core::math::position::WorldPosition;
use pumpkin_world::block::block_registry::Block;
use pumpkin_world::item::ItemStack;
use rand::random;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use uuid::Uuid;

#[derive(Default)]
pub struct ContainerHolder {
pub containers_by_id: HashMap<usize, OpenContainer>,
pub location_to_container_id: HashMap<WorldPosition, usize>,
}

impl ContainerHolder {
pub async fn destroy(
&mut self,
id: usize,
player_inventory: &mut PlayerInventory,
carried_item: &mut Option<ItemStack>,
) -> Vec<Uuid> {
if let Some(container) = self.containers_by_id.remove(&id) {
let unique = container.unique;
let players = container.players;
let mut container = container.container.lock().await;
container.destroy_container(player_inventory, carried_item, unique);
players
} else {
vec![]
}
}

pub async fn destroy_by_location(
&mut self,
location: &WorldPosition,
player_inventory: &mut PlayerInventory,
carried_item: &mut Option<ItemStack>,
) -> Vec<Uuid> {
if let Some(id) = self.location_to_container_id.remove(location) {
self.destroy(id, player_inventory, carried_item).await
} else {
vec![]
}
}

pub fn get_by_location(&self, location: &WorldPosition) -> Option<&OpenContainer> {
self.containers_by_id
.get(self.location_to_container_id.get(location)?)
}

pub fn get_mut_by_location(&mut self, location: &WorldPosition) -> Option<&mut OpenContainer> {
self.containers_by_id
.get_mut(self.location_to_container_id.get(location)?)
}

pub fn new_by_location<C: Container + Default + 'static>(
&mut self,
location: WorldPosition,
block: Option<Block>,
) -> Option<&mut OpenContainer> {
if self.location_to_container_id.contains_key(&location) {
return None;
}
let id = self.new_container::<C>(block, false);
self.location_to_container_id.insert(location, id);
self.containers_by_id.get_mut(&id)
}

pub fn new_container<C: Container + Default + 'static>(
&mut self,
block: Option<Block>,
unique: bool,
) -> usize {
let mut id: usize = random();
let mut new_container = OpenContainer::new_empty_container::<C>(block, unique);
while let Some(container) = self.containers_by_id.insert(id, new_container) {
new_container = container;
id = random();
}
id
}

pub fn new_unique<C: Container + Default + 'static>(
&mut self,
block: Option<Block>,
player_id: Uuid,
) -> usize {
let id = self.new_container::<C>(block, true);
let container = self.containers_by_id.get_mut(&id).expect("just created it");
container.players.push(player_id);
id
}
}

pub struct OpenContainer {
// TODO: unique id should be here
// TODO: should this be uuid?
players: Vec<i32>,
container: Arc<Mutex<Box<dyn Container>>>,
location: Option<WorldPosition>,
pub unique: bool,
block: Option<Block>,
pub id: usize,
container: Arc<Mutex<Box<dyn Container>>>,
players: Vec<Uuid>,
}

impl OpenContainer {
pub fn try_open(&self, player_id: i32) -> Option<&Arc<Mutex<Box<dyn Container>>>> {
pub fn try_open(&self, player_id: Uuid) -> Option<&Arc<Mutex<Box<dyn Container>>>> {
if !self.players.contains(&player_id) {
log::debug!("couldn't open container");
return None;
Expand All @@ -25,13 +114,13 @@ impl OpenContainer {
Some(container)
}

pub fn add_player(&mut self, player_id: i32) {
pub fn add_player(&mut self, player_id: Uuid) {
if !self.players.contains(&player_id) {
self.players.push(player_id);
}
}

pub fn remove_player(&mut self, player_id: i32) {
pub fn remove_player(&mut self, player_id: Uuid) {
if let Some(index) = self.players.iter().enumerate().find_map(|(index, id)| {
if *id == player_id {
Some(index)
Expand All @@ -44,53 +133,34 @@ impl OpenContainer {
}

pub fn new_empty_container<C: Container + Default + 'static>(
player_id: i32,
location: Option<WorldPosition>,
block: Option<Block>,
unique: bool,
) -> Self {
Self {
players: vec![player_id],
unique,
players: vec![],
container: Arc::new(Mutex::new(Box::new(C::default()))),
location,
block,
id: 0,
}
}

pub fn is_location(&self, try_position: WorldPosition) -> bool {
if let Some(location) = self.location {
location == try_position
} else {
false
}
}

pub async fn clear_all_slots(&self) {
self.container.lock().await.clear_all_slots();
}

pub fn clear_all_players(&mut self) {
self.players = vec![];
}

pub fn all_player_ids(&self) -> Vec<i32> {
self.players.clone()
}

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

pub fn get_location(&self) -> Option<WorldPosition> {
self.location
}

pub async fn set_location(&mut self, location: Option<WorldPosition>) {
self.location = location;
pub fn all_player_ids(&self) -> &[Uuid] {
&self.players
}

pub fn get_block(&self) -> Option<Block> {
self.block.clone()
}

pub async fn window_type(&self) -> &'static WindowType {
let container = self.container.lock().await;
container.window_type()
}
}
#[derive(Default)]
pub struct Chest([Option<ItemStack>; 27]);
Expand Down
6 changes: 1 addition & 5 deletions pumpkin/src/block/block_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
use crate::entity::player::Player;
use crate::server::Server;
use pumpkin_core::math::position::WorldPosition;
use pumpkin_inventory::OpenContainer;
use pumpkin_world::block::block_registry::Block;
use pumpkin_world::item::item_registry::Item;
use std::collections::HashMap;
Expand Down Expand Up @@ -91,13 +90,10 @@ impl BlockManager {
player: &Player,
location: WorldPosition,
server: &Server,
container: &mut OpenContainer,
) {
let pumpkin_block = self.get_pumpkin_block(block);
if let Some(pumpkin_block) = pumpkin_block {
pumpkin_block
.on_close(block, player, location, server, container)
.await;
pumpkin_block.on_close(player, location, server).await;
}
}

Expand Down
Loading
Loading