mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
fix: close container screens when their block is destroyed (#1539)
Track the block position of open container screens on the player and close them when the underlying block is broken or exploded, preventing ghost UIs and item duplication. Closes #1512
This commit is contained in:
@@ -60,7 +60,7 @@ impl BlockBehaviour for BarrelBlock {
|
||||
&& let Some(inventory) = block_entity.get_inventory()
|
||||
{
|
||||
args.player
|
||||
.open_handled_screen(&BarrelScreenFactory(inventory))
|
||||
.open_handled_screen(&BarrelScreenFactory(inventory), Some(*args.position))
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ impl BlockBehaviour for BlastFurnaceBlock {
|
||||
experience_container,
|
||||
);
|
||||
args.player
|
||||
.open_handled_screen(&blasting_furnace_screen_factory)
|
||||
.open_handled_screen(&blasting_furnace_screen_factory, Some(*args.position))
|
||||
.await;
|
||||
}
|
||||
crate::block::registry::BlockActionResult::Consume
|
||||
|
||||
@@ -182,7 +182,7 @@ impl BlockBehaviour for ChestBlock {
|
||||
};
|
||||
|
||||
args.player
|
||||
.open_handled_screen(&ChestScreenFactory(inventory))
|
||||
.open_handled_screen(&ChestScreenFactory(inventory), Some(*args.position))
|
||||
.await;
|
||||
|
||||
BlockActionResult::Success
|
||||
@@ -330,7 +330,7 @@ impl BlockBehaviour for CopperChestBlock {
|
||||
};
|
||||
|
||||
args.player
|
||||
.open_handled_screen(&ChestScreenFactory(inventory))
|
||||
.open_handled_screen(&ChestScreenFactory(inventory), Some(*args.position))
|
||||
.await;
|
||||
|
||||
BlockActionResult::Success
|
||||
|
||||
@@ -19,7 +19,7 @@ impl BlockBehaviour for CraftingTableBlock {
|
||||
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
|
||||
Box::pin(async move {
|
||||
args.player
|
||||
.open_handled_screen(&CraftingTableScreenFactory)
|
||||
.open_handled_screen(&CraftingTableScreenFactory, Some(*args.position))
|
||||
.await;
|
||||
|
||||
BlockActionResult::Success
|
||||
|
||||
@@ -83,7 +83,10 @@ impl BlockBehaviour for EnderChestBlock {
|
||||
let inventory = args.player.ender_chest_inventory();
|
||||
inventory.set_tracker(block_entity.get_tracker()).await;
|
||||
args.player
|
||||
.open_handled_screen(&EnderChestScreenFactory(inventory.clone()))
|
||||
.open_handled_screen(
|
||||
&EnderChestScreenFactory(inventory.clone()),
|
||||
Some(*args.position),
|
||||
)
|
||||
.await;
|
||||
|
||||
// TODO: player.incrementStat(Stats.OPEN_ENDERCHEST);
|
||||
|
||||
@@ -93,7 +93,7 @@ impl BlockBehaviour for FurnaceBlock {
|
||||
let furnace_screen_factory =
|
||||
FurnaceScreenFactory::new(inventory, property_delegate, experience_container);
|
||||
args.player
|
||||
.open_handled_screen(&furnace_screen_factory)
|
||||
.open_handled_screen(&furnace_screen_factory, Some(*args.position))
|
||||
.await;
|
||||
}
|
||||
crate::block::registry::BlockActionResult::Consume
|
||||
|
||||
@@ -59,7 +59,7 @@ impl BlockBehaviour for HopperBlock {
|
||||
&& let Some(inventory) = block_entity.get_inventory()
|
||||
{
|
||||
args.player
|
||||
.open_handled_screen(&HopperBlockScreenFactory(inventory))
|
||||
.open_handled_screen(&HopperBlockScreenFactory(inventory), Some(*args.position))
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ impl BlockBehaviour for DropperBlock {
|
||||
&& let Some(inventory) = block_entity.get_inventory()
|
||||
{
|
||||
args.player
|
||||
.open_handled_screen(&DropperScreenFactory(inventory))
|
||||
.open_handled_screen(&DropperScreenFactory(inventory), Some(*args.position))
|
||||
.await;
|
||||
}
|
||||
BlockActionResult::Success
|
||||
|
||||
@@ -87,7 +87,7 @@ impl BlockBehaviour for ShulkerBoxBlock {
|
||||
&& let Some(inventory) = block_entity.get_inventory()
|
||||
{
|
||||
args.player
|
||||
.open_handled_screen(&ShulkerBoxScreenFactory(inventory))
|
||||
.open_handled_screen(&ShulkerBoxScreenFactory(inventory), Some(*args.position))
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ impl BlockBehaviour for SmokerBlock {
|
||||
let smoker_screen_factory =
|
||||
SmokerScreenFactory::new(inventory, property_delegate, experience_container);
|
||||
args.player
|
||||
.open_handled_screen(&smoker_screen_factory)
|
||||
.open_handled_screen(&smoker_screen_factory, Some(*args.position))
|
||||
.await;
|
||||
}
|
||||
crate::block::registry::BlockActionResult::Consume
|
||||
|
||||
@@ -374,6 +374,8 @@ pub struct Player {
|
||||
pub hunger_manager: HungerManager,
|
||||
/// The ID of the currently open container (if any).
|
||||
pub open_container: AtomicCell<Option<u64>>,
|
||||
/// The block position of the currently open container screen (if any).
|
||||
pub open_container_pos: AtomicCell<Option<BlockPos>>,
|
||||
/// The item currently being held by the player.
|
||||
pub carried_item: Mutex<Option<ItemStack>>,
|
||||
/// The player's abilities and special powers.
|
||||
@@ -490,6 +492,7 @@ impl Player {
|
||||
hunger_manager: HungerManager::default(),
|
||||
current_block_destroy_stage: AtomicI32::new(-1),
|
||||
open_container: AtomicCell::new(None),
|
||||
open_container_pos: AtomicCell::new(None),
|
||||
tick_counter: AtomicI32::new(0),
|
||||
packet_sequence: AtomicI32::new(-1),
|
||||
start_mining_time: AtomicI32::new(0),
|
||||
@@ -2577,6 +2580,7 @@ impl Player {
|
||||
}
|
||||
|
||||
*self.current_screen_handler.lock().await = self.player_screen_handler.clone();
|
||||
self.open_container_pos.store(None);
|
||||
}
|
||||
|
||||
pub async fn on_screen_handler_opened(&self, screen_handler: Arc<Mutex<dyn ScreenHandler>>) {
|
||||
@@ -2594,6 +2598,7 @@ impl Player {
|
||||
pub async fn open_handled_screen(
|
||||
&self,
|
||||
screen_handler_factory: &dyn ScreenHandlerFactory,
|
||||
block_pos: Option<BlockPos>,
|
||||
) -> Option<u8> {
|
||||
if !self
|
||||
.current_screen_handler
|
||||
@@ -2631,6 +2636,7 @@ impl Player {
|
||||
drop(screen_handler_temp);
|
||||
self.on_screen_handler_opened(screen_handler.clone()).await;
|
||||
*self.current_screen_handler.lock().await = screen_handler;
|
||||
self.open_container_pos.store(block_pos);
|
||||
Some(self.screen_handler_sync_id.load(Ordering::Relaxed))
|
||||
} else {
|
||||
//TODO: Send message if spectator
|
||||
|
||||
@@ -207,6 +207,7 @@ impl Explosion {
|
||||
self.damage_entities(world).await;
|
||||
for (pos, (block, state)) in &blocks {
|
||||
world.set_block_state(pos, 0, BlockFlags::NOTIFY_ALL).await;
|
||||
world.close_container_screens_at(pos).await;
|
||||
|
||||
let pumpkin_block = world.block_registry.get_pumpkin_block(block.id);
|
||||
|
||||
|
||||
@@ -2930,6 +2930,9 @@ impl World {
|
||||
|
||||
let broken_state_id = self.set_block_state(position, new_state_id, flags).await;
|
||||
|
||||
// Close container screens for any players viewing this block
|
||||
self.close_container_screens_at(position).await;
|
||||
|
||||
if Block::from_state_id(broken_state_id) != &Block::FIRE {
|
||||
let particles_packet = CWorldEvent::new(
|
||||
WorldEvent::BlockBroken as i32,
|
||||
@@ -2958,6 +2961,16 @@ impl World {
|
||||
None
|
||||
}
|
||||
|
||||
/// Close container screens for all players who have a container open at the given block position.
|
||||
pub async fn close_container_screens_at(&self, position: &BlockPos) {
|
||||
let players = self.players.load();
|
||||
for player in players.iter() {
|
||||
if player.open_container_pos.load() == Some(*position) {
|
||||
player.close_handled_screen().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn drop_stack(self: &Arc<Self>, pos: &BlockPos, stack: ItemStack) {
|
||||
let height = EntityType::ITEM.dimension[1] / 2.0;
|
||||
let spawn_pos = {
|
||||
|
||||
Reference in New Issue
Block a user