mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-13 06:55:29 +00:00
continue refactoring, not finished, not tested
This is a bump from my workspace
This commit is contained in:
parent
a1695a52d5
commit
b4cb09fe5e
@ -39,20 +39,23 @@ final class AnvilHelper{
|
|||||||
public static function calculateResult(Player $player, Item $base, Item $material, ?string $customName = null) : ?AnvilCraftResult {
|
public static function calculateResult(Player $player, Item $base, Item $material, ?string $customName = null) : ?AnvilCraftResult {
|
||||||
|
|
||||||
$recipe = Server::getInstance()->getCraftingManager()->matchAnvilRecipe($base, $material);
|
$recipe = Server::getInstance()->getCraftingManager()->matchAnvilRecipe($base, $material);
|
||||||
|
if($recipe === null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
$result = $recipe->getResultFor($base, $material);
|
$result = $recipe->getResultFor($base, $material);
|
||||||
|
|
||||||
if($result !== null){
|
if($result !== null){
|
||||||
$resultItem = $result->getResult();
|
$resultItem = $result->getOutput();
|
||||||
$xpCost = $result->getXpCost();
|
$xpCost = $result->getXpCost();
|
||||||
if(($customName === null || $customName === "") && $resultItem->hasCustomName()){
|
if(($customName === null || $customName === "") && $resultItem->hasCustomName()){
|
||||||
$xpCost++;
|
$xpCost++;
|
||||||
$resultItem->clearCustomName();
|
$resultItem->clearCustomName();
|
||||||
}elseif($resultItem->getCustomName() !== $customName){
|
}elseif($customName !== null && $resultItem->getCustomName() !== $customName){
|
||||||
$xpCost++;
|
$xpCost++;
|
||||||
$resultItem->setCustomName($customName);
|
$resultItem->setCustomName($customName);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = new AnvilCraftResult($xpCost, $resultItem);
|
$result = new AnvilCraftResult($xpCost, $resultItem, $result->getSacrificeResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
if($result === null || $result->getXpCost() <= 0 || ($result->getXpCost() > self::COST_LIMIT && !$player->isCreative())){
|
if($result === null || $result->getXpCost() <= 0 || ($result->getXpCost() > self::COST_LIMIT && !$player->isCreative())){
|
||||||
|
@ -25,17 +25,44 @@ namespace pocketmine\crafting;
|
|||||||
|
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is here to hold the result of an anvil crafting process.
|
||||||
|
*/
|
||||||
class AnvilCraftResult{
|
class AnvilCraftResult{
|
||||||
|
/**
|
||||||
|
* @param int $xpCost
|
||||||
|
* @param Item $output
|
||||||
|
* @param Item|null $sacrificeResult If the given item is considered as null (count <= 0), the value will be set to null.
|
||||||
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private int $xpCost,
|
private int $xpCost,
|
||||||
private Item $result,
|
private Item $output,
|
||||||
){}
|
private ?Item $sacrificeResult
|
||||||
|
){
|
||||||
|
if($this->sacrificeResult !== null && $this->sacrificeResult->isNull()){
|
||||||
|
$this->sacrificeResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent the amount of experience points required to craft the output item.
|
||||||
|
*/
|
||||||
public function getXpCost() : int{
|
public function getXpCost() : int{
|
||||||
return $this->xpCost;
|
return $this->xpCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getResult() : Item{
|
/**
|
||||||
return $this->result;
|
* Represent the item given as output of the crafting process.
|
||||||
|
*/
|
||||||
|
public function getOutput() : Item{
|
||||||
|
return $this->output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This result has to be null if the sacrifice slot need to be emptied.
|
||||||
|
* If not null, it represent the item that will be left in the sacrifice slot after the crafting process.
|
||||||
|
*/
|
||||||
|
public function getSacrificeResult() : ?Item{
|
||||||
|
return $this->sacrificeResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,5 @@ namespace pocketmine\crafting;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
|
||||||
interface AnvilRecipe{
|
interface AnvilRecipe{
|
||||||
public function getXpCost() : int;
|
|
||||||
|
|
||||||
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult;
|
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ use function count;
|
|||||||
use function implode;
|
use function implode;
|
||||||
use function ksort;
|
use function ksort;
|
||||||
use function spl_object_id;
|
use function spl_object_id;
|
||||||
|
use function var_dump;
|
||||||
use const SORT_STRING;
|
use const SORT_STRING;
|
||||||
|
|
||||||
class CraftingManager{
|
class CraftingManager{
|
||||||
|
@ -31,8 +31,10 @@ use pocketmine\crafting\json\RecipeIngredientData;
|
|||||||
use pocketmine\crafting\json\ShapedRecipeData;
|
use pocketmine\crafting\json\ShapedRecipeData;
|
||||||
use pocketmine\crafting\json\ShapelessRecipeData;
|
use pocketmine\crafting\json\ShapelessRecipeData;
|
||||||
use pocketmine\data\bedrock\block\BlockStateData;
|
use pocketmine\data\bedrock\block\BlockStateData;
|
||||||
|
use pocketmine\data\bedrock\block\BlockTypeNames;
|
||||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||||
use pocketmine\data\bedrock\item\ItemTypeDeserializeException;
|
use pocketmine\data\bedrock\item\ItemTypeDeserializeException;
|
||||||
|
use pocketmine\data\bedrock\item\ItemTypeNames;
|
||||||
use pocketmine\data\bedrock\item\SavedItemData;
|
use pocketmine\data\bedrock\item\SavedItemData;
|
||||||
use pocketmine\data\bedrock\item\SavedItemStackData;
|
use pocketmine\data\bedrock\item\SavedItemStackData;
|
||||||
use pocketmine\data\SavedDataLoadingException;
|
use pocketmine\data\SavedDataLoadingException;
|
||||||
@ -335,15 +337,13 @@ final class CraftingManagerFromDataHelper{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$result->registerAnvilRecipe(new MaterialRepairRecipe(
|
$result->registerAnvilRecipe(new MaterialRepairRecipe(
|
||||||
new ExactRecipeIngredient(VanillaItems::DIAMOND_PICKAXE()),
|
new MetaWildcardRecipeIngredient(ItemTypeNames::DIAMOND_PICKAXE),
|
||||||
new ExactRecipeIngredient(VanillaItems::DIAMOND()),
|
new ExactRecipeIngredient(VanillaItems::DIAMOND())
|
||||||
VanillaItems::DIAMOND_PICKAXE()
|
|
||||||
));
|
));
|
||||||
|
|
||||||
$result->registerAnvilRecipe(new ItemCombineRecipe(
|
$result->registerAnvilRecipe(new ItemCombineRecipe(
|
||||||
new ExactRecipeIngredient(VanillaItems::DIAMOND_PICKAXE()),
|
new MetaWildcardRecipeIngredient(ItemTypeNames::DIAMOND_PICKAXE),
|
||||||
new ExactRecipeIngredient(VanillaItems::DIAMOND_PICKAXE()),
|
new MetaWildcardRecipeIngredient(ItemTypeNames::DIAMOND_PICKAXE)
|
||||||
VanillaItems::DIAMOND_PICKAXE()
|
|
||||||
));
|
));
|
||||||
|
|
||||||
//TODO: smithing
|
//TODO: smithing
|
||||||
|
@ -40,8 +40,7 @@ use function min;
|
|||||||
class ItemCombineRecipe implements AnvilRecipe{
|
class ItemCombineRecipe implements AnvilRecipe{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private RecipeIngredient $input,
|
private RecipeIngredient $input,
|
||||||
private RecipeIngredient $material,
|
private RecipeIngredient $material
|
||||||
private Item $result
|
|
||||||
){ }
|
){ }
|
||||||
|
|
||||||
public function getInput() : RecipeIngredient{
|
public function getInput() : RecipeIngredient{
|
||||||
@ -52,22 +51,14 @@ class ItemCombineRecipe implements AnvilRecipe{
|
|||||||
return $this->material;
|
return $this->material;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getResult() : Item{
|
|
||||||
return clone $this->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getXpCost() : int{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult{
|
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult{
|
||||||
if($input->equals($this->input->getItem()) && $material->equals($this->material->getItem())){
|
if($this->input->accepts($input) && $this->material->accepts($material)){
|
||||||
$result = $this->getResult();
|
$result = (clone $input);
|
||||||
$xpCost = 0;
|
$xpCost = 0;
|
||||||
if($input instanceof Durable && $material instanceof Durable){
|
if($result instanceof Durable && $material instanceof Durable){
|
||||||
$damage = $input->getDamage();
|
$damage = $result->getDamage();
|
||||||
if($damage !== 0){
|
if($damage !== 0){
|
||||||
$baseMaxDurability = $input->getMaxDurability();
|
$baseMaxDurability = $result->getMaxDurability();
|
||||||
$baseDurability = $baseMaxDurability - $damage;
|
$baseDurability = $baseMaxDurability - $damage;
|
||||||
$materialDurability = $material->getMaxDurability() - $material->getDamage();
|
$materialDurability = $material->getMaxDurability() - $material->getDamage();
|
||||||
$addDurability = (int) ($baseMaxDurability * 12 / 100);
|
$addDurability = (int) ($baseMaxDurability * 12 / 100);
|
||||||
@ -78,11 +69,6 @@ class ItemCombineRecipe implements AnvilRecipe{
|
|||||||
$xpCost = 2;
|
$xpCost = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting base enchantments to result
|
|
||||||
foreach($input->getEnchantments() as $enchantment){
|
|
||||||
$result->addEnchantment($enchantment);
|
|
||||||
}
|
|
||||||
|
|
||||||
// combining enchantments
|
// combining enchantments
|
||||||
foreach($material->getEnchantments() as $instance){
|
foreach($material->getEnchantments() as $instance){
|
||||||
$enchantment = $instance->getType();
|
$enchantment = $instance->getType();
|
||||||
@ -131,7 +117,7 @@ class ItemCombineRecipe implements AnvilRecipe{
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AnvilCraftResult($xpCost, $result);
|
return new AnvilCraftResult($xpCost, $result, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -23,11 +23,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\crafting;
|
namespace pocketmine\crafting;
|
||||||
|
|
||||||
|
use pocketmine\item\Durable;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\Tool;
|
||||||
use function ceil;
|
use function ceil;
|
||||||
use function floor;
|
use function floor;
|
||||||
use function max;
|
use function max;
|
||||||
use function min;
|
use function min;
|
||||||
|
use function var_dump;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represent a recipe that repair an item with a material in an anvil.
|
* Represent a recipe that repair an item with a material in an anvil.
|
||||||
@ -35,8 +38,7 @@ use function min;
|
|||||||
class MaterialRepairRecipe implements AnvilRecipe{
|
class MaterialRepairRecipe implements AnvilRecipe{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private RecipeIngredient $input,
|
private RecipeIngredient $input,
|
||||||
private RecipeIngredient $material,
|
private RecipeIngredient $material
|
||||||
private Item $result
|
|
||||||
){ }
|
){ }
|
||||||
|
|
||||||
public function getInput() : RecipeIngredient{
|
public function getInput() : RecipeIngredient{
|
||||||
@ -47,16 +49,8 @@ class MaterialRepairRecipe implements AnvilRecipe{
|
|||||||
return $this->material;
|
return $this->material;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getResult() : Item{
|
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult{
|
||||||
return clone $this->result;
|
if($this->input->accepts($input) && $this->material->accepts($material) && $input instanceof Durable){
|
||||||
}
|
|
||||||
|
|
||||||
public function getXpCost() : int{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getResultFor(Item $input, Item $material) : ?Item{
|
|
||||||
if($this->input->accepts($input) && $this->material->accepts($material)){
|
|
||||||
$damage = $input->getDamage();
|
$damage = $input->getDamage();
|
||||||
if($damage !== 0){
|
if($damage !== 0){
|
||||||
$quarter = min($damage, (int) floor($input->getMaxDurability() / 4));
|
$quarter = min($damage, (int) floor($input->getMaxDurability() / 4));
|
||||||
@ -65,7 +59,11 @@ class MaterialRepairRecipe implements AnvilRecipe{
|
|||||||
// TODO: remove the material
|
// TODO: remove the material
|
||||||
$damage -= $quarter * $numberRepair;
|
$damage -= $quarter * $numberRepair;
|
||||||
}
|
}
|
||||||
return $this->getResult()->setDamage(max(0, $damage));
|
return new AnvilCraftResult(
|
||||||
|
$numberRepair,
|
||||||
|
(clone $input)->setDamage(max(0, $damage)),
|
||||||
|
$material->pop($numberRepair)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class AnvilTransaction extends InventoryTransaction{
|
|||||||
if($calculAttempt === null){
|
if($calculAttempt === null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$result = $calculAttempt->getResult();
|
$result = $calculAttempt->getOutput();
|
||||||
if(!$result->equalsExact($expectedOutput)){
|
if(!$result->equalsExact($expectedOutput)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ class AnvilTransaction extends InventoryTransaction{
|
|||||||
parent::execute();
|
parent::execute();
|
||||||
|
|
||||||
if($this->source->hasFiniteResources()){
|
if($this->source->hasFiniteResources()){
|
||||||
$this->source->getXpManager()->subtractXpLevels($this->expectedResult->getRepairCost());
|
$this->source->getXpManager()->subtractXpLevels($this->expectedResult->getXpCost());
|
||||||
}
|
}
|
||||||
|
|
||||||
$inventory = $this->source->getCurrentWindow();
|
$inventory = $this->source->getCurrentWindow();
|
||||||
@ -148,9 +148,7 @@ class AnvilTransaction extends InventoryTransaction{
|
|||||||
throw new AssumptionFailedError("Expected that baseItem are not null before executing the event");
|
throw new AssumptionFailedError("Expected that baseItem are not null before executing the event");
|
||||||
}
|
}
|
||||||
|
|
||||||
$ev = new PlayerUseAnvilEvent($this->source, $this->baseItem, $this->materialItem, $this->expectedResult->getResult() ?? throw new \AssertionError(
|
$ev = new PlayerUseAnvilEvent($this->source, $this->baseItem, $this->materialItem, $this->expectedResult->getOutput(), $this->customName, $this->expectedResult->getXpCost());
|
||||||
"Expected that the expected result is not null"
|
|
||||||
), $this->customName, $this->expectedResult->getXpCost());
|
|
||||||
$ev->call();
|
$ev->call();
|
||||||
return !$ev->isCancelled();
|
return !$ev->isCancelled();
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ use pocketmine\utils\LegacyEnumShimTrait;
|
|||||||
* @method static ToolTier STONE()
|
* @method static ToolTier STONE()
|
||||||
* @method static ToolTier WOOD()
|
* @method static ToolTier WOOD()
|
||||||
*
|
*
|
||||||
* @phpstan-type TMetadata array{0: int, 1: int, 2: int, 3: int, 4: int, 5: int[]}
|
* @phpstan-type TMetadata array{0: int, 1: int, 2: int, 3: int, 4: int}
|
||||||
*/
|
*/
|
||||||
enum ToolTier{
|
enum ToolTier{
|
||||||
use LegacyEnumShimTrait;
|
use LegacyEnumShimTrait;
|
||||||
|
@ -358,7 +358,7 @@ class ItemStackRequestExecutor{
|
|||||||
$result = AnvilHelper::calculateResult($this->player, $window->getInput(), $window->getMaterial(), $this->request->getFilterStrings()[0] ?? null);
|
$result = AnvilHelper::calculateResult($this->player, $window->getInput(), $window->getMaterial(), $this->request->getFilterStrings()[0] ?? null);
|
||||||
if($result !== null){
|
if($result !== null){
|
||||||
$this->specialTransaction = new AnvilTransaction($this->player, $result, $this->request->getFilterStrings()[0] ?? null);
|
$this->specialTransaction = new AnvilTransaction($this->player, $result, $this->request->getFilterStrings()[0] ?? null);
|
||||||
$this->setNextCreatedItem($result->getResult());
|
$this->setNextCreatedItem($result->getOutput());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}elseif($action instanceof CraftingConsumeInputStackRequestAction){
|
}elseif($action instanceof CraftingConsumeInputStackRequestAction){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user