mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 02:42:58 +00:00
Crafting: nuke
This commit brings in a much-needed rewrite of crafting transaction handling. The following classes have been removed: - CraftingTransferMaterialAction - CraftingTakeResultAction The following classes have significant changes: - CraftingTransaction - All API methods have been removed and are now handled in CraftItemEvent - CraftItemEvent - added the following: - getInputs() - getOutputs() - getRepetitions() (tells how many times a recipe was crafted in this event) - Recipe interface: - Removed getResult() (individual recipes may handle this differently) - CraftingRecipe interface - removed the following: - matchItems() - getExtraResults() - getAllResults() - added the following - getResults() - getIngredientList() : Item[], which must return a 1D array of items that should be consumed (wildcards accepted). - matchesCraftingGrid(CraftingGrid) - ShapedRecipe - constructor now accepts string[], Item[], Item[] - ShapelessRecipe - constructor now accepts Item[], Item[]
This commit is contained in:
@ -28,11 +28,6 @@ use pocketmine\item\ItemFactory;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
class ShapedRecipe implements CraftingRecipe{
|
||||
/** @var Item */
|
||||
private $primaryResult;
|
||||
/** @var Item[] */
|
||||
private $extraResults = [];
|
||||
|
||||
/** @var UUID|null */
|
||||
private $id = null;
|
||||
|
||||
@ -40,90 +35,76 @@ class ShapedRecipe implements CraftingRecipe{
|
||||
private $shape = [];
|
||||
/** @var Item[] char => Item map */
|
||||
private $ingredientList = [];
|
||||
/** @var Item[] */
|
||||
private $results = [];
|
||||
|
||||
/** @var int */
|
||||
private $height;
|
||||
/** @var int */
|
||||
private $width;
|
||||
|
||||
/**
|
||||
* Constructs a ShapedRecipe instance.
|
||||
*
|
||||
* @param Item $primaryResult
|
||||
* @param string[] $shape<br>
|
||||
* @param string[] $shape <br>
|
||||
* Array of 1, 2, or 3 strings representing the rows of the recipe.
|
||||
* This accepts an array of 1, 2 or 3 strings. Each string should be of the same length and must be at most 3
|
||||
* characters long. Each character represents a unique type of ingredient. Spaces are interpreted as air.
|
||||
* @param Item[] $ingredients<br>
|
||||
* @param Item[] $ingredients <br>
|
||||
* Char => Item map of items to be set into the shape.
|
||||
* This accepts an array of Items, indexed by character. Every unique character (except space) in the shape
|
||||
* array MUST have a corresponding item in this list. Space character is automatically treated as air.
|
||||
* @param Item[] $extraResults<br>
|
||||
* List of additional result items to leave in the crafting grid afterwards. Used for things like cake recipe
|
||||
* empty buckets.
|
||||
* @param Item[] $results List of items that this recipe produces when crafted.
|
||||
*
|
||||
* Note: Recipes **do not** need to be square. Do NOT add padding for empty rows/columns.
|
||||
*/
|
||||
public function __construct(Item $primaryResult, array $shape, array $ingredients, array $extraResults = []){
|
||||
$rowCount = count($shape);
|
||||
if($rowCount > 3 or $rowCount <= 0){
|
||||
throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 rows, not $rowCount");
|
||||
public function __construct(array $shape, array $ingredients, array $results){
|
||||
$this->height = count($shape);
|
||||
if($this->height > 3 or $this->height <= 0){
|
||||
throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 rows, not $this->height");
|
||||
}
|
||||
|
||||
$shape = array_values($shape);
|
||||
|
||||
$columnCount = strlen($shape[0]);
|
||||
if($columnCount > 3 or $columnCount <= 0){
|
||||
throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 columns, not $columnCount");
|
||||
$this->width = strlen($shape[0]);
|
||||
if($this->width > 3 or $this->width <= 0){
|
||||
throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 columns, not $this->width");
|
||||
}
|
||||
|
||||
foreach($shape as $y => $row){
|
||||
if(strlen($row) !== $columnCount){
|
||||
throw new \InvalidArgumentException("Shaped recipe rows must all have the same length (expected $columnCount, got " . strlen($row) . ")");
|
||||
if(strlen($row) !== $this->width){
|
||||
throw new \InvalidArgumentException("Shaped recipe rows must all have the same length (expected $this->width, got " . strlen($row) . ")");
|
||||
}
|
||||
|
||||
for($x = 0; $x < $columnCount; ++$x){
|
||||
for($x = 0; $x < $this->width; ++$x){
|
||||
if($row{$x} !== ' ' and !isset($ingredients[$row{$x}])){
|
||||
throw new \InvalidArgumentException("No item specified for symbol '" . $row{$x} . "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->primaryResult = clone $primaryResult;
|
||||
foreach($extraResults as $item){
|
||||
$this->extraResults[] = clone $item;
|
||||
}
|
||||
|
||||
$this->shape = $shape;
|
||||
|
||||
foreach($ingredients as $char => $i){
|
||||
$this->setIngredient($char, $i);
|
||||
}
|
||||
|
||||
$this->results = array_map(function(Item $item) : Item{ return clone $item; }, $results);
|
||||
}
|
||||
|
||||
public function getWidth() : int{
|
||||
return strlen($this->shape[0]);
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
public function getHeight() : int{
|
||||
return count($this->shape);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getResult() : Item{
|
||||
return $this->primaryResult;
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getExtraResults() : array{
|
||||
return $this->extraResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getAllResults() : array{
|
||||
$results = $this->extraResults;
|
||||
array_unshift($results, $this->primaryResult);
|
||||
return $results;
|
||||
public function getResults() : array{
|
||||
return array_map(function(Item $item) : Item{ return clone $item; }, $this->results);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,8 +145,8 @@ class ShapedRecipe implements CraftingRecipe{
|
||||
public function getIngredientMap() : array{
|
||||
$ingredients = [];
|
||||
|
||||
for($y = 0, $y2 = $this->getHeight(); $y < $y2; ++$y){
|
||||
for($x = 0, $x2 = $this->getWidth(); $x < $x2; ++$x){
|
||||
for($y = 0; $y < $this->height; ++$y){
|
||||
for($x = 0; $x < $this->width; ++$x){
|
||||
$ingredients[$y][$x] = $this->getIngredient($x, $y);
|
||||
}
|
||||
}
|
||||
@ -173,6 +154,24 @@ class ShapedRecipe implements CraftingRecipe{
|
||||
return $ingredients;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getIngredientList() : array{
|
||||
$ingredients = [];
|
||||
|
||||
for($y = 0; $y < $this->height; ++$y){
|
||||
for($x = 0; $x < $this->width; ++$x){
|
||||
$ingredient = $this->getIngredient($x, $y);
|
||||
if(!$ingredient->isNull()){
|
||||
$ingredients[] = $ingredient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ingredients;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
@ -197,34 +196,20 @@ class ShapedRecipe implements CraftingRecipe{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item[][] $input
|
||||
* @param CraftingGrid $grid
|
||||
* @param bool $reverse
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function matchInputMap(array $input) : bool{
|
||||
$map = $this->getIngredientMap();
|
||||
private function matchInputMap(CraftingGrid $grid, bool $reverse) : bool{
|
||||
for($y = 0; $y < $this->height; ++$y){
|
||||
for($x = 0; $x < $this->width; ++$x){
|
||||
|
||||
//match the given items to the requested items
|
||||
for($y = 0, $y2 = $this->getHeight(); $y < $y2; ++$y){
|
||||
for($x = 0, $x2 = $this->getWidth(); $x < $x2; ++$x){
|
||||
$given = $input[$y][$x] ?? null;
|
||||
$required = $map[$y][$x];
|
||||
|
||||
if($given === null or !$required->equals($given, !$required->hasAnyDamageValue(), $required->hasCompoundTag()) or $required->getCount() !== $given->getCount()){
|
||||
$given = $grid->getIngredient($reverse ? $this->width - $x - 1 : $x, $y);
|
||||
$required = $this->getIngredient($x, $y);
|
||||
if(!$required->equals($given, !$required->hasAnyDamageValue(), $required->hasCompoundTag()) or $required->getCount() > $given->getCount()){
|
||||
return false;
|
||||
}
|
||||
|
||||
unset($input[$y][$x]);
|
||||
}
|
||||
}
|
||||
|
||||
//check if there are any items left in the grid outside of the recipe
|
||||
/** @var Item[] $row */
|
||||
foreach($input as $y => $row){
|
||||
foreach($row as $x => $needItem){
|
||||
if(!$needItem->isNull()){
|
||||
return false; //too many input ingredients
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,38 +217,15 @@ class ShapedRecipe implements CraftingRecipe{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item[][] $input
|
||||
* @param Item[][] $output
|
||||
* @param CraftingGrid $grid
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matchItems(array $input, array $output) : bool{
|
||||
if(
|
||||
!$this->matchInputMap($input) and //as-is
|
||||
!$this->matchInputMap(array_map(function(array $row) : array{ return array_reverse($row, false); }, $input)) //mirrored
|
||||
){
|
||||
public function matchesCraftingGrid(CraftingGrid $grid) : bool{
|
||||
if($this->width !== $grid->getRecipeWidth() or $this->height !== $grid->getRecipeHeight()){
|
||||
return false;
|
||||
}
|
||||
|
||||
//and then, finally, check that the output items are good:
|
||||
|
||||
/** @var Item[] $haveItems */
|
||||
$haveItems = array_merge(...$output);
|
||||
$needItems = $this->getExtraResults();
|
||||
foreach($haveItems as $j => $haveItem){
|
||||
if($haveItem->isNull()){
|
||||
unset($haveItems[$j]);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($needItems as $i => $needItem){
|
||||
if($needItem->equals($haveItem, !$needItem->hasAnyDamageValue(), $needItem->hasCompoundTag()) and $needItem->getCount() === $haveItem->getCount()){
|
||||
unset($haveItems[$j], $needItems[$i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count($haveItems) === 0 and count($needItems) === 0;
|
||||
return $this->matchInputMap($grid, false) or $this->matchInputMap($grid, true);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user