mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-23 19:34:15 +00:00
Remove ItemFactory involvement from brewing
this involves a very nasty hack for potion container change, but for the time being it can't be helped.
This commit is contained in:
parent
8831dff61b
commit
5e4e5147d9
@ -29,6 +29,7 @@ use pocketmine\nbt\TreeRoot;
|
|||||||
use pocketmine\utils\BinaryStream;
|
use pocketmine\utils\BinaryStream;
|
||||||
use pocketmine\utils\DestructorCallbackTrait;
|
use pocketmine\utils\DestructorCallbackTrait;
|
||||||
use pocketmine\utils\ObjectSet;
|
use pocketmine\utils\ObjectSet;
|
||||||
|
use function morton2d_encode;
|
||||||
use function usort;
|
use function usort;
|
||||||
|
|
||||||
class CraftingManager{
|
class CraftingManager{
|
||||||
@ -47,16 +48,22 @@ class CraftingManager{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @var PotionTypeRecipe[][]
|
* @var PotionTypeRecipe[][]
|
||||||
* @phpstan-var array<string, array<string, PotionTypeRecipe>>
|
* @phpstan-var list<PotionTypeRecipe>
|
||||||
*/
|
*/
|
||||||
protected array $potionTypeRecipes = [];
|
protected array $potionTypeRecipes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var PotionContainerChangeRecipe[][]
|
* @var PotionContainerChangeRecipe[]
|
||||||
* @phpstan-var array<int, array<string, PotionContainerChangeRecipe>>
|
* @phpstan-var list<PotionContainerChangeRecipe>
|
||||||
*/
|
*/
|
||||||
protected array $potionContainerChangeRecipes = [];
|
protected array $potionContainerChangeRecipes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BrewingRecipe[][]
|
||||||
|
* @phpstan-var array<int, array<int, BrewingRecipe>>
|
||||||
|
*/
|
||||||
|
private array $brewingRecipeCache = [];
|
||||||
|
|
||||||
/** @phpstan-var ObjectSet<\Closure() : void> */
|
/** @phpstan-var ObjectSet<\Closure() : void> */
|
||||||
private ObjectSet $recipeRegisteredCallbacks;
|
private ObjectSet $recipeRegisteredCallbacks;
|
||||||
|
|
||||||
@ -150,16 +157,16 @@ class CraftingManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return PotionTypeRecipe[][]
|
* @return PotionTypeRecipe[]
|
||||||
* @phpstan-return array<string, array<string, PotionTypeRecipe>>
|
* @phpstan-return list<PotionTypeRecipe>
|
||||||
*/
|
*/
|
||||||
public function getPotionTypeRecipes() : array{
|
public function getPotionTypeRecipes() : array{
|
||||||
return $this->potionTypeRecipes;
|
return $this->potionTypeRecipes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return PotionContainerChangeRecipe[][]
|
* @return PotionContainerChangeRecipe[]
|
||||||
* @phpstan-return array<int, array<string, PotionContainerChangeRecipe>>
|
* @phpstan-return list<PotionContainerChangeRecipe>
|
||||||
*/
|
*/
|
||||||
public function getPotionContainerChangeRecipes() : array{
|
public function getPotionContainerChangeRecipes() : array{
|
||||||
return $this->potionContainerChangeRecipes;
|
return $this->potionContainerChangeRecipes;
|
||||||
@ -182,9 +189,7 @@ class CraftingManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{
|
public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{
|
||||||
$input = $recipe->getInput();
|
$this->potionTypeRecipes[] = $recipe;
|
||||||
$ingredient = $recipe->getIngredient();
|
|
||||||
$this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . $ingredient->getMeta()] = $recipe;
|
|
||||||
|
|
||||||
foreach($this->recipeRegisteredCallbacks as $callback){
|
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||||
$callback();
|
$callback();
|
||||||
@ -192,8 +197,7 @@ class CraftingManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{
|
public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{
|
||||||
$ingredient = $recipe->getIngredient();
|
$this->potionContainerChangeRecipes[] = $recipe;
|
||||||
$this->potionContainerChangeRecipes[$recipe->getInputItemId()][$ingredient->getId() . ":" . $ingredient->getMeta()] = $recipe;
|
|
||||||
|
|
||||||
foreach($this->recipeRegisteredCallbacks as $callback){
|
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||||
$callback();
|
$callback();
|
||||||
@ -252,7 +256,25 @@ class CraftingManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function matchBrewingRecipe(Item $input, Item $ingredient) : ?BrewingRecipe{
|
public function matchBrewingRecipe(Item $input, Item $ingredient) : ?BrewingRecipe{
|
||||||
return $this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . $ingredient->getMeta()] ??
|
$inputHash = morton2d_encode($input->getId(), $input->getMeta());
|
||||||
$this->potionContainerChangeRecipes[$input->getId()][$ingredient->getId() . ":" . $ingredient->getMeta()] ?? null;
|
$ingredientHash = morton2d_encode($ingredient->getId(), $ingredient->getMeta());
|
||||||
|
$recipe = $this->brewingRecipeCache[$inputHash][$ingredientHash] ?? null;
|
||||||
|
if($recipe !== null){
|
||||||
|
return $recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($this->potionContainerChangeRecipes as $recipe){
|
||||||
|
if($recipe->getIngredient()->equals($ingredient) && $recipe->getResultFor($input) !== null){
|
||||||
|
return $this->brewingRecipeCache[$inputHash][$ingredientHash] = $recipe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($this->potionTypeRecipes as $recipe){
|
||||||
|
if($recipe->getIngredient()->equals($ingredient) && $recipe->getResultFor($input) !== null){
|
||||||
|
return $this->brewingRecipeCache[$inputHash][$ingredientHash] = $recipe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,9 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\crafting;
|
namespace pocketmine\crafting;
|
||||||
|
|
||||||
use pocketmine\data\bedrock\item\ItemTypeDeserializeException;
|
use pocketmine\data\bedrock\item\ItemTypeDeserializeException;
|
||||||
|
use pocketmine\data\bedrock\item\upgrade\LegacyItemIdToStringIdMap;
|
||||||
use pocketmine\data\SavedDataLoadingException;
|
use pocketmine\data\SavedDataLoadingException;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
|
||||||
use pocketmine\utils\AssumptionFailedError;
|
use pocketmine\utils\AssumptionFailedError;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
||||||
@ -172,17 +172,23 @@ final class CraftingManagerFromDataHelper{
|
|||||||
}
|
}
|
||||||
foreach($recipes["potion_container_change"] as $recipe){
|
foreach($recipes["potion_container_change"] as $recipe){
|
||||||
try{
|
try{
|
||||||
$input = ItemFactory::getInstance()->get($recipe["input_item_id"]);
|
|
||||||
$ingredient = Item::jsonDeserialize($recipe["ingredient"]);
|
$ingredient = Item::jsonDeserialize($recipe["ingredient"]);
|
||||||
$output = ItemFactory::getInstance()->get($recipe["output_item_id"]);
|
|
||||||
}catch(SavedDataLoadingException){
|
}catch(SavedDataLoadingException){
|
||||||
//unknown item
|
//unknown item
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: we'll be able to get rid of these conversions once the crafting data is updated
|
||||||
|
$inputId = LegacyItemIdToStringIdMap::getInstance()->legacyToString($recipe["input_item_id"]);
|
||||||
|
$outputId = LegacyItemIdToStringIdMap::getInstance()->legacyToString($recipe["output_item_id"]);
|
||||||
|
if($inputId === null || $outputId === null){
|
||||||
|
//unknown item
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$result->registerPotionContainerChangeRecipe(new PotionContainerChangeRecipe(
|
$result->registerPotionContainerChangeRecipe(new PotionContainerChangeRecipe(
|
||||||
$input->getId(),
|
$inputId,
|
||||||
$ingredient,
|
$ingredient,
|
||||||
$output->getId()
|
$outputId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,20 +23,21 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\crafting;
|
namespace pocketmine\crafting;
|
||||||
|
|
||||||
|
use pocketmine\data\bedrock\item\SavedItemData;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
||||||
|
|
||||||
class PotionContainerChangeRecipe implements BrewingRecipe{
|
class PotionContainerChangeRecipe implements BrewingRecipe{
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private int $inputItemId,
|
private string $inputItemId,
|
||||||
private Item $ingredient,
|
private Item $ingredient,
|
||||||
private int $outputItemId
|
private string $outputItemId
|
||||||
){
|
){
|
||||||
$this->ingredient = clone $ingredient;
|
$this->ingredient = clone $ingredient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInputItemId() : int{
|
public function getInputItemId() : string{
|
||||||
return $this->inputItemId;
|
return $this->inputItemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,11 +45,20 @@ class PotionContainerChangeRecipe implements BrewingRecipe{
|
|||||||
return clone $this->ingredient;
|
return clone $this->ingredient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOutputItemId() : int{
|
public function getOutputItemId() : string{
|
||||||
return $this->outputItemId;
|
return $this->outputItemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getResultFor(Item $input) : ?Item{
|
public function getResultFor(Item $input) : ?Item{
|
||||||
return $input->getId() === $this->getInputItemId() ? ItemFactory::getInstance()->get($this->getOutputItemId(), $input->getMeta()) : null;
|
//TODO: this is a really awful hack, but there isn't another way for now
|
||||||
|
//this relies on transforming the serialized item's ID, relying on the target item type's data being the same as the input.
|
||||||
|
//This is the same assumption previously made using ItemFactory::get(), except it was less obvious how bad it was.
|
||||||
|
//The other way is to bake the actual Potion class types into here, which isn't great for data-driving stuff.
|
||||||
|
//We need a better solution for this.
|
||||||
|
|
||||||
|
$data = GlobalItemDataHandlers::getSerializer()->serializeType($input);
|
||||||
|
return $data->getName() === $this->getInputItemId() ?
|
||||||
|
GlobalItemDataHandlers::getDeserializer()->deserializeType(new SavedItemData($this->getOutputItemId(), $data->getMeta(), $data->getBlock(), $data->getTag())) :
|
||||||
|
null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
src/network/mcpe/cache/CraftingDataCache.php
vendored
51
src/network/mcpe/cache/CraftingDataCache.php
vendored
@ -28,8 +28,7 @@ use pocketmine\crafting\FurnaceType;
|
|||||||
use pocketmine\crafting\RecipeIngredient;
|
use pocketmine\crafting\RecipeIngredient;
|
||||||
use pocketmine\crafting\ShapelessRecipeType;
|
use pocketmine\crafting\ShapelessRecipeType;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
|
||||||
use pocketmine\network\mcpe\convert\ItemTranslator;
|
|
||||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||||
@ -149,35 +148,31 @@ final class CraftingDataCache{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$potionTypeRecipes = [];
|
$potionTypeRecipes = [];
|
||||||
foreach($manager->getPotionTypeRecipes() as $recipes){
|
foreach($manager->getPotionTypeRecipes() as $recipe){
|
||||||
foreach($recipes as $recipe){
|
$input = $converter->coreItemStackToNet($recipe->getInput());
|
||||||
$input = $converter->coreItemStackToNet($recipe->getInput());
|
$ingredient = $converter->coreItemStackToNet($recipe->getIngredient());
|
||||||
$ingredient = $converter->coreItemStackToNet($recipe->getIngredient());
|
$output = $converter->coreItemStackToNet($recipe->getOutput());
|
||||||
$output = $converter->coreItemStackToNet($recipe->getOutput());
|
$potionTypeRecipes[] = new ProtocolPotionTypeRecipe(
|
||||||
$potionTypeRecipes[] = new ProtocolPotionTypeRecipe(
|
$input->getId(),
|
||||||
$input->getId(),
|
$input->getMeta(),
|
||||||
$input->getMeta(),
|
$ingredient->getId(),
|
||||||
$ingredient->getId(),
|
$ingredient->getMeta(),
|
||||||
$ingredient->getMeta(),
|
$output->getId(),
|
||||||
$output->getId(),
|
$output->getMeta()
|
||||||
$output->getMeta()
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$potionContainerChangeRecipes = [];
|
$potionContainerChangeRecipes = [];
|
||||||
$itemTranslator = ItemTranslator::getInstance();
|
$itemTypeDictionary = GlobalItemTypeDictionary::getInstance()->getDictionary();
|
||||||
foreach($manager->getPotionContainerChangeRecipes() as $recipes){
|
foreach($manager->getPotionContainerChangeRecipes() as $recipe){
|
||||||
foreach($recipes as $recipe){
|
$input = $itemTypeDictionary->fromStringId($recipe->getInputItemId());
|
||||||
$input = $itemTranslator->toNetworkId(ItemFactory::getInstance()->get($recipe->getInputItemId(), 0));
|
$ingredient = $converter->coreItemStackToNet($recipe->getIngredient());
|
||||||
$ingredient = $itemTranslator->toNetworkId($recipe->getIngredient());
|
$output = $itemTypeDictionary->fromStringId($recipe->getOutputItemId());
|
||||||
$output = $itemTranslator->toNetworkId(ItemFactory::getInstance()->get($recipe->getOutputItemId(), 0));
|
$potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe(
|
||||||
$potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe(
|
$input,
|
||||||
$input[0],
|
$ingredient->getId(),
|
||||||
$ingredient[0],
|
$output
|
||||||
$output[0]
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Timings::$craftingDataCacheRebuild->stopTiming();
|
Timings::$craftingDataCacheRebuild->stopTiming();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user