36 use DestructorCallbackTrait;
42 protected array $shapedRecipes = [];
47 protected array $shapelessRecipes = [];
53 private array $craftingRecipeIndex = [];
59 protected array $furnaceRecipeManagers = [];
65 protected array $potionTypeRecipes = [];
71 protected array $potionContainerChangeRecipes = [];
77 private array $brewingRecipeCache = [];
80 private ObjectSet $recipeRegisteredCallbacks;
82 public function __construct(){
83 $this->recipeRegisteredCallbacks =
new ObjectSet();
84 foreach(FurnaceType::cases() as $furnaceType){
88 $recipeRegisteredCallbacks = $this->recipeRegisteredCallbacks;
89 foreach($this->furnaceRecipeManagers as $furnaceRecipeManager){
90 $furnaceRecipeManager->getRecipeRegisteredCallbacks()->add(
static function(
FurnaceRecipe $recipe) use ($recipeRegisteredCallbacks) :
void{
91 foreach($recipeRegisteredCallbacks as $callback){
106 ($retval = $i1->getStateId() <=> $i2->getStateId()) === 0 && ($retval = $i1->getCount() <=> $i2->getCount()) === 0;
116 private static function pack(array $items) : array{
120 foreach($items as $i => $item){
121 foreach($result as $otherItem){
122 if($item->canStackWith($otherItem)){
123 $otherItem->setCount($otherItem->getCount() + $item->getCount());
129 $result[] = clone $item;
138 private static function hashOutputs(array $outputs) : string{
139 $outputs = self::pack($outputs);
140 usort($outputs, [self::class,
"sort"]);
141 $result =
new BinaryStream();
142 foreach($outputs as $o){
145 $result->putVarInt($o->getStateId());
146 $result->put((
new LittleEndianNbtSerializer())->write(
new TreeRoot($o->getNamedTag())));
149 return $result->getBuffer();
157 return $this->shapelessRecipes;
165 return $this->shapedRecipes;
173 return $this->craftingRecipeIndex;
176 public function getCraftingRecipeFromIndex(
int $index) : ?
CraftingRecipe{
177 return $this->craftingRecipeIndex[$index] ?? null;
180 public function getFurnaceRecipeManager(FurnaceType $furnaceType) : FurnaceRecipeManager{
181 return $this->furnaceRecipeManagers[spl_object_id($furnaceType)];
189 return $this->potionTypeRecipes;
197 return $this->potionContainerChangeRecipes;
200 public function registerShapedRecipe(
ShapedRecipe $recipe) : void{
201 $this->shapedRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
202 $this->craftingRecipeIndex[] = $recipe;
204 foreach($this->recipeRegisteredCallbacks as $callback){
209 public function registerShapelessRecipe(ShapelessRecipe $recipe) : void{
210 $this->shapelessRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
211 $this->craftingRecipeIndex[] = $recipe;
213 foreach($this->recipeRegisteredCallbacks as $callback){
218 public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{
219 $this->potionTypeRecipes[] = $recipe;
221 foreach($this->recipeRegisteredCallbacks as $callback){
226 public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{
227 $this->potionContainerChangeRecipes[] = $recipe;
229 foreach($this->recipeRegisteredCallbacks as $callback){
240 $outputHash = self::hashOutputs($outputs);
242 if(isset($this->shapedRecipes[$outputHash])){
243 foreach($this->shapedRecipes[$outputHash] as $recipe){
244 if($recipe->matchesCraftingGrid($grid)){
250 if(isset($this->shapelessRecipes[$outputHash])){
251 foreach($this->shapelessRecipes[$outputHash] as $recipe){
252 if($recipe->matchesCraftingGrid($grid)){
270 $outputHash = self::hashOutputs($outputs);
272 if(isset($this->shapedRecipes[$outputHash])){
273 foreach($this->shapedRecipes[$outputHash] as $recipe){
278 if(isset($this->shapelessRecipes[$outputHash])){
279 foreach($this->shapelessRecipes[$outputHash] as $recipe){
285 public function matchBrewingRecipe(Item $input, Item $ingredient) : ?BrewingRecipe{
286 $inputHash = $input->getStateId();
287 $ingredientHash = $ingredient->getStateId();
288 $cached = $this->brewingRecipeCache[$inputHash][$ingredientHash] ??
null;
289 if($cached !==
null){
293 foreach($this->potionContainerChangeRecipes as $recipe){
294 if($recipe->getIngredient()->accepts($ingredient) && $recipe->getResultFor($input) !==
null){
295 return $this->brewingRecipeCache[$inputHash][$ingredientHash] = $recipe;
299 foreach($this->potionTypeRecipes as $recipe){
300 if($recipe->getIngredient()->accepts($ingredient) && $recipe->getResultFor($input) !==
null){
301 return $this->brewingRecipeCache[$inputHash][$ingredientHash] = $recipe;