DelegateInventory: fixed slots being synced twice and breaking ItemStackRequests

the second time the slot is synced, there is no prediction, so the slot update isn't associated with a request anymore. This causes subsequent requests in the same packet to fail, since the dependency request ID isn't associated with the slot anymore.

This change fixes the problem by only allowing the backing inventory to trigger a call to DelegateInventory->on*Change(). While we could have removed and re-added the listener instead, this way is safer since it doesn't assume that the backing inventory won't modify the given item in setItem().

closes #5692
This commit is contained in:
Dylan K. Taylor 2023-04-12 15:42:33 +01:00
parent ba62e0f9cb
commit 7e92da126d
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D

View File

@ -30,6 +30,7 @@ use pocketmine\item\Item;
*/
class DelegateInventory extends BaseInventory{
private InventoryListener $inventoryListener;
private bool $backingInventoryChanging = false;
public function __construct(
private Inventory $backingInventory
@ -39,12 +40,22 @@ class DelegateInventory extends BaseInventory{
$this->backingInventory->getListeners()->add($this->inventoryListener = new CallbackInventoryListener(
static function(Inventory $unused, int $slot, Item $oldItem) use ($weakThis) : void{
if(($strongThis = $weakThis->get()) !== null){
$strongThis->onSlotChange($slot, $oldItem);
$strongThis->backingInventoryChanging = true;
try{
$strongThis->onSlotChange($slot, $oldItem);
}finally{
$strongThis->backingInventoryChanging = false;
}
}
},
static function(Inventory $unused, array $oldContents) use ($weakThis) : void{
if(($strongThis = $weakThis->get()) !== null){
$strongThis->onContentChange($oldContents);
$strongThis->backingInventoryChanging = true;
try{
$strongThis->onContentChange($oldContents);
}finally{
$strongThis->backingInventoryChanging = false;
}
}
}
));
@ -73,4 +84,16 @@ class DelegateInventory extends BaseInventory{
protected function internalSetContents(array $items) : void{
$this->backingInventory->setContents($items);
}
protected function onSlotChange(int $index, Item $before) : void{
if($this->backingInventoryChanging){
parent::onSlotChange($index, $before);
}
}
protected function onContentChange(array $itemsBefore) : void{
if($this->backingInventoryChanging){
parent::onContentChange($itemsBefore);
}
}
}