mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-07 02:08:21 +00:00
Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17418990148
This commit is contained in:
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup PHP and tools
|
- name: Setup PHP and tools
|
||||||
uses: shivammathur/setup-php@2.35.3
|
uses: shivammathur/setup-php@2.35.4
|
||||||
with:
|
with:
|
||||||
php-version: 8.3
|
php-version: 8.3
|
||||||
|
|
||||||
|
2
.github/workflows/draft-release-pr-check.yml
vendored
2
.github/workflows/draft-release-pr-check.yml
vendored
@ -49,7 +49,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@2.35.3
|
uses: shivammathur/setup-php@2.35.4
|
||||||
with:
|
with:
|
||||||
php-version: 8.3
|
php-version: 8.3
|
||||||
|
|
||||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -87,7 +87,7 @@ jobs:
|
|||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@2.35.3
|
uses: shivammathur/setup-php@2.35.4
|
||||||
with:
|
with:
|
||||||
php-version: ${{ env.PHP_VERSION }}
|
php-version: ${{ env.PHP_VERSION }}
|
||||||
|
|
||||||
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup PHP and tools
|
- name: Setup PHP and tools
|
||||||
uses: shivammathur/setup-php@2.35.3
|
uses: shivammathur/setup-php@2.35.4
|
||||||
with:
|
with:
|
||||||
php-version: 8.3
|
php-version: 8.3
|
||||||
tools: php-cs-fixer:3.75
|
tools: php-cs-fixer:3.75
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\network\mcpe\convert;
|
namespace pocketmine\network\mcpe\convert;
|
||||||
|
|
||||||
|
use pocketmine\block\tile\Container;
|
||||||
use pocketmine\block\VanillaBlocks;
|
use pocketmine\block\VanillaBlocks;
|
||||||
use pocketmine\crafting\ExactRecipeIngredient;
|
use pocketmine\crafting\ExactRecipeIngredient;
|
||||||
use pocketmine\crafting\MetaWildcardRecipeIngredient;
|
use pocketmine\crafting\MetaWildcardRecipeIngredient;
|
||||||
@ -31,10 +32,16 @@ use pocketmine\crafting\TagWildcardRecipeIngredient;
|
|||||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||||
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
use pocketmine\data\bedrock\item\BlockItemIdMap;
|
||||||
use pocketmine\data\bedrock\item\ItemTypeNames;
|
use pocketmine\data\bedrock\item\ItemTypeNames;
|
||||||
|
use pocketmine\data\SavedDataLoadingException;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\VanillaItems;
|
use pocketmine\item\VanillaItems;
|
||||||
|
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||||
|
use pocketmine\nbt\NBT;
|
||||||
use pocketmine\nbt\NbtException;
|
use pocketmine\nbt\NbtException;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
|
use pocketmine\nbt\tag\ListTag;
|
||||||
|
use pocketmine\nbt\tag\Tag;
|
||||||
|
use pocketmine\nbt\TreeRoot;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||||
use pocketmine\network\mcpe\protocol\types\GameMode as ProtocolGameMode;
|
use pocketmine\network\mcpe\protocol\types\GameMode as ProtocolGameMode;
|
||||||
@ -52,11 +59,13 @@ use pocketmine\utils\SingletonTrait;
|
|||||||
use pocketmine\world\format\io\GlobalBlockStateHandlers;
|
use pocketmine\world\format\io\GlobalBlockStateHandlers;
|
||||||
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
||||||
use function get_class;
|
use function get_class;
|
||||||
|
use function hash;
|
||||||
|
|
||||||
class TypeConverter{
|
class TypeConverter{
|
||||||
use SingletonTrait;
|
use SingletonTrait;
|
||||||
|
|
||||||
private const PM_ID_TAG = "___Id___";
|
private const PM_ID_TAG = "___Id___";
|
||||||
|
private const PM_FULL_NBT_HASH_TAG = "___FullNbtHash___";
|
||||||
|
|
||||||
private const RECIPE_INPUT_WILDCARD_META = 0x7fff;
|
private const RECIPE_INPUT_WILDCARD_META = 0x7fff;
|
||||||
|
|
||||||
@ -197,6 +206,85 @@ class TypeConverter{
|
|||||||
return new ExactRecipeIngredient($result);
|
return new ExactRecipeIngredient($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips unnecessary block actor NBT from items that have it.
|
||||||
|
* This tag can potentially be extremely large, and is not read by the client anyway.
|
||||||
|
*/
|
||||||
|
protected function stripBlockEntityNBT(CompoundTag $tag) : bool{
|
||||||
|
if(($tag->getTag(Item::TAG_BLOCK_ENTITY_TAG)) !== null){
|
||||||
|
//client doesn't use this tag, so it's fine to delete completely
|
||||||
|
$tag->removeTag(Item::TAG_BLOCK_ENTITY_TAG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips non-viewable data from shulker boxes and similar blocks
|
||||||
|
* The lore for shulker boxes only requires knowing the type & count of items and possibly custom name
|
||||||
|
* We don't need to, and should not allow, sending nested inventories across the network.
|
||||||
|
*/
|
||||||
|
protected function stripContainedItemNonVisualNBT(CompoundTag $tag) : bool{
|
||||||
|
if(
|
||||||
|
($blockEntityInventoryTag = $tag->getTag(Container::TAG_ITEMS)) !== null &&
|
||||||
|
$blockEntityInventoryTag instanceof ListTag &&
|
||||||
|
$blockEntityInventoryTag->getTagType() === NBT::TAG_Compound &&
|
||||||
|
$blockEntityInventoryTag->count() > 0
|
||||||
|
){
|
||||||
|
$stripped = new ListTag();
|
||||||
|
|
||||||
|
/** @var CompoundTag $itemTag */
|
||||||
|
foreach($blockEntityInventoryTag as $itemTag){
|
||||||
|
try{
|
||||||
|
$containedItem = Item::nbtDeserialize($itemTag);
|
||||||
|
$customName = $containedItem->getCustomName();
|
||||||
|
$containedItem->clearNamedTag();
|
||||||
|
$containedItem->setCustomName($customName);
|
||||||
|
$stripped->push($containedItem->nbtSerialize());
|
||||||
|
}catch(SavedDataLoadingException){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$tag->setTag(Container::TAG_ITEMS, $stripped);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a hash of an item's server-side NBT.
|
||||||
|
* This is baked into an item's network NBT to make sure the client doesn't try to stack items with the same network
|
||||||
|
* NBT but different server-side NBT.
|
||||||
|
*/
|
||||||
|
protected function hashNBT(Tag $tag) : string{
|
||||||
|
$encoded = (new LittleEndianNbtSerializer())->write(new TreeRoot($tag));
|
||||||
|
return hash('sha256', $encoded, binary: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: HACK!
|
||||||
|
* Creates a copy of an item's NBT with non-viewable data stripped.
|
||||||
|
* This is a pretty yucky hack that's mainly needed because of inventories inside blockitems containing blockentity
|
||||||
|
* data. There isn't really a good way to deal with this due to the way tiles currently require a position,
|
||||||
|
* otherwise we could just keep a copy of the tile context and ask it for persistent vs network NBT as needed.
|
||||||
|
* Unfortunately, making this nice will require significant BC breaks, so this will have to do for now.
|
||||||
|
*/
|
||||||
|
protected function cleanupUnnecessaryItemNBT(CompoundTag $original) : CompoundTag{
|
||||||
|
$tag = clone $original;
|
||||||
|
$anythingStripped = false;
|
||||||
|
foreach([
|
||||||
|
$this->stripContainedItemNonVisualNBT($tag),
|
||||||
|
$this->stripBlockEntityNBT($tag)
|
||||||
|
] as $stripped){
|
||||||
|
$anythingStripped = $anythingStripped || $stripped;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($anythingStripped){
|
||||||
|
$tag->setByteArray(self::PM_FULL_NBT_HASH_TAG, $this->hashNBT($original));
|
||||||
|
}
|
||||||
|
return $tag;
|
||||||
|
}
|
||||||
|
|
||||||
public function coreItemStackToNet(Item $itemStack) : ItemStack{
|
public function coreItemStackToNet(Item $itemStack) : ItemStack{
|
||||||
if($itemStack->isNull()){
|
if($itemStack->isNull()){
|
||||||
return ItemStack::null();
|
return ItemStack::null();
|
||||||
@ -205,7 +293,7 @@ class TypeConverter{
|
|||||||
if($nbt->count() === 0){
|
if($nbt->count() === 0){
|
||||||
$nbt = null;
|
$nbt = null;
|
||||||
}else{
|
}else{
|
||||||
$nbt = clone $nbt;
|
$nbt = $this->cleanupUnnecessaryItemNBT($nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
$idMeta = $this->itemTranslator->toNetworkIdQuiet($itemStack);
|
$idMeta = $this->itemTranslator->toNetworkIdQuiet($itemStack);
|
||||||
|
Reference in New Issue
Block a user