Skip to content

Commit 35eae86

Browse files
committed
[sync] Update embedded LibEnchantment from standalone
1 parent 738a50d commit 35eae86

21 files changed

Lines changed: 1759 additions & 0 deletions
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace imperazim\enchantment;
6+
7+
use pocketmine\item\enchantment\Enchantment;
8+
use pocketmine\item\enchantment\ItemFlags;
9+
use pocketmine\item\enchantment\Rarity;
10+
use pocketmine\player\Player;
11+
12+
/**
13+
* Base class for all custom enchantments.
14+
*/
15+
class CustomEnchantment extends Enchantment {
16+
17+
// Usage type constants
18+
public const USAGE_HAND = 0;
19+
public const USAGE_ANY_INVENTORY = 1;
20+
public const USAGE_INVENTORY = 2;
21+
public const USAGE_ARMOR = 3;
22+
public const USAGE_HELMET = 4;
23+
public const USAGE_CHESTPLATE = 5;
24+
public const USAGE_LEGGINGS = 6;
25+
public const USAGE_BOOTS = 7;
26+
27+
// Item type constants
28+
public const ITEM_GLOBAL = 0;
29+
public const ITEM_SWORD = 1;
30+
public const ITEM_BOW = 2;
31+
public const ITEM_TOOL = 3;
32+
public const ITEM_SHEARS = 4;
33+
public const ITEM_FLINT_AND_STEEL = 5;
34+
public const ITEM_PICKAXE = 6;
35+
public const ITEM_AXE = 7;
36+
public const ITEM_HOE = 8;
37+
public const ITEM_SHOVEL = 9;
38+
public const ITEM_HELMET = 10;
39+
public const ITEM_CHESTPLATE = 11;
40+
public const ITEM_LEGGINGS = 12;
41+
public const ITEM_BOOTS = 13;
42+
public const ITEM_COMPASS = 14;
43+
public const ITEM_ELYTRA = 15;
44+
45+
public string $name = '';
46+
public int $rarity = Rarity::RARE;
47+
public int $maxLevel = 1;
48+
public string $displayName = '';
49+
public string $description = '';
50+
public int $cooldownDuration = 0;
51+
public int $chance = 100;
52+
public int $usageType = self::USAGE_HAND;
53+
public int $itemType = self::ITEM_GLOBAL;
54+
public array $extraData = [];
55+
56+
/** @var array<string, int> playerUUID => expiry timestamp */
57+
protected array $cooldown = [];
58+
59+
public function __construct(int $rarity = Rarity::RARE, int $primaryFlag = ItemFlags::ALL, int $secondaryFlag = ItemFlags::ALL) {
60+
$this->rarity = $rarity;
61+
$this->extraData = $this->getDefaultExtraData();
62+
parent::__construct($this->name, $this->rarity, $primaryFlag, $secondaryFlag, $this->maxLevel);
63+
}
64+
65+
public function getDisplayName(): string {
66+
return $this->displayName !== '' ? $this->displayName : $this->name;
67+
}
68+
69+
public function getDescription(): string {
70+
return $this->description;
71+
}
72+
73+
public function getUsageType(): int {
74+
return $this->usageType;
75+
}
76+
77+
public function getItemType(): int {
78+
return $this->itemType;
79+
}
80+
81+
public function getPriority(): int {
82+
return 1;
83+
}
84+
85+
public function canReact(): bool {
86+
return false;
87+
}
88+
89+
public function canTick(): bool {
90+
return false;
91+
}
92+
93+
public function canToggle(): bool {
94+
return false;
95+
}
96+
97+
public function getCooldown(Player $player): int {
98+
$uuid = $player->getUniqueId()->toString();
99+
return ($this->cooldown[$uuid] ?? time()) - time();
100+
}
101+
102+
public function setCooldown(Player $player, int $cooldown): void {
103+
$uuid = $player->getUniqueId()->toString();
104+
$this->cooldown[$uuid] = time() + $cooldown;
105+
}
106+
107+
public function clearCooldown(Player $player): void {
108+
$uuid = $player->getUniqueId()->toString();
109+
unset($this->cooldown[$uuid]);
110+
}
111+
112+
public function getDefaultExtraData(): array {
113+
return [];
114+
}
115+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace imperazim\enchantment;
6+
7+
use ReflectionClass;
8+
use ReflectionProperty;
9+
use pocketmine\data\bedrock\EnchantmentIdMap;
10+
use pocketmine\item\enchantment\StringToEnchantmentParser;
11+
use pocketmine\utils\StringToTParser;
12+
13+
/**
14+
* Static facade for registering and managing custom enchantments.
15+
*/
16+
final class EnchantmentFactory {
17+
18+
/** @var array<int, CustomEnchantment> id => enchantment */
19+
private static array $enchants = [];
20+
21+
/**
22+
* Register a custom enchantment with the given numeric ID.
23+
*/
24+
public static function register(int $id, CustomEnchantment $enchant): void {
25+
EnchantmentIdMap::getInstance()->register($id, $enchant);
26+
self::$enchants[$id] = $enchant;
27+
28+
$parser = StringToEnchantmentParser::getInstance();
29+
$parser->register($enchant->name, fn() => $enchant);
30+
$displayName = $enchant->getDisplayName();
31+
if ($displayName !== '' && $displayName !== $enchant->name) {
32+
$parser->register($displayName, fn() => $enchant);
33+
}
34+
}
35+
36+
/**
37+
* Unregister a custom enchantment by ID or instance.
38+
*/
39+
public static function unregister(int|CustomEnchantment $target): void {
40+
if ($target instanceof CustomEnchantment) {
41+
$id = array_search($target, self::$enchants, true);
42+
if ($id === false) {
43+
return;
44+
}
45+
} else {
46+
$id = $target;
47+
}
48+
49+
if (!isset(self::$enchants[$id])) {
50+
return;
51+
}
52+
53+
$enchant = self::$enchants[$id];
54+
55+
// Unregister from StringToEnchantmentParser
56+
self::unregisterName($enchant);
57+
58+
// Unregister from EnchantmentIdMap
59+
self::unregisterId($id);
60+
61+
unset(self::$enchants[$id]);
62+
}
63+
64+
/**
65+
* Get a custom enchantment by its numeric ID.
66+
*/
67+
public static function get(int $id): ?CustomEnchantment {
68+
return self::$enchants[$id] ?? null;
69+
}
70+
71+
/**
72+
* Get a custom enchantment by its name.
73+
*/
74+
public static function getByName(string $name): ?CustomEnchantment {
75+
$result = StringToEnchantmentParser::getInstance()->parse($name);
76+
return $result instanceof CustomEnchantment ? $result : null;
77+
}
78+
79+
/**
80+
* Get all registered custom enchantments.
81+
* @return array<int, CustomEnchantment>
82+
*/
83+
public static function getAll(): array {
84+
return self::$enchants;
85+
}
86+
87+
/**
88+
* Remove enchantment names from StringToEnchantmentParser via reflection.
89+
*/
90+
private static function unregisterName(CustomEnchantment $enchant): void {
91+
$parser = StringToEnchantmentParser::getInstance();
92+
$callbackMap = self::getPrivateProperty($parser, 'callbackMap');
93+
94+
$normalize = fn(string $s): string => strtolower(str_replace([' ', 'minecraft:'], ['_', ''], trim($s)));
95+
96+
unset($callbackMap[$normalize($enchant->name)]);
97+
$displayName = $enchant->getDisplayName();
98+
if ($displayName !== '' && $displayName !== $enchant->name) {
99+
unset($callbackMap[$normalize($displayName)]);
100+
}
101+
102+
self::setPrivateProperty($parser, 'callbackMap', $callbackMap);
103+
}
104+
105+
/**
106+
* Remove enchantment ID mapping from EnchantmentIdMap via reflection.
107+
*/
108+
private static function unregisterId(int $id): void {
109+
$idMap = EnchantmentIdMap::getInstance();
110+
111+
$enchant = $idMap->fromId($id);
112+
if ($enchant !== null) {
113+
$enumToId = self::getPrivateProperty($idMap, 'enumToId');
114+
unset($enumToId[spl_object_id($enchant)]);
115+
self::setPrivateProperty($idMap, 'enumToId', $enumToId);
116+
}
117+
118+
$idToEnum = self::getPrivateProperty($idMap, 'idToEnum');
119+
unset($idToEnum[$id]);
120+
self::setPrivateProperty($idMap, 'idToEnum', $idToEnum);
121+
}
122+
123+
private static function getPrivateProperty(object $object, string $property): mixed {
124+
$reflection = new ReflectionProperty($object, $property);
125+
$reflection->setAccessible(true);
126+
return $reflection->getValue($object);
127+
}
128+
129+
private static function setPrivateProperty(object $object, string $property, mixed $value): void {
130+
$reflection = new ReflectionProperty($object, $property);
131+
$reflection->setAccessible(true);
132+
$reflection->setValue($object, $value);
133+
}
134+
}

0 commit comments

Comments
 (0)