diff --git a/src/crafting/CraftingManager.php b/src/crafting/CraftingManager.php index c7c0b10c645..4942a127bd2 100644 --- a/src/crafting/CraftingManager.php +++ b/src/crafting/CraftingManager.php @@ -29,6 +29,8 @@ use pocketmine\utils\BinaryStream; use pocketmine\utils\DestructorCallbackTrait; use pocketmine\utils\ObjectSet; +use function array_search; +use function count; use function spl_object_id; use function usort; @@ -79,25 +81,39 @@ class CraftingManager{ /** @phpstan-var ObjectSet<\Closure() : void> */ private ObjectSet $recipeRegisteredCallbacks; + /** @phpstan-var ObjectSet<\Closure() : void> */ + private ObjectSet $recipeUnregisteredCallbacks; + public function __construct(){ $this->recipeRegisteredCallbacks = new ObjectSet(); + $this->recipeUnregisteredCallbacks = new ObjectSet(); + foreach(FurnaceType::cases() as $furnaceType){ $this->furnaceRecipeManagers[spl_object_id($furnaceType)] = new FurnaceRecipeManager(); } $recipeRegisteredCallbacks = $this->recipeRegisteredCallbacks; + $recipeUnregisteredCallbacks = $this->recipeUnregisteredCallbacks; foreach($this->furnaceRecipeManagers as $furnaceRecipeManager){ $furnaceRecipeManager->getRecipeRegisteredCallbacks()->add(static function(FurnaceRecipe $recipe) use ($recipeRegisteredCallbacks) : void{ foreach($recipeRegisteredCallbacks as $callback){ $callback(); } }); + $furnaceRecipeManager->getRecipeUnregisteredCallbacks()->add(static function(FurnaceRecipe $recipe) use ($recipeUnregisteredCallbacks) : void{ + foreach($recipeUnregisteredCallbacks as $callback){ + $callback(); + } + }); } } /** @phpstan-return ObjectSet<\Closure() : void> */ public function getRecipeRegisteredCallbacks() : ObjectSet{ return $this->recipeRegisteredCallbacks; } + /** @phpstan-return ObjectSet<\Closure() : void> */ + public function getRecipeUnregisteredCallbacks() : ObjectSet{ return $this->recipeUnregisteredCallbacks; } + /** * Function used to arrange Shapeless Recipe ingredient lists into a consistent order. */ @@ -206,6 +222,34 @@ public function registerShapedRecipe(ShapedRecipe $recipe) : void{ } } + public function unregisterShapedRecipe(ShapedRecipe $recipe) : void{ + $edited = false; + $hash = self::hashOutputs($recipe->getResults()); + + foreach($this->shapedRecipes[$hash] ?? [] as $i => $r){ + if($r === $recipe){ + unset($this->shapedRecipes[$hash][$i]); + if(count($this->shapedRecipes[$hash]) === 0){ + unset($this->shapedRecipes[$hash]); + $edited = true; + } + break; + } + } + + $index = array_search($recipe, $this->craftingRecipeIndex, true); + if($index !== false){ + unset($this->craftingRecipeIndex[$index]); + $edited = true; + } + + if($edited){ + foreach($this->recipeUnregisteredCallbacks as $callback){ + $callback(); + } + } + } + public function registerShapelessRecipe(ShapelessRecipe $recipe) : void{ $this->shapelessRecipes[self::hashOutputs($recipe->getResults())][] = $recipe; $this->craftingRecipeIndex[] = $recipe; @@ -215,6 +259,34 @@ public function registerShapelessRecipe(ShapelessRecipe $recipe) : void{ } } + public function unregisterShapelessRecipe(ShapelessRecipe $recipe) : void{ + $edited = false; + $hash = self::hashOutputs($recipe->getResults()); + + foreach($this->shapelessRecipes[$hash] ?? [] as $i => $r){ + if($r === $recipe){ + unset($this->shapelessRecipes[$hash][$i]); + if(count($this->shapelessRecipes[$hash]) === 0){ + unset($this->shapelessRecipes[$hash]); + $edited = true; + } + break; + } + } + + $index = array_search($recipe, $this->craftingRecipeIndex, true); + if($index !== false){ + unset($this->craftingRecipeIndex[$index]); + $edited = true; + } + + if($edited){ + foreach($this->recipeUnregisteredCallbacks as $callback){ + $callback(); + } + } + } + public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{ $this->potionTypeRecipes[] = $recipe; @@ -223,6 +295,17 @@ public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{ } } + public function unregisterPotionTypeRecipe(PotionTypeRecipe $recipe) : void{ + $recipeIndex = array_search($recipe, $this->potionTypeRecipes, true); + if($recipeIndex !== false){ + unset($this->potionTypeRecipes[$recipeIndex]); + + foreach($this->recipeUnregisteredCallbacks as $callback){ + $callback(); + } + } + } + public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{ $this->potionContainerChangeRecipes[] = $recipe; @@ -231,6 +314,17 @@ public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe } } + public function unregisterPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{ + $recipeIndex = array_search($recipe, $this->potionContainerChangeRecipes, true); + if($recipeIndex !== false){ + unset($this->potionContainerChangeRecipes[$recipeIndex]); + + foreach($this->recipeUnregisteredCallbacks as $callback){ + $callback(); + } + } + } + /** * @param Item[] $outputs */ diff --git a/src/crafting/FurnaceRecipeManager.php b/src/crafting/FurnaceRecipeManager.php index d13465b44a7..72fbf252632 100644 --- a/src/crafting/FurnaceRecipeManager.php +++ b/src/crafting/FurnaceRecipeManager.php @@ -25,6 +25,7 @@ use pocketmine\item\Item; use pocketmine\utils\ObjectSet; +use function array_search; final class FurnaceRecipeManager{ /** @var FurnaceRecipe[] */ @@ -39,8 +40,12 @@ final class FurnaceRecipeManager{ /** @phpstan-var ObjectSet<\Closure(FurnaceRecipe) : void> */ private ObjectSet $recipeRegisteredCallbacks; + /** @phpstan-var ObjectSet<\Closure(FurnaceRecipe) : void> */ + private ObjectSet $recipeUnregisteredCallbacks; + public function __construct(){ $this->recipeRegisteredCallbacks = new ObjectSet(); + $this->recipeUnregisteredCallbacks = new ObjectSet(); } /** @@ -50,6 +55,13 @@ public function getRecipeRegisteredCallbacks() : ObjectSet{ return $this->recipeRegisteredCallbacks; } + /** + * @phpstan-return ObjectSet<\Closure(FurnaceRecipe) : void> + */ + public function getRecipeUnregisteredCallbacks() : ObjectSet{ + return $this->recipeUnregisteredCallbacks; + } + /** * @return FurnaceRecipe[] */ @@ -64,6 +76,17 @@ public function register(FurnaceRecipe $recipe) : void{ } } + public function unregister(FurnaceRecipe $recipe) : void{ + $index = array_search($recipe, $this->furnaceRecipes, true); + if($index !== false){ + unset($this->furnaceRecipes[$index]); + + foreach($this->recipeUnregisteredCallbacks as $callback){ + $callback($recipe); + } + } + } + public function match(Item $input) : ?FurnaceRecipe{ $index = $input->getStateId(); $simpleRecipe = $this->lookupCache[$index] ?? null; diff --git a/src/network/mcpe/cache/CraftingDataCache.php b/src/network/mcpe/cache/CraftingDataCache.php index 14523f74c7f..565a6c18e0c 100644 --- a/src/network/mcpe/cache/CraftingDataCache.php +++ b/src/network/mcpe/cache/CraftingDataCache.php @@ -65,6 +65,9 @@ public function getCache(CraftingManager $manager) : CraftingDataPacket{ $manager->getRecipeRegisteredCallbacks()->add(function() use ($id) : void{ unset($this->caches[$id]); }); + $manager->getRecipeUnregisteredCallbacks()->add(function() use ($id) : void{ + unset($this->caches[$id]); + }); $this->caches[$id] = $this->buildCraftingDataCache($manager); } return $this->caches[$id];