mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-06 17:59:48 +00:00
Rewritten crafting, fixed #45
This commit is contained in:
193
src/pocketmine/inventory/transaction/CraftingTransaction.php
Normal file
193
src/pocketmine/inventory/transaction/CraftingTransaction.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory\transaction;
|
||||
|
||||
use pocketmine\event\inventory\CraftItemEvent;
|
||||
use pocketmine\inventory\BigCraftingGrid;
|
||||
use pocketmine\inventory\CraftingRecipe;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\Player;
|
||||
|
||||
class CraftingTransaction extends InventoryTransaction{
|
||||
|
||||
protected $gridSize;
|
||||
/** @var Item[][] */
|
||||
protected $inputs;
|
||||
/** @var Item[][] */
|
||||
protected $secondaryOutputs;
|
||||
/** @var Item|null */
|
||||
protected $primaryOutput;
|
||||
|
||||
private $isReindexed = false;
|
||||
|
||||
/** @var CraftingRecipe|null */
|
||||
protected $recipe = null;
|
||||
|
||||
public function __construct(Player $source, $actions = []){
|
||||
$this->gridSize = ($source->getCraftingGrid() instanceof BigCraftingGrid) ? 3 : 2;
|
||||
|
||||
$air = ItemFactory::get(Item::AIR, 0, 0);
|
||||
$this->inputs = array_fill(0, $this->gridSize, array_fill(0, $this->gridSize, $air));
|
||||
$this->secondaryOutputs = array_fill(0, $this->gridSize, array_fill(0, $this->gridSize, $air));
|
||||
|
||||
parent::__construct($source, $actions);
|
||||
}
|
||||
|
||||
public function setInput(int $index, Item $item) : void{
|
||||
$y = (int) ($index / $this->gridSize);
|
||||
$x = $index % $this->gridSize;
|
||||
|
||||
if($this->inputs[$y][$x]->isNull()){
|
||||
$this->inputs[$y][$x] = clone $item;
|
||||
}else{
|
||||
throw new \RuntimeException("Input $index has already been set");
|
||||
}
|
||||
}
|
||||
|
||||
public function getInputMap() : array{
|
||||
return $this->inputs;
|
||||
}
|
||||
|
||||
public function setExtraOutput(int $index, Item $item) : void{
|
||||
$y = (int) ($index / $this->gridSize);
|
||||
$x = $index % $this->gridSize;
|
||||
|
||||
if($this->secondaryOutputs[$y][$x]->isNull()){
|
||||
$this->secondaryOutputs[$y][$x] = clone $item;
|
||||
}else{
|
||||
throw new \RuntimeException("Output $index has already been set");
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrimaryOutput() : ?Item{
|
||||
return $this->primaryOutput;
|
||||
}
|
||||
|
||||
public function setPrimaryOutput(Item $item) : void{
|
||||
if($this->primaryOutput === null){
|
||||
$this->primaryOutput = clone $item;
|
||||
}else{
|
||||
throw new \RuntimeException("Primary result item has already been set");
|
||||
}
|
||||
}
|
||||
|
||||
public function getRecipe() : ?CraftingRecipe{
|
||||
return $this->recipe;
|
||||
}
|
||||
|
||||
private function reindexInputs() : void{
|
||||
if($this->isReindexed){
|
||||
return;
|
||||
}
|
||||
|
||||
$xOffset = $this->gridSize;
|
||||
$yOffset = $this->gridSize;
|
||||
|
||||
$height = 0;
|
||||
$width = 0;
|
||||
|
||||
foreach($this->inputs as $y => $row){
|
||||
foreach($row as $x => $item){
|
||||
if(!$item->isNull()){
|
||||
$xOffset = min($x, $xOffset);
|
||||
$yOffset = min($y, $yOffset);
|
||||
|
||||
$height = max($y + 1 - $yOffset, $height);
|
||||
$width = max($x + 1 - $xOffset, $width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($height === 0 or $width === 0){
|
||||
return;
|
||||
}
|
||||
|
||||
$air = ItemFactory::get(Item::AIR, 0, 0);
|
||||
$reindexed = array_fill(0, $height, array_fill(0, $width, $air));
|
||||
foreach($reindexed as $y => $row){
|
||||
foreach($row as $x => $item){
|
||||
$reindexed[$y][$x] = $this->inputs[$y + $yOffset][$x + $xOffset];
|
||||
}
|
||||
}
|
||||
|
||||
$this->inputs = $reindexed;
|
||||
|
||||
$this->isReindexed = true;
|
||||
}
|
||||
|
||||
public function canExecute() : bool{
|
||||
$this->reindexInputs();
|
||||
|
||||
$this->recipe = $this->source->getServer()->getCraftingManager()->matchRecipe($this->inputs, $this->primaryOutput, $this->secondaryOutputs);
|
||||
|
||||
return $this->recipe !== null and parent::canExecute();
|
||||
}
|
||||
|
||||
protected function callExecuteEvent() : bool{
|
||||
$this->source->getServer()->getPluginManager()->callEvent($ev = new CraftItemEvent($this));
|
||||
return !$ev->isCancelled();
|
||||
}
|
||||
|
||||
public function execute() : bool{
|
||||
if(parent::execute()){
|
||||
switch($this->primaryOutput->getId()){
|
||||
case Item::CRAFTING_TABLE:
|
||||
$this->source->awardAchievement("buildWorkBench");
|
||||
break;
|
||||
case Item::WOODEN_PICKAXE:
|
||||
$this->source->awardAchievement("buildPickaxe");
|
||||
break;
|
||||
case Item::FURNACE:
|
||||
$this->source->awardAchievement("buildFurnace");
|
||||
break;
|
||||
case Item::WOODEN_HOE:
|
||||
$this->source->awardAchievement("buildHoe");
|
||||
break;
|
||||
case Item::BREAD:
|
||||
$this->source->awardAchievement("makeBread");
|
||||
break;
|
||||
case Item::CAKE:
|
||||
$this->source->awardAchievement("bakeCake");
|
||||
break;
|
||||
case Item::STONE_PICKAXE:
|
||||
case Item::GOLDEN_PICKAXE:
|
||||
case Item::IRON_PICKAXE:
|
||||
case Item::DIAMOND_PICKAXE:
|
||||
$this->source->awardAchievement("buildBetterPickaxe");
|
||||
break;
|
||||
case Item::WOODEN_SWORD:
|
||||
$this->source->awardAchievement("buildSword");
|
||||
break;
|
||||
case Item::DIAMOND:
|
||||
$this->source->awardAchievement("diamond");
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ class InventoryTransaction{
|
||||
private $creationTime;
|
||||
protected $hasExecuted = false;
|
||||
/** @var Player */
|
||||
protected $source = null;
|
||||
protected $source;
|
||||
|
||||
/** @var Inventory[] */
|
||||
protected $inventories = [];
|
||||
@ -52,7 +52,7 @@ class InventoryTransaction{
|
||||
* @param Player $source
|
||||
* @param InventoryAction[] $actions
|
||||
*/
|
||||
public function __construct(Player $source = null, array $actions = []){
|
||||
public function __construct(Player $source, array $actions = []){
|
||||
$this->creationTime = microtime(true);
|
||||
$this->source = $source;
|
||||
foreach($actions as $action){
|
||||
@ -219,8 +219,6 @@ class InventoryTransaction{
|
||||
}
|
||||
|
||||
$this->addAction(new SlotChangeAction($originalAction->getInventory(), $originalAction->getSlot(), $originalAction->getSourceItem(), $lastTargetItem));
|
||||
|
||||
MainLogger::getLogger()->debug("Successfully compacted " . count($originalList) . " actions for " . $this->source->getName());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -243,6 +241,11 @@ class InventoryTransaction{
|
||||
}
|
||||
}
|
||||
|
||||
protected function callExecuteEvent() : bool{
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new InventoryTransactionEvent($this));
|
||||
return !$ev->isCancelled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@ -251,8 +254,7 @@ class InventoryTransaction{
|
||||
return false;
|
||||
}
|
||||
|
||||
Server::getInstance()->getPluginManager()->callEvent($ev = new InventoryTransactionEvent($this));
|
||||
if($ev->isCancelled()){
|
||||
if(!$this->callExecuteEvent()){
|
||||
$this->handleFailed();
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory\transaction\action;
|
||||
|
||||
use pocketmine\inventory\transaction\CraftingTransaction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\Player;
|
||||
|
||||
/**
|
||||
* Action used to take the primary result item during crafting.
|
||||
*/
|
||||
class CraftingTakeResultAction extends InventoryAction{
|
||||
|
||||
public function onAddToTransaction(InventoryTransaction $transaction) : void{
|
||||
if($transaction instanceof CraftingTransaction){
|
||||
$transaction->setPrimaryOutput($this->getSourceItem());
|
||||
}else{
|
||||
throw new \InvalidStateException(get_class($this) . " can only be added to CraftingTransactions");
|
||||
}
|
||||
}
|
||||
|
||||
public function isValid(Player $source) : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function execute(Player $source) : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onExecuteSuccess(Player $source) : void{
|
||||
|
||||
}
|
||||
|
||||
public function onExecuteFail(Player $source) : void{
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory\transaction\action;
|
||||
|
||||
use pocketmine\inventory\transaction\CraftingTransaction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Player;
|
||||
|
||||
/**
|
||||
* Action used to take ingredients out of the crafting grid, or put secondary results into the crafting grid, when
|
||||
* crafting.
|
||||
*/
|
||||
class CraftingTransferMaterialAction extends InventoryAction{
|
||||
/** @var int */
|
||||
private $slot;
|
||||
|
||||
public function __construct(Item $sourceItem, Item $targetItem, int $slot){
|
||||
parent::__construct($sourceItem, $targetItem);
|
||||
$this->slot = $slot;
|
||||
}
|
||||
|
||||
public function onAddToTransaction(InventoryTransaction $transaction) : void{
|
||||
if($transaction instanceof CraftingTransaction){
|
||||
if($this->sourceItem->isNull()){
|
||||
$transaction->setInput($this->slot, $this->targetItem);
|
||||
}elseif($this->targetItem->isNull()){
|
||||
$transaction->setExtraOutput($this->slot, $this->sourceItem);
|
||||
}else{
|
||||
throw new \InvalidStateException("Invalid " . get_class($this) . ", either source or target item must be air, got source: " . $this->sourceItem . ", target: " . $this->targetItem);
|
||||
}
|
||||
}else{
|
||||
throw new \InvalidStateException(get_class($this) . " can only be added to CraftingTransactions");
|
||||
}
|
||||
}
|
||||
|
||||
public function isValid(Player $source) : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function execute(Player $source) : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onExecuteSuccess(Player $source) : void{
|
||||
|
||||
}
|
||||
|
||||
public function onExecuteFail(Player $source) : void{
|
||||
|
||||
}
|
||||
}
|
@ -83,6 +83,7 @@ class SlotChangeAction extends InventoryAction{
|
||||
* Adds this action's target inventory to the transaction's inventory list.
|
||||
*
|
||||
* @param InventoryTransaction $transaction
|
||||
*
|
||||
*/
|
||||
public function onAddToTransaction(InventoryTransaction $transaction) : void{
|
||||
$transaction->addInventory($this->inventory);
|
||||
|
Reference in New Issue
Block a user