Cleaned up ShapedRecipe handling, ShapedRecipe API changes

use shapes from json instead of just generating maps
fix a ton of bugs
This commit is contained in:
Dylan K. Taylor 2017-09-17 11:45:09 +01:00
parent c8199e14ad
commit 642c7733cd
2 changed files with 59 additions and 61 deletions

View File

@ -68,16 +68,12 @@ class CraftingManager{
case 1: case 1:
// TODO: handle multiple result items // TODO: handle multiple result items
$first = $recipe["output"][0]; $first = $recipe["output"][0];
$result = new ShapedRecipe(Item::jsonDeserialize($first), $recipe["height"], $recipe["width"]);
$shape = array_map(function(string $keys) : array{ return str_split($keys); }, $recipe["shape"]); $this->registerRecipe(new ShapedRecipe(
$ingredients = array_map(function(array $data) : Item{ return Item::jsonDeserialize($data); }, $recipe["input"]); Item::jsonDeserialize($first),
foreach($shape as $y => $row){ $recipe["shape"],
foreach($row as $x => $ingredient){ array_map(function(array $data) : Item{ return Item::jsonDeserialize($data); }, $recipe["input"])
$result->addIngredient($x, $y, $ingredients[$ingredient] ?? Item::get(Item::AIR, 0, 0)); ));
}
}
$this->registerRecipe($result);
break; break;
case 2: case 2:
case 3: case 3:

View File

@ -38,36 +38,62 @@ class ShapedRecipe implements Recipe{
/** @var string[] */ /** @var string[] */
private $shape = []; private $shape = [];
/** @var Item[] char => Item map */
/** @var Item[][] */ private $ingredientList = [];
private $ingredients = [];
/** @var Vector2[][] */
private $shapeItems = [];
/** /**
* @param Item $result * Constructs a ShapedRecipe instance.
* @param int $height
* @param int $width
* *
* @throws \Exception * @param Item $result
* @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>
* 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.
*
* Note: Recipes **do not** need to be square. Do NOT add padding for empty rows/columns.
*/ */
public function __construct(Item $result, int $height, int $width){ public function __construct(Item $result, array $shape, array $ingredients){
for($h = 0; $h < $height; $h++){ $rowCount = count($shape);
if($width === 0 or $width > 3){ if($rowCount > 3 or $rowCount <= 0){
throw new \InvalidStateException("Crafting rows should be 1, 2, 3 wide, not $width"); throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 rows, not $rowCount");
}
$this->ingredients[] = array_fill(0, $width, null);
} }
$shape = array_values($shape);
$columnCount = strlen($shape[0]);
if($columnCount > 3 or $rowCount <= 0){
throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 columns, not $columnCount");
}
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) . ")");
}
for($x = 0; $x < $columnCount; ++$x){
if($row{$x} !== ' ' and !isset($ingredients[$row{$x}])){
throw new \InvalidArgumentException("No item specified for symbol '" . $row{$x} . "'");
}
}
}
$this->output = clone $result; $this->output = clone $result;
$this->shape = $shape;
foreach($ingredients as $char => $i){
$this->setIngredient($char, $i);
}
} }
public function getWidth() : int{ public function getWidth() : int{
return count($this->ingredients[0]); return strlen($this->shape[0]);
} }
public function getHeight() : int{ public function getHeight() : int{
return count($this->ingredients); return count($this->shape);
} }
/** /**
@ -92,58 +118,32 @@ class ShapedRecipe implements Recipe{
$this->id = $id; $this->id = $id;
} }
/**
* @param int $x
* @param int $y
* @param Item $item
*
* @return $this
*/
public function addIngredient(int $x, int $y, Item $item){
$this->ingredients[$y][$x] = clone $item;
return $this;
}
/** /**
* @param string $key * @param string $key
* @param Item $item * @param Item $item
* *
* @return $this * @return $this
* @throws \Exception * @throws \InvalidArgumentException
*/ */
public function setIngredient(string $key, Item $item){ public function setIngredient(string $key, Item $item){
if(!array_key_exists($key, $this->shape)){ if(strpos(implode($this->shape), $key) === false){
throw new \Exception("Symbol does not appear in the shape: " . $key); throw new \InvalidArgumentException("Symbol '$key' does not appear in the recipe shape");
} }
$this->fixRecipe($key, $item); $this->ingredientList[$key] = clone $item;
return $this; return $this;
} }
/**
* @param string $key
* @param Item $item
*/
protected function fixRecipe(string $key, Item $item){
foreach($this->shapeItems[$key] as $entry){
$this->ingredients[$entry->y][$entry->x] = clone $item;
}
}
/** /**
* @return Item[][] * @return Item[][]
*/ */
public function getIngredientMap() : array{ public function getIngredientMap() : array{
$ingredients = []; $ingredients = [];
foreach($this->ingredients as $y => $row){
$ingredients[$y] = []; for($y = 0, $y2 = $this->getHeight(); $y < $y2; ++$y){
foreach($row as $x => $ingredient){ for($x = 0, $x2 = $this->getWidth(); $x < $x2; ++$x){
if($ingredient !== null){ $ingredients[$y][$x] = $this->getIngredient($x, $y);
$ingredients[$y][$x] = clone $ingredient;
}else{
$ingredients[$y][$x] = ItemFactory::get(Item::AIR);
}
} }
} }
@ -157,10 +157,12 @@ class ShapedRecipe implements Recipe{
* @return Item * @return Item
*/ */
public function getIngredient(int $x, int $y) : Item{ public function getIngredient(int $x, int $y) : Item{
return $this->ingredients[$y][$x] ?? ItemFactory::get(Item::AIR); $exists = $this->ingredientList[$this->shape[$y]{$x}] ?? null;
return $exists !== null ? clone $exists : ItemFactory::get(Item::AIR);
} }
/** /**
* Returns an array of strings containing characters representing the recipe's shape.
* @return string[] * @return string[]
*/ */
public function getShape() : array{ public function getShape() : array{