mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-03 16:45:13 +00:00
Bedrock 1.21.60 (#6627)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
This commit is contained in:
@ -690,7 +690,7 @@ class InventoryManager{
|
||||
}
|
||||
|
||||
public function syncCreative() : void{
|
||||
$this->session->sendDataPacket(CreativeInventoryCache::getInstance()->getCache($this->player->getCreativeInventory()));
|
||||
$this->session->sendDataPacket(CreativeInventoryCache::getInstance()->buildPacket($this->player->getCreativeInventory(), $this->session));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1058,7 +1058,7 @@ class NetworkSession{
|
||||
];
|
||||
|
||||
$layers = [
|
||||
new AbilitiesLayer(AbilitiesLayer::LAYER_BASE, $boolAbilities, $for->getFlightSpeedMultiplier(), 0.1),
|
||||
new AbilitiesLayer(AbilitiesLayer::LAYER_BASE, $boolAbilities, $for->getFlightSpeedMultiplier(), 1, 0.1),
|
||||
];
|
||||
if(!$for->hasBlockCollision()){
|
||||
//TODO: HACK! In 1.19.80, the client starts falling in our faux spectator mode when it clips into a
|
||||
@ -1068,7 +1068,7 @@ class NetworkSession{
|
||||
|
||||
$layers[] = new AbilitiesLayer(AbilitiesLayer::LAYER_SPECTATOR, [
|
||||
AbilitiesLayer::ABILITY_FLYING => true,
|
||||
], null, null);
|
||||
], null, null, null);
|
||||
}
|
||||
|
||||
$this->sendDataPacket(UpdateAbilitiesPacket::create(new AbilitiesData(
|
||||
|
106
src/network/mcpe/cache/CreativeInventoryCache.php
vendored
106
src/network/mcpe/cache/CreativeInventoryCache.php
vendored
@ -23,23 +23,30 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\cache;
|
||||
|
||||
use pocketmine\inventory\CreativeCategory;
|
||||
use pocketmine\inventory\CreativeInventory;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\CreativeContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeGroupEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeItemEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use function is_string;
|
||||
use function spl_object_id;
|
||||
use const PHP_INT_MIN;
|
||||
|
||||
final class CreativeInventoryCache{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @var CreativeContentPacket[]
|
||||
* @phpstan-var array<int, CreativeContentPacket>
|
||||
* @var CreativeInventoryCacheEntry[]
|
||||
* @phpstan-var array<int, CreativeInventoryCacheEntry>
|
||||
*/
|
||||
private array $caches = [];
|
||||
|
||||
public function getCache(CreativeInventory $inventory) : CreativeContentPacket{
|
||||
private function getCacheEntry(CreativeInventory $inventory) : CreativeInventoryCacheEntry{
|
||||
$id = spl_object_id($inventory);
|
||||
if(!isset($this->caches[$id])){
|
||||
$inventory->getDestructorCallbacks()->add(function() use ($id) : void{
|
||||
@ -48,7 +55,7 @@ final class CreativeInventoryCache{
|
||||
$inventory->getContentChangedCallbacks()->add(function() use ($id) : void{
|
||||
unset($this->caches[$id]);
|
||||
});
|
||||
$this->caches[$id] = $this->buildCreativeInventoryCache($inventory);
|
||||
$this->caches[$id] = $this->buildCacheEntry($inventory);
|
||||
}
|
||||
return $this->caches[$id];
|
||||
}
|
||||
@ -56,14 +63,91 @@ final class CreativeInventoryCache{
|
||||
/**
|
||||
* Rebuild the cache for the given inventory.
|
||||
*/
|
||||
private function buildCreativeInventoryCache(CreativeInventory $inventory) : CreativeContentPacket{
|
||||
$entries = [];
|
||||
private function buildCacheEntry(CreativeInventory $inventory) : CreativeInventoryCacheEntry{
|
||||
$categories = [];
|
||||
$groups = [];
|
||||
|
||||
$typeConverter = TypeConverter::getInstance();
|
||||
//creative inventory may have holes if items were unregistered - ensure network IDs used are always consistent
|
||||
foreach($inventory->getAll() as $k => $item){
|
||||
$entries[] = new CreativeContentEntry($k, $typeConverter->coreItemStackToNet($item));
|
||||
|
||||
$nextIndex = 0;
|
||||
$groupIndexes = [];
|
||||
$itemGroupIndexes = [];
|
||||
|
||||
foreach($inventory->getAllEntries() as $k => $entry){
|
||||
$group = $entry->getGroup();
|
||||
$category = $entry->getCategory();
|
||||
if($group === null){
|
||||
$groupId = PHP_INT_MIN;
|
||||
}else{
|
||||
$groupId = spl_object_id($group);
|
||||
unset($groupIndexes[$category->name][PHP_INT_MIN]); //start a new anonymous group for this category
|
||||
}
|
||||
|
||||
//group object may be reused by multiple categories
|
||||
if(!isset($groupIndexes[$category->name][$groupId])){
|
||||
$groupIndexes[$category->name][$groupId] = $nextIndex++;
|
||||
$categories[] = $category;
|
||||
$groups[] = $group;
|
||||
}
|
||||
$itemGroupIndexes[$k] = $groupIndexes[$category->name][$groupId];
|
||||
}
|
||||
|
||||
return CreativeContentPacket::create($entries);
|
||||
//creative inventory may have holes if items were unregistered - ensure network IDs used are always consistent
|
||||
$items = [];
|
||||
foreach($inventory->getAllEntries() as $k => $entry){
|
||||
$items[] = new CreativeItemEntry(
|
||||
$k,
|
||||
$typeConverter->coreItemStackToNet($entry->getItem()),
|
||||
$itemGroupIndexes[$k]
|
||||
);
|
||||
}
|
||||
|
||||
return new CreativeInventoryCacheEntry($categories, $groups, $items);
|
||||
}
|
||||
|
||||
public function buildPacket(CreativeInventory $inventory, NetworkSession $session) : CreativeContentPacket{
|
||||
$player = $session->getPlayer() ?? throw new \LogicException("Cannot prepare creative data for a session without a player");
|
||||
$language = $player->getLanguage();
|
||||
$forceLanguage = $player->getServer()->isLanguageForced();
|
||||
$typeConverter = $session->getTypeConverter();
|
||||
$cachedEntry = $this->getCacheEntry($inventory);
|
||||
$translate = function(Translatable|string $translatable) use ($session, $language, $forceLanguage) : string{
|
||||
if(is_string($translatable)){
|
||||
$message = $translatable;
|
||||
}elseif(!$forceLanguage){
|
||||
[$message,] = $session->prepareClientTranslatableMessage($translatable);
|
||||
}else{
|
||||
$message = $language->translate($translatable);
|
||||
}
|
||||
return $message;
|
||||
};
|
||||
|
||||
$groupEntries = [];
|
||||
foreach($cachedEntry->categories as $index => $category){
|
||||
$group = $cachedEntry->groups[$index];
|
||||
$categoryId = match ($category) {
|
||||
CreativeCategory::CONSTRUCTION => CreativeContentPacket::CATEGORY_CONSTRUCTION,
|
||||
CreativeCategory::NATURE => CreativeContentPacket::CATEGORY_NATURE,
|
||||
CreativeCategory::EQUIPMENT => CreativeContentPacket::CATEGORY_EQUIPMENT,
|
||||
CreativeCategory::ITEMS => CreativeContentPacket::CATEGORY_ITEMS
|
||||
};
|
||||
if($group === null){
|
||||
$groupEntries[] = new CreativeGroupEntry($categoryId, "", ItemStack::null());
|
||||
}else{
|
||||
$groupIcon = $group->getIcon();
|
||||
//TODO: HACK! In 1.21.60, Workaround glitchy behaviour when an item is used as an icon for a group it
|
||||
//doesn't belong to. Without this hack, both instances of the item will show a +, but neither of them
|
||||
//will actually expand the group work correctly.
|
||||
$groupIcon->getNamedTag()->setInt("___GroupBugWorkaround___", $index);
|
||||
$groupName = $group->getName();
|
||||
$groupEntries[] = new CreativeGroupEntry(
|
||||
$categoryId,
|
||||
$translate($groupName),
|
||||
$typeConverter->coreItemStackToNet($groupIcon)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return CreativeContentPacket::create($groupEntries, $cachedEntry->items);
|
||||
}
|
||||
}
|
||||
|
48
src/network/mcpe/cache/CreativeInventoryCacheEntry.php
vendored
Normal file
48
src/network/mcpe/cache/CreativeInventoryCacheEntry.php
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
<?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\cache;
|
||||
|
||||
use pocketmine\inventory\CreativeCategory;
|
||||
use pocketmine\inventory\CreativeGroup;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeItemEntry;
|
||||
|
||||
final class CreativeInventoryCacheEntry{
|
||||
|
||||
/**
|
||||
* @param CreativeCategory[] $categories
|
||||
* @param CreativeGroup[]|null[] $groups
|
||||
* @param CreativeItemEntry[] $items
|
||||
*
|
||||
* @phpstan-param list<CreativeCategory> $categories
|
||||
* @phpstan-param list<CreativeGroup|null> $groups
|
||||
* @phpstan-param list<CreativeItemEntry> $items
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly array $categories,
|
||||
public readonly array $groups,
|
||||
public readonly array $items,
|
||||
){
|
||||
//NOOP
|
||||
}
|
||||
}
|
@ -23,10 +23,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\convert;
|
||||
|
||||
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||
use pocketmine\nbt\LittleEndianNbtSerializer;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||
use pocketmine\network\mcpe\protocol\types\ItemTypeEntry;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Utils;
|
||||
use function base64_decode;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_int;
|
||||
@ -41,12 +46,15 @@ final class ItemTypeDictionaryFromDataHelper{
|
||||
throw new AssumptionFailedError("Invalid item list format");
|
||||
}
|
||||
|
||||
$emptyNBT = new CacheableNbt(new CompoundTag());
|
||||
$nbtSerializer = new LittleEndianNbtSerializer();
|
||||
|
||||
$params = [];
|
||||
foreach(Utils::promoteKeys($table) as $name => $entry){
|
||||
if(!is_array($entry) || !is_string($name) || !isset($entry["component_based"], $entry["runtime_id"]) || !is_bool($entry["component_based"]) || !is_int($entry["runtime_id"])){
|
||||
if(!is_array($entry) || !is_string($name) || !isset($entry["component_based"], $entry["runtime_id"], $entry["version"]) || !is_bool($entry["component_based"]) || !is_int($entry["runtime_id"]) || !is_int($entry["version"]) || !(is_string($componentNbt = $entry["component_nbt"] ?? null) || $componentNbt === null)){
|
||||
throw new AssumptionFailedError("Invalid item list format");
|
||||
}
|
||||
$params[] = new ItemTypeEntry($name, $entry["runtime_id"], $entry["component_based"]);
|
||||
$params[] = new ItemTypeEntry($name, $entry["runtime_id"], $entry["component_based"], $entry["version"], $componentNbt === null ? $emptyNBT : new CacheableNbt($nbtSerializer->read(ErrorToExceptionHandler::trapAndRemoveFalse(fn() => base64_decode($componentNbt, true)))->mustGetCompoundTag()));
|
||||
}
|
||||
return new ItemTypeDictionary($params);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\network\mcpe\cache\CraftingDataCache;
|
||||
use pocketmine\network\mcpe\cache\StaticPacketCache;
|
||||
use pocketmine\network\mcpe\InventoryManager;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\ItemRegistryPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
||||
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
||||
@ -110,9 +111,11 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
new NetworkPermissions(disableClientSounds: true),
|
||||
[],
|
||||
0,
|
||||
$typeConverter->getItemTypeDictionary()->getEntries(),
|
||||
));
|
||||
|
||||
$this->session->getLogger()->debug("Sending items");
|
||||
$this->session->sendDataPacket(ItemRegistryPacket::create($typeConverter->getItemTypeDictionary()->getEntries()));
|
||||
|
||||
$this->session->getLogger()->debug("Sending actor identifiers");
|
||||
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getAvailableActorIdentifiers());
|
||||
|
||||
|
Reference in New Issue
Block a user