mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-23 11:26:37 +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\DestructorCallbackTrait;
|
||||
use pocketmine\utils\ObjectSet;
|
||||
use function morton2d_encode;
|
||||
use function usort;
|
||||
|
||||
class CraftingManager{
|
||||
@ -47,16 +48,22 @@ class CraftingManager{
|
||||
|
||||
/**
|
||||
* @var PotionTypeRecipe[][]
|
||||
* @phpstan-var array<string, array<string, PotionTypeRecipe>>
|
||||
* @phpstan-var list<PotionTypeRecipe>
|
||||
*/
|
||||
protected array $potionTypeRecipes = [];
|
||||
|
||||
/**
|
||||
* @var PotionContainerChangeRecipe[][]
|
||||
* @phpstan-var array<int, array<string, PotionContainerChangeRecipe>>
|
||||
* @var PotionContainerChangeRecipe[]
|
||||
* @phpstan-var list<PotionContainerChangeRecipe>
|
||||
*/
|
||||
protected array $potionContainerChangeRecipes = [];
|
||||
|
||||
/**
|
||||
* @var BrewingRecipe[][]
|
||||
* @phpstan-var array<int, array<int, BrewingRecipe>>
|
||||
*/
|
||||
private array $brewingRecipeCache = [];
|
||||
|
||||
/** @phpstan-var ObjectSet<\Closure() : void> */
|
||||
private ObjectSet $recipeRegisteredCallbacks;
|
||||
|
||||
@ -150,16 +157,16 @@ class CraftingManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PotionTypeRecipe[][]
|
||||
* @phpstan-return array<string, array<string, PotionTypeRecipe>>
|
||||
* @return PotionTypeRecipe[]
|
||||
* @phpstan-return list<PotionTypeRecipe>
|
||||
*/
|
||||
public function getPotionTypeRecipes() : array{
|
||||
return $this->potionTypeRecipes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PotionContainerChangeRecipe[][]
|
||||
* @phpstan-return array<int, array<string, PotionContainerChangeRecipe>>
|
||||
* @return PotionContainerChangeRecipe[]
|
||||
* @phpstan-return list<PotionContainerChangeRecipe>
|
||||
*/
|
||||
public function getPotionContainerChangeRecipes() : array{
|
||||
return $this->potionContainerChangeRecipes;
|
||||
@ -182,9 +189,7 @@ class CraftingManager{
|
||||
}
|
||||
|
||||
public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{
|
||||
$input = $recipe->getInput();
|
||||
$ingredient = $recipe->getIngredient();
|
||||
$this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . $ingredient->getMeta()] = $recipe;
|
||||
$this->potionTypeRecipes[] = $recipe;
|
||||
|
||||
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||
$callback();
|
||||
@ -192,8 +197,7 @@ class CraftingManager{
|
||||
}
|
||||
|
||||
public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{
|
||||
$ingredient = $recipe->getIngredient();
|
||||
$this->potionContainerChangeRecipes[$recipe->getInputItemId()][$ingredient->getId() . ":" . $ingredient->getMeta()] = $recipe;
|
||||
$this->potionContainerChangeRecipes[] = $recipe;
|
||||
|
||||
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||
$callback();
|
||||
@ -252,7 +256,25 @@ class CraftingManager{
|
||||
}
|
||||
|
||||
public function matchBrewingRecipe(Item $input, Item $ingredient) : ?BrewingRecipe{
|
||||
return $this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . $ingredient->getMeta()] ??
|
||||
$this->potionContainerChangeRecipes[$input->getId()][$ingredient->getId() . ":" . $ingredient->getMeta()] ?? null;
|
||||
$inputHash = morton2d_encode($input->getId(), $input->getMeta());
|
||||
$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;
|
||||
|
||||
use pocketmine\data\bedrock\item\ItemTypeDeserializeException;
|
||||
use pocketmine\data\bedrock\item\upgrade\LegacyItemIdToStringIdMap;
|
||||
use pocketmine\data\SavedDataLoadingException;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
||||
@ -172,17 +172,23 @@ final class CraftingManagerFromDataHelper{
|
||||
}
|
||||
foreach($recipes["potion_container_change"] as $recipe){
|
||||
try{
|
||||
$input = ItemFactory::getInstance()->get($recipe["input_item_id"]);
|
||||
$ingredient = Item::jsonDeserialize($recipe["ingredient"]);
|
||||
$output = ItemFactory::getInstance()->get($recipe["output_item_id"]);
|
||||
}catch(SavedDataLoadingException){
|
||||
//unknown item
|
||||
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(
|
||||
$input->getId(),
|
||||
$inputId,
|
||||
$ingredient,
|
||||
$output->getId()
|
||||
$outputId
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -23,20 +23,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\data\bedrock\item\SavedItemData;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
||||
|
||||
class PotionContainerChangeRecipe implements BrewingRecipe{
|
||||
|
||||
public function __construct(
|
||||
private int $inputItemId,
|
||||
private string $inputItemId,
|
||||
private Item $ingredient,
|
||||
private int $outputItemId
|
||||
private string $outputItemId
|
||||
){
|
||||
$this->ingredient = clone $ingredient;
|
||||
}
|
||||
|
||||
public function getInputItemId() : int{
|
||||
public function getInputItemId() : string{
|
||||
return $this->inputItemId;
|
||||
}
|
||||
|
||||
@ -44,11 +45,20 @@ class PotionContainerChangeRecipe implements BrewingRecipe{
|
||||
return clone $this->ingredient;
|
||||
}
|
||||
|
||||
public function getOutputItemId() : int{
|
||||
public function getOutputItemId() : string{
|
||||
return $this->outputItemId;
|
||||
}
|
||||
|
||||
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\ShapelessRecipeType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\network\mcpe\convert\ItemTranslator;
|
||||
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
@ -149,35 +148,31 @@ final class CraftingDataCache{
|
||||
}
|
||||
|
||||
$potionTypeRecipes = [];
|
||||
foreach($manager->getPotionTypeRecipes() as $recipes){
|
||||
foreach($recipes as $recipe){
|
||||
$input = $converter->coreItemStackToNet($recipe->getInput());
|
||||
$ingredient = $converter->coreItemStackToNet($recipe->getIngredient());
|
||||
$output = $converter->coreItemStackToNet($recipe->getOutput());
|
||||
$potionTypeRecipes[] = new ProtocolPotionTypeRecipe(
|
||||
$input->getId(),
|
||||
$input->getMeta(),
|
||||
$ingredient->getId(),
|
||||
$ingredient->getMeta(),
|
||||
$output->getId(),
|
||||
$output->getMeta()
|
||||
);
|
||||
}
|
||||
foreach($manager->getPotionTypeRecipes() as $recipe){
|
||||
$input = $converter->coreItemStackToNet($recipe->getInput());
|
||||
$ingredient = $converter->coreItemStackToNet($recipe->getIngredient());
|
||||
$output = $converter->coreItemStackToNet($recipe->getOutput());
|
||||
$potionTypeRecipes[] = new ProtocolPotionTypeRecipe(
|
||||
$input->getId(),
|
||||
$input->getMeta(),
|
||||
$ingredient->getId(),
|
||||
$ingredient->getMeta(),
|
||||
$output->getId(),
|
||||
$output->getMeta()
|
||||
);
|
||||
}
|
||||
|
||||
$potionContainerChangeRecipes = [];
|
||||
$itemTranslator = ItemTranslator::getInstance();
|
||||
foreach($manager->getPotionContainerChangeRecipes() as $recipes){
|
||||
foreach($recipes as $recipe){
|
||||
$input = $itemTranslator->toNetworkId(ItemFactory::getInstance()->get($recipe->getInputItemId(), 0));
|
||||
$ingredient = $itemTranslator->toNetworkId($recipe->getIngredient());
|
||||
$output = $itemTranslator->toNetworkId(ItemFactory::getInstance()->get($recipe->getOutputItemId(), 0));
|
||||
$potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe(
|
||||
$input[0],
|
||||
$ingredient[0],
|
||||
$output[0]
|
||||
);
|
||||
}
|
||||
$itemTypeDictionary = GlobalItemTypeDictionary::getInstance()->getDictionary();
|
||||
foreach($manager->getPotionContainerChangeRecipes() as $recipe){
|
||||
$input = $itemTypeDictionary->fromStringId($recipe->getInputItemId());
|
||||
$ingredient = $converter->coreItemStackToNet($recipe->getIngredient());
|
||||
$output = $itemTypeDictionary->fromStringId($recipe->getOutputItemId());
|
||||
$potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe(
|
||||
$input,
|
||||
$ingredient->getId(),
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
Timings::$craftingDataCacheRebuild->stopTiming();
|
||||
|
Loading…
x
Reference in New Issue
Block a user