Skip to content

Commit 738a50d

Browse files
committed
[sync] Update embedded LibCustom from standalone
1 parent 9f35f47 commit 738a50d

81 files changed

Lines changed: 3175 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace imperazim\custom;
5+
6+
use imperazim\custom\block\CustomBlockFactory;
7+
use imperazim\custom\item\CustomItemFactory;
8+
use imperazim\custom\item\ItemComponentsHolder;
9+
use imperazim\custom\registry\ReflectionBridge;
10+
use imperazim\packet\handler\PacketHandler;
11+
use imperazim\packet\LibPacket;
12+
use pocketmine\block\inventory\ChestInventory;
13+
use pocketmine\block\inventory\DoubleChestInventory;
14+
use pocketmine\block\inventory\EnderChestInventory;
15+
use pocketmine\block\inventory\FurnaceInventory;
16+
use pocketmine\block\inventory\HopperInventory;
17+
use pocketmine\block\inventory\ShulkerBoxInventory;
18+
use pocketmine\block\ItemFrame;
19+
use pocketmine\event\EventPriority;
20+
use pocketmine\event\inventory\InventoryTransactionEvent;
21+
use pocketmine\event\Listener;
22+
use pocketmine\event\player\PlayerDropItemEvent;
23+
use pocketmine\event\player\PlayerInteractEvent;
24+
use pocketmine\inventory\PlayerInventory;
25+
use pocketmine\network\mcpe\NetworkSession;
26+
use pocketmine\network\mcpe\protocol\ItemRegistryPacket;
27+
use pocketmine\network\mcpe\protocol\ResourcePackStackPacket;
28+
use pocketmine\network\mcpe\protocol\StartGamePacket;
29+
use pocketmine\network\mcpe\protocol\types\BlockPaletteEntry;
30+
use pocketmine\network\mcpe\protocol\types\Experiments;
31+
use pocketmine\network\mcpe\protocol\types\ItemTypeEntry;
32+
use pocketmine\plugin\PluginBase;
33+
use pocketmine\Server;
34+
use function array_merge;
35+
use function count;
36+
37+
final class CustomManager implements Listener {
38+
39+
private static Experiments $experiments;
40+
41+
/** @var ItemTypeEntry[] */
42+
private static array $cachedItemTable = [];
43+
44+
/** @var BlockPaletteEntry[] */
45+
private static array $cachedBlockPalette = [];
46+
47+
public static function init(PluginBase $plugin): void {
48+
self::$experiments = new Experiments(['data_driven_items' => true], true);
49+
50+
$interceptor = LibPacket::createInterceptor($plugin, EventPriority::NORMAL);
51+
52+
$interceptor->registerOutgoing(new class extends PacketHandler {
53+
public function __construct() {
54+
parent::__construct([ItemRegistryPacket::class]);
55+
}
56+
57+
public function handle($packet, NetworkSession $session): bool {
58+
if ($packet instanceof ItemRegistryPacket) {
59+
if (CustomManager::$cachedItemTable === []) {
60+
CustomManager::$cachedItemTable = CustomItemFactory::getInstance()->getItemTableEntries();
61+
}
62+
if (count(CustomManager::$cachedItemTable) > 0) {
63+
ReflectionBridge::mergeItemRegistryEntries($packet, CustomManager::$cachedItemTable);
64+
}
65+
}
66+
return true;
67+
}
68+
});
69+
70+
$interceptor->registerOutgoing(new class extends PacketHandler {
71+
public function __construct() {
72+
parent::__construct([StartGamePacket::class]);
73+
}
74+
75+
public function handle($packet, NetworkSession $session): bool {
76+
if ($packet instanceof StartGamePacket) {
77+
if (CustomManager::$cachedBlockPalette === []) {
78+
CustomManager::$cachedBlockPalette = CustomBlockFactory::getInstance()->getBlockPaletteEntries();
79+
}
80+
$packet->levelSettings->experiments = CustomManager::$experiments;
81+
if (count(CustomManager::$cachedBlockPalette) > 0) {
82+
$packet->blockPalette = CustomManager::$cachedBlockPalette;
83+
}
84+
}
85+
return true;
86+
}
87+
});
88+
89+
$interceptor->registerOutgoing(new class extends PacketHandler {
90+
public function __construct() {
91+
parent::__construct([ResourcePackStackPacket::class]);
92+
}
93+
94+
public function handle($packet, NetworkSession $session): bool {
95+
if ($packet instanceof ResourcePackStackPacket) {
96+
$packet->experiments = CustomManager::$experiments;
97+
}
98+
return true;
99+
}
100+
});
101+
102+
Server::getInstance()->getPluginManager()->registerEvents(new self(), $plugin);
103+
}
104+
105+
public function onDrop(PlayerDropItemEvent $event): void {
106+
$item = $event->getItem();
107+
if ($item instanceof ItemComponentsHolder && $item->isLockedInInventory()) {
108+
$event->cancel();
109+
}
110+
}
111+
112+
public function onTouch(PlayerInteractEvent $event): void {
113+
$player = $event->getPlayer();
114+
$item = $player->getInventory()->getItemInHand();
115+
$block = $event->getBlock();
116+
if ($block instanceof ItemFrame && $item instanceof ItemComponentsHolder && $item->isLockedInInventory()) {
117+
$event->cancel();
118+
}
119+
}
120+
121+
public function onTransaction(InventoryTransactionEvent $event): void {
122+
$hasPlayer = false;
123+
$hasContainer = false;
124+
foreach ($event->getTransaction()->getInventories() as $inventory) {
125+
if ($inventory instanceof PlayerInventory) {
126+
$hasPlayer = true;
127+
}
128+
if ($inventory instanceof ChestInventory || $inventory instanceof DoubleChestInventory ||
129+
$inventory instanceof EnderChestInventory || $inventory instanceof FurnaceInventory ||
130+
$inventory instanceof ShulkerBoxInventory || $inventory instanceof HopperInventory) {
131+
$hasContainer = true;
132+
}
133+
}
134+
if ($hasPlayer && $hasContainer) {
135+
foreach ($event->getTransaction()->getActions() as $action) {
136+
$item = $action->getTargetItem();
137+
if ($item instanceof ItemComponentsHolder && $item->isLockedInInventory()) {
138+
$event->cancel();
139+
return;
140+
}
141+
}
142+
}
143+
}
144+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace imperazim\custom\block;
5+
6+
use pocketmine\nbt\tag\CompoundTag;
7+
8+
interface BlockComponent {
9+
10+
public function getName(): string;
11+
12+
public function toNbt(): CompoundTag;
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace imperazim\custom\block;
5+
6+
interface BlockComponentsHolder {
7+
8+
/** @return BlockComponent[] */
9+
public function getBlockComponents(): array;
10+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace imperazim\custom\block;
5+
6+
use imperazim\custom\registry\ReflectionBridge;
7+
use pocketmine\data\bedrock\block\BlockStateData;
8+
use pocketmine\data\bedrock\block\BlockTypeNames;
9+
use pocketmine\nbt\tag\CompoundTag;
10+
use pocketmine\network\mcpe\convert\BlockStateDictionaryEntry;
11+
use pocketmine\utils\AssumptionFailedError;
12+
use pocketmine\utils\SingletonTrait;
13+
use RuntimeException;
14+
use function array_keys;
15+
use function count;
16+
use function hash;
17+
use function strcmp;
18+
use function usort;
19+
20+
final class BlockPaletteManager {
21+
use SingletonTrait;
22+
23+
/** @var BlockStateDictionaryEntry[] */
24+
private array $states;
25+
26+
/** @var BlockStateDictionaryEntry[] */
27+
private array $customStates = [];
28+
29+
public function __construct() {
30+
$this->states = ReflectionBridge::getBlockStates();
31+
}
32+
33+
/**
34+
* @return BlockStateDictionaryEntry[]
35+
*/
36+
public function getStates(): array {
37+
return $this->states;
38+
}
39+
40+
/**
41+
* @return BlockStateDictionaryEntry[]
42+
*/
43+
public function getCustomStates(): array {
44+
return $this->customStates;
45+
}
46+
47+
/**
48+
* Inserts the provided state into the correct position of the palette.
49+
*/
50+
public function insertState(CompoundTag $state, int $meta = 0): void {
51+
if (($name = $state->getString(BlockStateData::TAG_NAME, '')) === '') {
52+
throw new RuntimeException("Block state must contain a StringTag called 'name'");
53+
}
54+
if (($properties = $state->getCompoundTag(BlockStateData::TAG_STATES)) === null) {
55+
throw new RuntimeException("Block state must contain a CompoundTag called 'states'");
56+
}
57+
$entry = new BlockStateDictionaryEntry($name, $properties->getValue(), $meta);
58+
$this->sortWith($entry);
59+
$this->customStates[] = $entry;
60+
}
61+
62+
/**
63+
* Sorts the palette's block states in the correct order, also adding the provided state to the array.
64+
*/
65+
private function sortWith(BlockStateDictionaryEntry $newState): void {
66+
// Split the palette into groups of states by block name, preserving existing order.
67+
$states = [];
68+
foreach ($this->getStates() as $state) {
69+
$states[$state->getStateName()][] = $state;
70+
}
71+
// Append the new state at the end to preserve existing order.
72+
$states[$newState->getStateName()][] = $newState;
73+
74+
$names = array_keys($states);
75+
// As of 1.18.30, blocks are sorted using a fnv164 hash of their names.
76+
usort($names, static fn(string $a, string $b) => strcmp(hash('fnv164', $a), hash('fnv164', $b)));
77+
78+
$sortedStates = [];
79+
$stateId = 0;
80+
$stateDataToStateIdLookup = [];
81+
foreach ($names as $name) {
82+
foreach ($states[$name] as $state) {
83+
$sortedStates[$stateId] = $state;
84+
if (count($states[$name]) === 1) {
85+
$stateDataToStateIdLookup[$name] = $stateId;
86+
} else {
87+
$stateDataToStateIdLookup[$name][$state->getRawStateProperties()] = $stateId;
88+
}
89+
$stateId++;
90+
}
91+
}
92+
93+
$this->states = $sortedStates;
94+
ReflectionBridge::applyBlockPalette($sortedStates, $stateDataToStateIdLookup);
95+
}
96+
}

0 commit comments

Comments
 (0)