PocketMine-MP 5.25.1 git-694aa17cc916a954b10fe12721c81b1dc73eecd5
Loading...
Searching...
No Matches
CreativeInventoryCache.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\network\mcpe\cache;
25
35use pocketmine\utils\SingletonTrait;
36use function is_string;
37use function spl_object_id;
38use const PHP_INT_MIN;
39
41 use SingletonTrait;
42
47 private array $caches = [];
48
49 private function getCacheEntry(CreativeInventory $inventory) : CreativeInventoryCacheEntry{
50 $id = spl_object_id($inventory);
51 if(!isset($this->caches[$id])){
52 $inventory->getDestructorCallbacks()->add(function() use ($id) : void{
53 unset($this->caches[$id]);
54 });
55 $inventory->getContentChangedCallbacks()->add(function() use ($id) : void{
56 unset($this->caches[$id]);
57 });
58 $this->caches[$id] = $this->buildCacheEntry($inventory);
59 }
60 return $this->caches[$id];
61 }
62
66 private function buildCacheEntry(CreativeInventory $inventory) : CreativeInventoryCacheEntry{
67 $categories = [];
68 $groups = [];
69
70 $typeConverter = TypeConverter::getInstance();
71
72 $nextIndex = 0;
73 $groupIndexes = [];
74 $itemGroupIndexes = [];
75
76 foreach($inventory->getAllEntries() as $k => $entry){
77 $group = $entry->getGroup();
78 $category = $entry->getCategory();
79 if($group === null){
80 $groupId = PHP_INT_MIN;
81 }else{
82 $groupId = spl_object_id($group);
83 unset($groupIndexes[$category->name][PHP_INT_MIN]); //start a new anonymous group for this category
84 }
85
86 //group object may be reused by multiple categories
87 if(!isset($groupIndexes[$category->name][$groupId])){
88 $groupIndexes[$category->name][$groupId] = $nextIndex++;
89 $categories[] = $category;
90 $groups[] = $group;
91 }
92 $itemGroupIndexes[$k] = $groupIndexes[$category->name][$groupId];
93 }
94
95 //creative inventory may have holes if items were unregistered - ensure network IDs used are always consistent
96 $items = [];
97 foreach($inventory->getAllEntries() as $k => $entry){
98 $items[] = new CreativeItemEntry(
99 $k,
100 $typeConverter->coreItemStackToNet($entry->getItem()),
101 $itemGroupIndexes[$k]
102 );
103 }
104
105 return new CreativeInventoryCacheEntry($categories, $groups, $items);
106 }
107
108 public function buildPacket(CreativeInventory $inventory, NetworkSession $session) : CreativeContentPacket{
109 $player = $session->getPlayer() ?? throw new \LogicException("Cannot prepare creative data for a session without a player");
110 $language = $player->getLanguage();
111 $forceLanguage = $player->getServer()->isLanguageForced();
112 $typeConverter = $session->getTypeConverter();
113 $cachedEntry = $this->getCacheEntry($inventory);
114 $translate = function(Translatable|string $translatable) use ($session, $language, $forceLanguage) : string{
115 if(is_string($translatable)){
116 $message = $translatable;
117 }elseif(!$forceLanguage){
118 [$message,] = $session->prepareClientTranslatableMessage($translatable);
119 }else{
120 $message = $language->translate($translatable);
121 }
122 return $message;
123 };
124
125 $groupEntries = [];
126 foreach($cachedEntry->categories as $index => $category){
127 $group = $cachedEntry->groups[$index];
128 $categoryId = match ($category) {
129 CreativeCategory::CONSTRUCTION => CreativeContentPacket::CATEGORY_CONSTRUCTION,
130 CreativeCategory::NATURE => CreativeContentPacket::CATEGORY_NATURE,
131 CreativeCategory::EQUIPMENT => CreativeContentPacket::CATEGORY_EQUIPMENT,
132 CreativeCategory::ITEMS => CreativeContentPacket::CATEGORY_ITEMS
133 };
134 if($group === null){
135 $groupEntries[] = new CreativeGroupEntry($categoryId, "", ItemStack::null());
136 }else{
137 $groupIcon = $group->getIcon();
138 //TODO: HACK! In 1.21.60, Workaround glitchy behaviour when an item is used as an icon for a group it
139 //doesn't belong to. Without this hack, both instances of the item will show a +, but neither of them
140 //will actually expand the group work correctly.
141 $groupIcon->getNamedTag()->setInt("___GroupBugWorkaround___", $index);
142 $groupName = $group->getName();
143 $groupEntries[] = new CreativeGroupEntry(
144 $categoryId,
145 $translate($groupName),
146 $typeConverter->coreItemStackToNet($groupIcon)
147 );
148 }
149 }
150
151 return CreativeContentPacket::create($groupEntries, $cachedEntry->items);
152 }
153}
add(Item $item, CreativeCategory $category=CreativeCategory::ITEMS, ?CreativeGroup $group=null)
prepareClientTranslatableMessage(Translatable $message)