mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-10 21:45:35 +00:00
Confine legacy transaction handling to dropping items only
This commit is contained in:
parent
2e9a3f9160
commit
eedc943766
@ -31,11 +31,11 @@ use pocketmine\entity\animation\ConsumingItemAnimation;
|
|||||||
use pocketmine\entity\Attribute;
|
use pocketmine\entity\Attribute;
|
||||||
use pocketmine\entity\InvalidSkinException;
|
use pocketmine\entity\InvalidSkinException;
|
||||||
use pocketmine\event\player\PlayerEditBookEvent;
|
use pocketmine\event\player\PlayerEditBookEvent;
|
||||||
use pocketmine\inventory\transaction\action\InventoryAction;
|
use pocketmine\inventory\transaction\action\DropItemAction;
|
||||||
use pocketmine\inventory\transaction\CraftingTransaction;
|
use pocketmine\inventory\transaction\CraftingTransaction;
|
||||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||||
|
use pocketmine\inventory\transaction\TransactionBuilder;
|
||||||
use pocketmine\inventory\transaction\TransactionException;
|
use pocketmine\inventory\transaction\TransactionException;
|
||||||
use pocketmine\inventory\transaction\TransactionValidationException;
|
|
||||||
use pocketmine\item\VanillaItems;
|
use pocketmine\item\VanillaItems;
|
||||||
use pocketmine\item\WritableBook;
|
use pocketmine\item\WritableBook;
|
||||||
use pocketmine\item\WritableBookPage;
|
use pocketmine\item\WritableBookPage;
|
||||||
@ -99,7 +99,6 @@ use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData;
|
|||||||
use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData;
|
use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequest;
|
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequest;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponse;
|
use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponse;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData;
|
use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData;
|
use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData;
|
||||||
use pocketmine\network\mcpe\protocol\types\PlayerAction;
|
use pocketmine\network\mcpe\protocol\types\PlayerAction;
|
||||||
@ -378,72 +377,49 @@ class InGamePacketHandler extends PacketHandler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function handleNormalTransaction(NormalTransactionData $data, int $itemStackRequestId) : bool{
|
private function handleNormalTransaction(NormalTransactionData $data, int $itemStackRequestId) : bool{
|
||||||
/** @var InventoryAction[] $actions */
|
//When the ItemStackRequest system is used, this transaction type is only used for dropping items by pressing Q.
|
||||||
$actions = [];
|
//I don't know why they don't just use ItemStackRequest for that too, which already supports dropping items by
|
||||||
|
//clicking them outside an open inventory menu, but for now it is what it is.
|
||||||
|
//Fortunately, this means we can be extremely strict about the validation criteria.
|
||||||
|
|
||||||
|
if(count($data->getActions()) > 2){
|
||||||
|
throw new PacketHandlingException("Expected exactly 2 actions for dropping an item");
|
||||||
|
}
|
||||||
|
|
||||||
$isCraftingPart = false;
|
|
||||||
$converter = TypeConverter::getInstance();
|
|
||||||
foreach($data->getActions() as $networkInventoryAction){
|
foreach($data->getActions() as $networkInventoryAction){
|
||||||
if(
|
if($networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_WORLD){
|
||||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO || (
|
//drop item - we don't need to validate this, we only care about the count
|
||||||
$this->craftingTransaction !== null &&
|
//if the resulting actions don't match the client for some reason, it will trigger an automatic
|
||||||
!$networkInventoryAction->oldItem->getItemStack()->equals($networkInventoryAction->newItem->getItemStack()) &&
|
//prediction rollback anyway.
|
||||||
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER &&
|
//it's technically possible to see this more than once, but a normal client should never do that.
|
||||||
$networkInventoryAction->windowId === ContainerIds::UI &&
|
$inventory = $this->player->getInventory();
|
||||||
$networkInventoryAction->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT
|
$heldItem = $inventory->getItemInHand();
|
||||||
)
|
|
||||||
){
|
|
||||||
$isCraftingPart = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$action = $converter->createInventoryAction($networkInventoryAction, $this->player, $this->inventoryManager);
|
$droppedItem = TypeConverter::getInstance()->netItemStackToCore($networkInventoryAction->newItem->getItemStack());
|
||||||
if($action !== null){
|
}catch(TypeConversionException $e){
|
||||||
$actions[] = $action;
|
throw PacketHandlingException::wrap($e);
|
||||||
}
|
}
|
||||||
}catch(TypeConversionException $e){
|
|
||||||
$this->session->getLogger()->debug("Error unpacking inventory action: " . $e->getMessage());
|
//TODO: if we can avoid decoding incoming item NBT, it will be faster to compare network ItemStacks
|
||||||
return false;
|
//rather than converting to internal itemstacks and using canStackWith() here.
|
||||||
|
if(!$heldItem->canStackWith($droppedItem) || $heldItem->getCount() < $droppedItem->getCount()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//purposely overwritten here - this allows any immutable internal references to be shared
|
||||||
|
$droppedItem = $heldItem->pop($droppedItem->getCount());
|
||||||
|
|
||||||
|
$builder = new TransactionBuilder();
|
||||||
|
$builder->getInventory($inventory)->setItem($inventory->getHeldItemIndex(), $heldItem);
|
||||||
|
$builder->addAction(new DropItemAction($droppedItem));
|
||||||
|
|
||||||
|
$transaction = new InventoryTransaction($this->player, $builder->generateActions());
|
||||||
|
return $this->executeInventoryTransaction($transaction, $itemStackRequestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($isCraftingPart){
|
throw new PacketHandlingException("Legacy 'normal' transactions should only be used for dropping items");
|
||||||
if($this->craftingTransaction === null){
|
|
||||||
//TODO: this might not be crafting if there is a special inventory open (anvil, enchanting, loom etc)
|
|
||||||
$this->craftingTransaction = new CraftingTransaction($this->player, $this->player->getServer()->getCraftingManager(), $actions);
|
|
||||||
}else{
|
|
||||||
foreach($actions as $action){
|
|
||||||
$this->craftingTransaction->addAction($action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try{
|
|
||||||
$this->craftingTransaction->validate();
|
|
||||||
}catch(TransactionValidationException $e){
|
|
||||||
//transaction is incomplete - crafting transaction comes in lots of little bits, so we have to collect
|
|
||||||
//all of the parts before we can execute it
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
try{
|
|
||||||
return $this->executeInventoryTransaction($this->craftingTransaction, $itemStackRequestId);
|
|
||||||
}finally{
|
|
||||||
$this->craftingTransaction = null;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
//normal transaction fallthru
|
|
||||||
if($this->craftingTransaction !== null){
|
|
||||||
$this->session->getLogger()->debug("Got unexpected normal inventory action with incomplete crafting transaction, refusing to execute crafting");
|
|
||||||
$this->craftingTransaction = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count($actions) === 0){
|
|
||||||
//TODO: 1.13+ often sends transactions with nothing but useless crap in them, no need for the debug noise
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->executeInventoryTransaction(new InventoryTransaction($this->player, $actions), $itemStackRequestId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function handleUseItemTransaction(UseItemTransactionData $data) : bool{
|
private function handleUseItemTransaction(UseItemTransactionData $data) : bool{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user