PocketMine-MP 5.32.2 git-1ebd7d3960d713d56f77f610fe0c15cdee201069
Loading...
Searching...
No Matches
CraftingDataCache.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\network\mcpe\cache;
25
27use pocketmine\crafting\FurnaceType;
30use pocketmine\crafting\ShapelessRecipeType;
45use pocketmine\utils\SingletonTrait;
46use Ramsey\Uuid\Uuid;
47use function array_map;
48use function spl_object_id;
49
51 use SingletonTrait;
52
57 private array $caches = [];
58
63 public const RECIPE_ID_OFFSET = 1;
64
65 public function getCache(CraftingManager $manager) : CraftingDataPacket{
66 $id = spl_object_id($manager);
67 if(!isset($this->caches[$id])){
68 $manager->getDestructorCallbacks()->add(function() use ($id) : void{
69 unset($this->caches[$id]);
70 });
71 $manager->getRecipeRegisteredCallbacks()->add(function() use ($id) : void{
72 unset($this->caches[$id]);
73 });
74 $this->caches[$id] = $this->buildCraftingDataCache($manager);
75 }
76 return $this->caches[$id];
77 }
78
82 private function buildCraftingDataCache(CraftingManager $manager) : CraftingDataPacket{
83 Timings::$craftingDataCacheRebuild->startTiming();
84
85 $nullUUID = Uuid::fromString(Uuid::NIL);
86 $converter = TypeConverter::getInstance();
87 $recipesWithTypeIds = [];
88
89 $noUnlockingRequirement = new RecipeUnlockingRequirement(null);
90 foreach($manager->getCraftingRecipeIndex() as $index => $recipe){
91 //the client doesn't like recipes with an ID of 0, so we need to offset them
92 $recipeNetId = $index + self::RECIPE_ID_OFFSET;
93 if($recipe instanceof ShapelessRecipe){
94 $typeTag = match($recipe->getType()){
95 ShapelessRecipeType::CRAFTING => CraftingRecipeBlockName::CRAFTING_TABLE,
96 ShapelessRecipeType::STONECUTTER => CraftingRecipeBlockName::STONECUTTER,
97 ShapelessRecipeType::CARTOGRAPHY => CraftingRecipeBlockName::CARTOGRAPHY_TABLE,
98 ShapelessRecipeType::SMITHING => CraftingRecipeBlockName::SMITHING_TABLE,
99 };
100 $recipesWithTypeIds[] = new ProtocolShapelessRecipe(
101 CraftingDataPacket::ENTRY_SHAPELESS,
102 Binary::writeInt($recipeNetId),
103 array_map($converter->coreRecipeIngredientToNet(...), $recipe->getIngredientList()),
104 array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
105 $nullUUID,
106 $typeTag,
107 50,
108 $noUnlockingRequirement,
109 $recipeNetId
110 );
111 }elseif($recipe instanceof ShapedRecipe){
112 $inputs = [];
113
114 for($row = 0, $height = $recipe->getHeight(); $row < $height; ++$row){
115 for($column = 0, $width = $recipe->getWidth(); $column < $width; ++$column){
116 $inputs[$row][$column] = $converter->coreRecipeIngredientToNet($recipe->getIngredient($column, $row));
117 }
118 }
119 $recipesWithTypeIds[] = $r = new ProtocolShapedRecipe(
120 CraftingDataPacket::ENTRY_SHAPED,
121 Binary::writeInt($recipeNetId),
122 $inputs,
123 array_map($converter->coreItemStackToNet(...), $recipe->getResults()),
124 $nullUUID,
125 CraftingRecipeBlockName::CRAFTING_TABLE,
126 50,
127 true,
128 $noUnlockingRequirement,
129 $recipeNetId,
130 );
131 }else{
132 //TODO: probably special recipe types
133 }
134 }
135
136 foreach(FurnaceType::cases() as $furnaceType){
137 $typeTag = match($furnaceType){
138 FurnaceType::FURNACE => FurnaceRecipeBlockName::FURNACE,
139 FurnaceType::BLAST_FURNACE => FurnaceRecipeBlockName::BLAST_FURNACE,
140 FurnaceType::SMOKER => FurnaceRecipeBlockName::SMOKER,
141 FurnaceType::CAMPFIRE => FurnaceRecipeBlockName::CAMPFIRE,
142 FurnaceType::SOUL_CAMPFIRE => FurnaceRecipeBlockName::SOUL_CAMPFIRE
143 };
144 foreach($manager->getFurnaceRecipeManager($furnaceType)->getAll() as $recipe){
145 $input = $converter->coreRecipeIngredientToNet($recipe->getInput())->getDescriptor();
146 if(!$input instanceof IntIdMetaItemDescriptor){
147 throw new AssumptionFailedError();
148 }
149 $recipesWithTypeIds[] = new ProtocolFurnaceRecipe(
150 CraftingDataPacket::ENTRY_FURNACE_DATA,
151 $input->getId(),
152 $input->getMeta(),
153 $converter->coreItemStackToNet($recipe->getResult()),
154 $typeTag
155 );
156 }
157 }
158
159 $potionTypeRecipes = [];
160 foreach($manager->getPotionTypeRecipes() as $recipe){
161 $input = $converter->coreRecipeIngredientToNet($recipe->getInput())->getDescriptor();
162 $ingredient = $converter->coreRecipeIngredientToNet($recipe->getIngredient())->getDescriptor();
163 if(!$input instanceof IntIdMetaItemDescriptor || !$ingredient instanceof IntIdMetaItemDescriptor){
164 throw new AssumptionFailedError();
165 }
166 $output = $converter->coreItemStackToNet($recipe->getOutput());
167 $potionTypeRecipes[] = new ProtocolPotionTypeRecipe(
168 $input->getId(),
169 $input->getMeta(),
170 $ingredient->getId(),
171 $ingredient->getMeta(),
172 $output->getId(),
173 $output->getMeta()
174 );
175 }
176
177 $potionContainerChangeRecipes = [];
178 $itemTypeDictionary = $converter->getItemTypeDictionary();
179 foreach($manager->getPotionContainerChangeRecipes() as $recipe){
180 $input = $itemTypeDictionary->fromStringId($recipe->getInputItemId());
181 $ingredient = $converter->coreRecipeIngredientToNet($recipe->getIngredient())->getDescriptor();
182 if(!$ingredient instanceof IntIdMetaItemDescriptor){
183 throw new AssumptionFailedError();
184 }
185 $output = $itemTypeDictionary->fromStringId($recipe->getOutputItemId());
186 $potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe(
187 $input,
188 $ingredient->getId(),
189 $output
190 );
191 }
192
193 Timings::$craftingDataCacheRebuild->stopTiming();
194 return CraftingDataPacket::create($recipesWithTypeIds, $potionTypeRecipes, $potionContainerChangeRecipes, [], true);
195 }
196}
static create(array $recipesWithTypeIds, array $potionTypeRecipes, array $potionContainerRecipes, array $materialReducerRecipes, bool $cleanRecipes)