mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-07 20:28:31 +00:00
Removed crafting data cache from CraftingManager
This commit is contained in:
parent
31089ce3b2
commit
0d9561c93f
@ -23,23 +23,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\crafting;
|
namespace pocketmine\crafting;
|
||||||
|
|
||||||
|
use Ds\Set;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
use pocketmine\utils\DestructorCallbackTrait;
|
||||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe as ProtocolFurnaceRecipe;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe;
|
|
||||||
use pocketmine\timings\Timings;
|
|
||||||
use pocketmine\utils\Binary;
|
|
||||||
use pocketmine\uuid\UUID;
|
|
||||||
use function array_map;
|
|
||||||
use function json_encode;
|
use function json_encode;
|
||||||
use function str_repeat;
|
|
||||||
use function usort;
|
use function usort;
|
||||||
|
|
||||||
class CraftingManager{
|
class CraftingManager{
|
||||||
|
use DestructorCallbackTrait;
|
||||||
|
|
||||||
/** @var ShapedRecipe[][] */
|
/** @var ShapedRecipe[][] */
|
||||||
protected $shapedRecipes = [];
|
protected $shapedRecipes = [];
|
||||||
/** @var ShapelessRecipe[][] */
|
/** @var ShapelessRecipe[][] */
|
||||||
@ -48,93 +40,24 @@ class CraftingManager{
|
|||||||
/** @var FurnaceRecipeManager */
|
/** @var FurnaceRecipeManager */
|
||||||
protected $furnaceRecipeManager;
|
protected $furnaceRecipeManager;
|
||||||
|
|
||||||
/** @var CraftingDataPacket|null */
|
/**
|
||||||
private $craftingDataCache = null;
|
* @var Set
|
||||||
|
* @phpstan-var Set<\Closure() : void>
|
||||||
|
*/
|
||||||
|
private $recipeRegisteredCallbacks;
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
|
$this->recipeRegisteredCallbacks = new Set();
|
||||||
$this->furnaceRecipeManager = new FurnaceRecipeManager();
|
$this->furnaceRecipeManager = new FurnaceRecipeManager();
|
||||||
$this->furnaceRecipeManager->getRecipeRegisteredCallbacks()->add(function(FurnaceRecipe $recipe) : void{
|
$this->furnaceRecipeManager->getRecipeRegisteredCallbacks()->add(function(FurnaceRecipe $recipe) : void{
|
||||||
$this->craftingDataCache = null;
|
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||||
|
$callback();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @phpstan-return Set<\Closure() : void> */
|
||||||
* Rebuilds the cached CraftingDataPacket.
|
public function getRecipeRegisteredCallbacks() : Set{ return $this->recipeRegisteredCallbacks; }
|
||||||
*/
|
|
||||||
private function buildCraftingDataCache() : CraftingDataPacket{
|
|
||||||
Timings::$craftingDataCacheRebuildTimer->startTiming();
|
|
||||||
$pk = new CraftingDataPacket();
|
|
||||||
$pk->cleanRecipes = true;
|
|
||||||
|
|
||||||
$counter = 0;
|
|
||||||
$nullUUID = UUID::fromData(str_repeat("\x00", 16));
|
|
||||||
$converter = TypeConverter::getInstance();
|
|
||||||
foreach($this->shapelessRecipes as $list){
|
|
||||||
foreach($list as $recipe){
|
|
||||||
$pk->entries[] = new ProtocolShapelessRecipe(
|
|
||||||
CraftingDataPacket::ENTRY_SHAPELESS,
|
|
||||||
Binary::writeInt($counter++),
|
|
||||||
array_map(function(Item $item) use ($converter) : RecipeIngredient{
|
|
||||||
return $converter->coreItemStackToRecipeIngredient($item);
|
|
||||||
}, $recipe->getIngredientList()),
|
|
||||||
array_map(function(Item $item) use ($converter) : ItemStack{
|
|
||||||
return $converter->coreItemStackToNet($item);
|
|
||||||
}, $recipe->getResults()),
|
|
||||||
$nullUUID,
|
|
||||||
"crafting_table",
|
|
||||||
50,
|
|
||||||
$counter
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach($this->shapedRecipes as $list){
|
|
||||||
foreach($list as $recipe){
|
|
||||||
$inputs = [];
|
|
||||||
|
|
||||||
for($row = 0, $height = $recipe->getHeight(); $row < $height; ++$row){
|
|
||||||
for($column = 0, $width = $recipe->getWidth(); $column < $width; ++$column){
|
|
||||||
$inputs[$row][$column] = $converter->coreItemStackToRecipeIngredient($recipe->getIngredient($column, $row));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$pk->entries[] = $r = new ProtocolShapedRecipe(
|
|
||||||
CraftingDataPacket::ENTRY_SHAPED,
|
|
||||||
Binary::writeInt($counter++),
|
|
||||||
$inputs,
|
|
||||||
array_map(function(Item $item) use ($converter) : ItemStack{
|
|
||||||
return $converter->coreItemStackToNet($item);
|
|
||||||
}, $recipe->getResults()),
|
|
||||||
$nullUUID,
|
|
||||||
"crafting_table",
|
|
||||||
50,
|
|
||||||
$counter
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($this->furnaceRecipeManager->getAll() as $recipe){
|
|
||||||
$input = $converter->coreItemStackToNet($recipe->getInput());
|
|
||||||
$pk->entries[] = new ProtocolFurnaceRecipe(
|
|
||||||
CraftingDataPacket::ENTRY_FURNACE_DATA,
|
|
||||||
$input->getId(),
|
|
||||||
$input->getMeta(),
|
|
||||||
$converter->coreItemStackToNet($recipe->getResult()),
|
|
||||||
"furnace"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $pk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a pre-compressed CraftingDataPacket for sending to players. Rebuilds the cache if it is not found.
|
|
||||||
*/
|
|
||||||
public function getCraftingDataPacket() : CraftingDataPacket{
|
|
||||||
if($this->craftingDataCache === null){
|
|
||||||
$this->craftingDataCache = $this->buildCraftingDataCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->craftingDataCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function used to arrange Shapeless Recipe ingredient lists into a consistent order.
|
* Function used to arrange Shapeless Recipe ingredient lists into a consistent order.
|
||||||
@ -205,13 +128,17 @@ class CraftingManager{
|
|||||||
public function registerShapedRecipe(ShapedRecipe $recipe) : void{
|
public function registerShapedRecipe(ShapedRecipe $recipe) : void{
|
||||||
$this->shapedRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
|
$this->shapedRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
|
||||||
|
|
||||||
$this->craftingDataCache = null;
|
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||||
|
$callback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerShapelessRecipe(ShapelessRecipe $recipe) : void{
|
public function registerShapelessRecipe(ShapelessRecipe $recipe) : void{
|
||||||
$this->shapelessRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
|
$this->shapelessRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
|
||||||
|
|
||||||
$this->craftingDataCache = null;
|
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||||
|
$callback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
132
src/network/mcpe/CraftingDataCache.php
Normal file
132
src/network/mcpe/CraftingDataCache.php
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\network\mcpe;
|
||||||
|
|
||||||
|
use pocketmine\crafting\CraftingManager;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
|
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe as ProtocolFurnaceRecipe;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe;
|
||||||
|
use pocketmine\timings\Timings;
|
||||||
|
use pocketmine\utils\Binary;
|
||||||
|
use pocketmine\utils\SingletonTrait;
|
||||||
|
use pocketmine\uuid\UUID;
|
||||||
|
use function array_map;
|
||||||
|
use function spl_object_id;
|
||||||
|
use function str_repeat;
|
||||||
|
|
||||||
|
final class CraftingDataCache{
|
||||||
|
use SingletonTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var CraftingDataPacket[]
|
||||||
|
* @phpstan-var array<int, CraftingDataPacket>
|
||||||
|
*/
|
||||||
|
private $caches = [];
|
||||||
|
|
||||||
|
public function getCache(CraftingManager $manager) : CraftingDataPacket{
|
||||||
|
$id = spl_object_id($manager);
|
||||||
|
if(!isset($this->caches[$id])){
|
||||||
|
$manager->getDestructorCallbacks()->add(function() use ($id) : void{
|
||||||
|
unset($this->caches[$id]);
|
||||||
|
});
|
||||||
|
$manager->getRecipeRegisteredCallbacks()->add(function() use ($id) : void{
|
||||||
|
unset($this->caches[$id]);
|
||||||
|
});
|
||||||
|
$this->caches[$id] = $this->buildCraftingDataCache($manager);
|
||||||
|
}
|
||||||
|
return $this->caches[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuilds the cached CraftingDataPacket.
|
||||||
|
*/
|
||||||
|
private function buildCraftingDataCache(CraftingManager $manager) : CraftingDataPacket{
|
||||||
|
Timings::$craftingDataCacheRebuildTimer->startTiming();
|
||||||
|
$pk = new CraftingDataPacket();
|
||||||
|
$pk->cleanRecipes = true;
|
||||||
|
|
||||||
|
$counter = 0;
|
||||||
|
$nullUUID = UUID::fromData(str_repeat("\x00", 16));
|
||||||
|
$converter = TypeConverter::getInstance();
|
||||||
|
foreach($manager->getShapelessRecipes() as $list){
|
||||||
|
foreach($list as $recipe){
|
||||||
|
$pk->entries[] = new ProtocolShapelessRecipe(
|
||||||
|
CraftingDataPacket::ENTRY_SHAPELESS,
|
||||||
|
Binary::writeInt($counter++),
|
||||||
|
array_map(function(Item $item) use ($converter) : RecipeIngredient{
|
||||||
|
return $converter->coreItemStackToRecipeIngredient($item);
|
||||||
|
}, $recipe->getIngredientList()),
|
||||||
|
array_map(function(Item $item) use ($converter) : ItemStack{
|
||||||
|
return $converter->coreItemStackToNet($item);
|
||||||
|
}, $recipe->getResults()),
|
||||||
|
$nullUUID,
|
||||||
|
"crafting_table",
|
||||||
|
50,
|
||||||
|
$counter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($manager->getShapedRecipes() as $list){
|
||||||
|
foreach($list as $recipe){
|
||||||
|
$inputs = [];
|
||||||
|
|
||||||
|
for($row = 0, $height = $recipe->getHeight(); $row < $height; ++$row){
|
||||||
|
for($column = 0, $width = $recipe->getWidth(); $column < $width; ++$column){
|
||||||
|
$inputs[$row][$column] = $converter->coreItemStackToRecipeIngredient($recipe->getIngredient($column, $row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$pk->entries[] = $r = new ProtocolShapedRecipe(
|
||||||
|
CraftingDataPacket::ENTRY_SHAPED,
|
||||||
|
Binary::writeInt($counter++),
|
||||||
|
$inputs,
|
||||||
|
array_map(function(Item $item) use ($converter) : ItemStack{
|
||||||
|
return $converter->coreItemStackToNet($item);
|
||||||
|
}, $recipe->getResults()),
|
||||||
|
$nullUUID,
|
||||||
|
"crafting_table",
|
||||||
|
50,
|
||||||
|
$counter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($manager->getFurnaceRecipeManager()->getAll() as $recipe){
|
||||||
|
$input = $converter->coreItemStackToNet($recipe->getInput());
|
||||||
|
$pk->entries[] = new ProtocolFurnaceRecipe(
|
||||||
|
CraftingDataPacket::ENTRY_FURNACE_DATA,
|
||||||
|
$input->getId(),
|
||||||
|
$input->getMeta(),
|
||||||
|
$converter->coreItemStackToNet($recipe->getResult()),
|
||||||
|
"furnace"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pk;
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\handler;
|
|||||||
use pocketmine\data\bedrock\LegacyItemIdToStringIdMap;
|
use pocketmine\data\bedrock\LegacyItemIdToStringIdMap;
|
||||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
|
use pocketmine\network\mcpe\CraftingDataCache;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
||||||
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
||||||
@ -100,7 +101,7 @@ class PreSpawnPacketHandler extends PacketHandler{
|
|||||||
$this->session->getInvManager()->syncAll();
|
$this->session->getInvManager()->syncAll();
|
||||||
$this->session->getInvManager()->syncCreative();
|
$this->session->getInvManager()->syncCreative();
|
||||||
$this->session->getInvManager()->syncSelectedHotbarSlot();
|
$this->session->getInvManager()->syncSelectedHotbarSlot();
|
||||||
$this->session->sendDataPacket($this->server->getCraftingManager()->getCraftingDataPacket());
|
$this->session->sendDataPacket(CraftingDataCache::getInstance()->getCache($this->server->getCraftingManager()));
|
||||||
|
|
||||||
$this->session->syncPlayerList($this->server->getOnlinePlayers());
|
$this->session->syncPlayerList($this->server->getOnlinePlayers());
|
||||||
}
|
}
|
||||||
|
52
src/utils/DestructorCallbackTrait.php
Normal file
52
src/utils/DestructorCallbackTrait.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\utils;
|
||||||
|
|
||||||
|
use Ds\Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This trait provides destructor callback functionality to objects which use it. This enables a weakmap-like system
|
||||||
|
* to function without actually having weak maps.
|
||||||
|
* TODO: remove this in PHP 8
|
||||||
|
*/
|
||||||
|
trait DestructorCallbackTrait{
|
||||||
|
/**
|
||||||
|
* @var Set
|
||||||
|
* @phpstan-var Set<\Closure() : void>|null
|
||||||
|
*/
|
||||||
|
private $destructorCallbacks = null;
|
||||||
|
|
||||||
|
/** @phpstan-return Set<\Closure() : void> */
|
||||||
|
public function getDestructorCallbacks() : Set{
|
||||||
|
return $this->destructorCallbacks === null ? ($this->destructorCallbacks = new Set()) : $this->destructorCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct(){
|
||||||
|
if($this->destructorCallbacks !== null){
|
||||||
|
foreach($this->destructorCallbacks as $callback){
|
||||||
|
$callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user