mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-15 02:09:42 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
commit
8c594fd126
@ -1 +1 @@
|
||||
Subproject commit ed0bc4d2afafd00f9ee92823c6b1bd66789ce4f2
|
||||
Subproject commit a053f65e1897e432478229071383fe1ba16032c3
|
39
composer.lock
generated
39
composer.lock
generated
@ -1211,16 +1211,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.16.0",
|
||||
"version": "v4.17.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "19526a33fb561ef417e822e85f08a00db4059c17"
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17",
|
||||
"reference": "19526a33fb561ef417e822e85f08a00db4059c17",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1261,9 +1261,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
|
||||
},
|
||||
"time": "2023-06-25T14:52:30+00:00"
|
||||
"time": "2023-08-13T19:53:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -1861,16 +1861,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.3.1",
|
||||
"version": "10.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "d442ce7c4104d5683c12e67e4dcb5058159e9804"
|
||||
"reference": "0dafb1175c366dd274eaa9a625e914451506bcd1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d442ce7c4104d5683c12e67e4dcb5058159e9804",
|
||||
"reference": "d442ce7c4104d5683c12e67e4dcb5058159e9804",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0dafb1175c366dd274eaa9a625e914451506bcd1",
|
||||
"reference": "0dafb1175c366dd274eaa9a625e914451506bcd1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1942,7 +1942,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.1"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1958,7 +1958,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-04T06:48:08+00:00"
|
||||
"time": "2023-08-15T05:34:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -2129,16 +2129,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "5.0.0",
|
||||
"version": "5.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "72f01e6586e0caf6af81297897bd112eb7e9627c"
|
||||
"reference": "2db5010a484d53ebf536087a70b4a5423c102372"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/72f01e6586e0caf6af81297897bd112eb7e9627c",
|
||||
"reference": "72f01e6586e0caf6af81297897bd112eb7e9627c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
|
||||
"reference": "2db5010a484d53ebf536087a70b4a5423c102372",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2149,7 +2149,7 @@
|
||||
"sebastian/exporter": "^5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.0"
|
||||
"phpunit/phpunit": "^10.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -2193,7 +2193,8 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.0"
|
||||
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2201,7 +2202,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-03T07:07:16+00:00"
|
||||
"time": "2023-08-14T13:18:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
|
@ -36,6 +36,9 @@ use pocketmine\data\runtime\RuntimeDataSizeCalculator;
|
||||
use pocketmine\data\runtime\RuntimeDataWriter;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\item\enchantment\AvailableEnchantmentRegistry;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTagRegistry;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemBlock;
|
||||
@ -422,6 +425,19 @@ class Block{
|
||||
return $this->typeInfo->getBreakInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tags that represent the type of item being enchanted and are used to determine
|
||||
* what enchantments can be applied to the item of this block during in-game enchanting (enchanting table, anvil, fishing, etc.).
|
||||
* @see ItemEnchantmentTags
|
||||
* @see ItemEnchantmentTagRegistry
|
||||
* @see AvailableEnchantmentRegistry
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getEnchantmentTags() : array{
|
||||
return $this->typeInfo->getEnchantmentTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actions needed so the block is broken with the Item
|
||||
*
|
||||
|
@ -35,10 +35,12 @@ final class BlockTypeInfo{
|
||||
|
||||
/**
|
||||
* @param string[] $typeTags
|
||||
* @param string[] $enchantmentTags
|
||||
*/
|
||||
public function __construct(
|
||||
private BlockBreakInfo $breakInfo,
|
||||
array $typeTags = []
|
||||
array $typeTags = [],
|
||||
private array $enchantmentTags = []
|
||||
){
|
||||
$this->typeTags = array_fill_keys($typeTags, true);
|
||||
}
|
||||
@ -49,4 +51,17 @@ final class BlockTypeInfo{
|
||||
public function getTypeTags() : array{ return array_keys($this->typeTags); }
|
||||
|
||||
public function hasTypeTag(string $tag) : bool{ return isset($this->typeTags[$tag]); }
|
||||
|
||||
/**
|
||||
* Returns tags that represent the type of item being enchanted and are used to determine
|
||||
* what enchantments can be applied to the item of this block during in-game enchanting (enchanting table, anvil, fishing, etc.).
|
||||
* @see ItemEnchantmentTags
|
||||
* @see ItemEnchantmentTagRegistry
|
||||
* @see AvailableEnchantmentRegistry
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getEnchantmentTags() : array{
|
||||
return $this->enchantmentTags;
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,10 @@ class Cake extends BaseCake{
|
||||
return parent::onInteract($item, $face, $clickVector, $player, $returnedItems);
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getResidue() : Block{
|
||||
$clone = clone $this;
|
||||
$clone->bites++;
|
||||
|
@ -63,6 +63,14 @@ final class PotionCauldron extends FillableCauldron{
|
||||
|
||||
/** @return $this */
|
||||
public function setPotionItem(?Item $potionItem) : self{
|
||||
if($potionItem !== null && !match($potionItem->getTypeId()){
|
||||
ItemTypeIds::POTION,
|
||||
ItemTypeIds::SPLASH_POTION,
|
||||
ItemTypeIds::LINGERING_POTION => true,
|
||||
default => false,
|
||||
}){
|
||||
throw new \InvalidArgumentException("Item must be a POTION, SPLASH_POTION or LINGERING_POTION");
|
||||
}
|
||||
$this->potionItem = $potionItem !== null ? (clone $potionItem)->setCount(1) : null;
|
||||
return $this;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ use pocketmine\block\utils\SaplingType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags as EnchantmentTags;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ToolTier;
|
||||
use pocketmine\math\Facing;
|
||||
@ -966,7 +967,7 @@ final class VanillaBlocks{
|
||||
|
||||
$pumpkinBreakInfo = new Info(BreakInfo::axe(1.0));
|
||||
self::register("pumpkin", new Pumpkin(new BID(Ids::PUMPKIN), "Pumpkin", $pumpkinBreakInfo));
|
||||
self::register("carved_pumpkin", new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN), "Carved Pumpkin", $pumpkinBreakInfo));
|
||||
self::register("carved_pumpkin", new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN), "Carved Pumpkin", new Info(BreakInfo::axe(1.0), enchantmentTags: [EnchantmentTags::MASK])));
|
||||
self::register("lit_pumpkin", new LitPumpkin(new BID(Ids::LIT_PUMPKIN), "Jack o'Lantern", $pumpkinBreakInfo));
|
||||
|
||||
self::register("pumpkin_stem", new PumpkinStem(new BID(Ids::PUMPKIN_STEM), "Pumpkin Stem", new Info(BreakInfo::instant())));
|
||||
@ -1002,7 +1003,7 @@ final class VanillaBlocks{
|
||||
|
||||
self::register("sea_lantern", new SeaLantern(new BID(Ids::SEA_LANTERN), "Sea Lantern", new Info(new BreakInfo(0.3))));
|
||||
self::register("sea_pickle", new SeaPickle(new BID(Ids::SEA_PICKLE), "Sea Pickle", new Info(BreakInfo::instant())));
|
||||
self::register("mob_head", new MobHead(new BID(Ids::MOB_HEAD, TileMobHead::class), "Mob Head", new Info(new BreakInfo(1.0))));
|
||||
self::register("mob_head", new MobHead(new BID(Ids::MOB_HEAD, TileMobHead::class), "Mob Head", new Info(new BreakInfo(1.0), enchantmentTags: [EnchantmentTags::MASK])));
|
||||
self::register("slime", new Slime(new BID(Ids::SLIME), "Slime Block", new Info(BreakInfo::instant())));
|
||||
self::register("snow", new Snow(new BID(Ids::SNOW), "Snow Block", new Info(BreakInfo::shovel(0.2, ToolTier::WOOD()))));
|
||||
self::register("snow_layer", new SnowLayer(new BID(Ids::SNOW_LAYER), "Snow Layer", new Info(BreakInfo::shovel(0.1, ToolTier::WOOD()))));
|
||||
|
@ -23,9 +23,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\event\player\PlayerEnchantOptionsRequestEvent;
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\item\enchantment\EnchantmentHelper as Helper;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\world\Position;
|
||||
use function array_values;
|
||||
use function count;
|
||||
|
||||
class EnchantInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
|
||||
use BlockInventoryTrait;
|
||||
@ -33,8 +39,47 @@ class EnchantInventory extends SimpleInventory implements BlockInventory, Tempor
|
||||
public const SLOT_INPUT = 0;
|
||||
public const SLOT_LAPIS = 1;
|
||||
|
||||
/** @var EnchantOption[] $options */
|
||||
private array $options = [];
|
||||
|
||||
public function __construct(Position $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(2);
|
||||
}
|
||||
|
||||
protected function onSlotChange(int $index, Item $before) : void{
|
||||
if($index === self::SLOT_INPUT){
|
||||
foreach($this->viewers as $viewer){
|
||||
$this->options = [];
|
||||
$item = $this->getInput();
|
||||
$options = Helper::getEnchantOptions($this->holder, $item, $viewer->getEnchantmentSeed());
|
||||
|
||||
$event = new PlayerEnchantOptionsRequestEvent($viewer, $this, $options);
|
||||
$event->call();
|
||||
if(!$event->isCancelled() && count($event->getOptions()) > 0){
|
||||
$this->options = array_values($event->getOptions());
|
||||
$viewer->getNetworkSession()->getInvManager()?->syncEnchantingTableOptions($this->options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::onSlotChange($index, $before);
|
||||
}
|
||||
|
||||
public function getInput() : Item{
|
||||
return $this->getItem(self::SLOT_INPUT);
|
||||
}
|
||||
|
||||
public function getLapis() : Item{
|
||||
return $this->getItem(self::SLOT_LAPIS);
|
||||
}
|
||||
|
||||
public function getOutput(int $optionId) : ?Item{
|
||||
$option = $this->getOption($optionId);
|
||||
return $option === null ? null : Helper::enchantItem($this->getInput(), $option->getEnchantments());
|
||||
}
|
||||
|
||||
public function getOption(int $optionId) : ?EnchantOption{
|
||||
return $this->options[$optionId] ?? null;
|
||||
}
|
||||
}
|
||||
|
@ -223,6 +223,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::ECHO_SHARD, Items::ECHO_SHARD());
|
||||
$this->map1to1Item(Ids::EGG, Items::EGG());
|
||||
$this->map1to1Item(Ids::EMERALD, Items::EMERALD());
|
||||
$this->map1to1Item(Ids::ENCHANTED_BOOK, Items::ENCHANTED_BOOK());
|
||||
$this->map1to1Item(Ids::ENCHANTED_GOLDEN_APPLE, Items::ENCHANTED_GOLDEN_APPLE());
|
||||
$this->map1to1Item(Ids::ENDER_PEARL, Items::ENDER_PEARL());
|
||||
$this->map1to1Item(Ids::EXPERIENCE_BOTTLE, Items::EXPERIENCE_BOTTLE());
|
||||
|
@ -76,7 +76,7 @@ use function array_key_exists;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function min;
|
||||
use function random_int;
|
||||
use function mt_rand;
|
||||
|
||||
class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
|
||||
@ -211,6 +211,18 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
return $this->xpManager;
|
||||
}
|
||||
|
||||
public function getEnchantmentSeed() : int{
|
||||
return $this->xpSeed;
|
||||
}
|
||||
|
||||
public function setEnchantmentSeed(int $seed) : void{
|
||||
$this->xpSeed = $seed;
|
||||
}
|
||||
|
||||
public function generateEnchantmentSeed() : int{
|
||||
return mt_rand(Limits::INT32_MIN, Limits::INT32_MAX);
|
||||
}
|
||||
|
||||
public function getXpDropAmount() : int{
|
||||
//this causes some XP to be lost on death when above level 1 (by design), dropping at most enough points for
|
||||
//about 7.5 levels of XP.
|
||||
@ -334,7 +346,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
if(($xpSeedTag = $nbt->getTag(self::TAG_XP_SEED)) instanceof IntTag){
|
||||
$this->xpSeed = $xpSeedTag->getValue();
|
||||
}else{
|
||||
$this->xpSeed = random_int(Limits::INT32_MIN, Limits::INT32_MAX);
|
||||
$this->xpSeed = $this->generateEnchantmentSeed();
|
||||
}
|
||||
}
|
||||
|
||||
|
75
src/event/player/PlayerEnchantOptionsRequestEvent.php
Normal file
75
src/event/player/PlayerEnchantOptionsRequestEvent.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?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\event\player;
|
||||
|
||||
use pocketmine\block\inventory\EnchantInventory;
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\event\Event;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Called when a player inserts an item into an enchanting table's input slot.
|
||||
* The options provided by the event will be shown on the enchanting table menu.
|
||||
*/
|
||||
class PlayerEnchantOptionsRequestEvent extends PlayerEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
/**
|
||||
* @param EnchantOption[] $options
|
||||
*/
|
||||
public function __construct(
|
||||
Player $player,
|
||||
private readonly EnchantInventory $enchantInventory,
|
||||
private array $options
|
||||
){
|
||||
$this->player = $player;
|
||||
}
|
||||
|
||||
public function getEnchantInventory() : EnchantInventory{
|
||||
return $this->enchantInventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EnchantOption[]
|
||||
*/
|
||||
public function getOptions() : array{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EnchantOption[] $options
|
||||
*/
|
||||
public function setOptions(array $options) : void{
|
||||
Utils::validateArrayValueType($options, function(EnchantOption $_) : void{ });
|
||||
if(($optionCount = count($options)) > 3){
|
||||
throw new \LogicException("The maximum number of options for an enchanting table is 3, but $optionCount have been passed");
|
||||
}
|
||||
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
85
src/event/player/PlayerItemEnchantEvent.php
Normal file
85
src/event/player/PlayerItemEnchantEvent.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?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\event\player;
|
||||
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\inventory\transaction\EnchantTransaction;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
/**
|
||||
* Called when a player enchants an item using an enchanting table.
|
||||
*/
|
||||
class PlayerItemEnchantEvent extends PlayerEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
public function __construct(
|
||||
Player $player,
|
||||
private readonly EnchantTransaction $transaction,
|
||||
private readonly EnchantOption $option,
|
||||
private readonly Item $inputItem,
|
||||
private readonly Item $outputItem,
|
||||
private readonly int $cost
|
||||
){
|
||||
$this->player = $player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inventory transaction involved in this enchant event.
|
||||
*/
|
||||
public function getTransaction() : EnchantTransaction{
|
||||
return $this->transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enchantment option used.
|
||||
*/
|
||||
public function getOption() : EnchantOption{
|
||||
return $this->option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item to be enchanted.
|
||||
*/
|
||||
public function getInputItem() : Item{
|
||||
return clone $this->inputItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enchanted item.
|
||||
*/
|
||||
public function getOutputItem() : Item{
|
||||
return clone $this->outputItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of XP levels and lapis that will be subtracted after enchanting
|
||||
* if the player is not in creative mode.
|
||||
*/
|
||||
public function getCost() : int{
|
||||
return $this->cost;
|
||||
}
|
||||
}
|
132
src/inventory/transaction/EnchantTransaction.php
Normal file
132
src/inventory/transaction/EnchantTransaction.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?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\inventory\transaction;
|
||||
|
||||
use pocketmine\event\player\PlayerItemEnchantEvent;
|
||||
use pocketmine\item\enchantment\EnchantmentHelper;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use function count;
|
||||
|
||||
class EnchantTransaction extends InventoryTransaction{
|
||||
|
||||
private ?Item $inputItem = null;
|
||||
private ?Item $outputItem = null;
|
||||
|
||||
public function __construct(
|
||||
Player $source,
|
||||
private readonly EnchantOption $option,
|
||||
private readonly int $cost
|
||||
){
|
||||
parent::__construct($source);
|
||||
}
|
||||
|
||||
private function validateOutput() : void{
|
||||
if($this->inputItem === null || $this->outputItem === null){
|
||||
throw new AssumptionFailedError("Expected that inputItem and outputItem are not null before validating output");
|
||||
}
|
||||
|
||||
$enchantedInput = EnchantmentHelper::enchantItem($this->inputItem, $this->option->getEnchantments());
|
||||
if(!$this->outputItem->equalsExact($enchantedInput)){
|
||||
throw new TransactionValidationException("Invalid output item");
|
||||
}
|
||||
}
|
||||
|
||||
private function validateFiniteResources(int $lapisSpent) : void{
|
||||
if($lapisSpent !== $this->cost){
|
||||
throw new TransactionValidationException("Expected the amount of lapis lazuli spent to be $this->cost, but received $lapisSpent");
|
||||
}
|
||||
|
||||
$xpLevel = $this->source->getXpManager()->getXpLevel();
|
||||
$requiredXpLevel = $this->option->getRequiredXpLevel();
|
||||
|
||||
if($xpLevel < $requiredXpLevel){
|
||||
throw new TransactionValidationException("Player's XP level $xpLevel is less than the required XP level $requiredXpLevel");
|
||||
}
|
||||
if($xpLevel < $this->cost){
|
||||
throw new TransactionValidationException("Player's XP level $xpLevel is less than the XP level cost $this->cost");
|
||||
}
|
||||
}
|
||||
|
||||
public function validate() : void{
|
||||
if(count($this->actions) < 1){
|
||||
throw new TransactionValidationException("Transaction must have at least one action to be executable");
|
||||
}
|
||||
|
||||
/** @var Item[] $inputs */
|
||||
$inputs = [];
|
||||
/** @var Item[] $outputs */
|
||||
$outputs = [];
|
||||
$this->matchItems($outputs, $inputs);
|
||||
|
||||
$lapisSpent = 0;
|
||||
foreach($inputs as $input){
|
||||
if($input->getTypeId() === ItemTypeIds::LAPIS_LAZULI){
|
||||
$lapisSpent = $input->getCount();
|
||||
}else{
|
||||
if($this->inputItem !== null){
|
||||
throw new TransactionValidationException("Received more than 1 items to enchant");
|
||||
}
|
||||
$this->inputItem = $input;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->inputItem === null){
|
||||
throw new TransactionValidationException("No item to enchant received");
|
||||
}
|
||||
|
||||
if(($outputCount = count($outputs)) !== 1){
|
||||
throw new TransactionValidationException("Expected 1 output item, but received $outputCount");
|
||||
}
|
||||
$this->outputItem = $outputs[0];
|
||||
|
||||
$this->validateOutput();
|
||||
|
||||
if($this->source->hasFiniteResources()){
|
||||
$this->validateFiniteResources($lapisSpent);
|
||||
}
|
||||
}
|
||||
|
||||
public function execute() : void{
|
||||
parent::execute();
|
||||
|
||||
if($this->source->hasFiniteResources()){
|
||||
$this->source->getXpManager()->subtractXpLevels($this->cost);
|
||||
}
|
||||
$this->source->setEnchantmentSeed($this->source->generateEnchantmentSeed());
|
||||
}
|
||||
|
||||
protected function callExecuteEvent() : bool{
|
||||
if($this->inputItem === null || $this->outputItem === null){
|
||||
throw new AssumptionFailedError("Expected that inputItem and outputItem are not null before executing the event");
|
||||
}
|
||||
|
||||
$event = new PlayerItemEnchantEvent($this->source, $this, $this->option, $this->inputItem, $this->outputItem, $this->cost);
|
||||
$event->call();
|
||||
return !$event->isCancelled();
|
||||
}
|
||||
}
|
@ -44,8 +44,11 @@ class Armor extends Durable{
|
||||
|
||||
protected ?Color $customColor = null;
|
||||
|
||||
public function __construct(ItemIdentifier $identifier, string $name, ArmorTypeInfo $info){
|
||||
parent::__construct($identifier, $name);
|
||||
/**
|
||||
* @param string[] $enchantmentTags
|
||||
*/
|
||||
public function __construct(ItemIdentifier $identifier, string $name, ArmorTypeInfo $info, array $enchantmentTags = []){
|
||||
parent::__construct($identifier, $name, $enchantmentTags);
|
||||
$this->armorInfo = $info;
|
||||
}
|
||||
|
||||
@ -72,6 +75,14 @@ class Armor extends Durable{
|
||||
return $this->armorInfo->isFireProof();
|
||||
}
|
||||
|
||||
public function getMaterial() : ArmorMaterial{
|
||||
return $this->armorInfo->getMaterial();
|
||||
}
|
||||
|
||||
public function getEnchantability() : int{
|
||||
return $this->armorInfo->getMaterial()->getEnchantability();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dyed colour of this armour piece. This generally only applies to leather armour.
|
||||
*/
|
||||
|
42
src/item/ArmorMaterial.php
Normal file
42
src/item/ArmorMaterial.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?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\item;
|
||||
|
||||
class ArmorMaterial{
|
||||
|
||||
public function __construct(
|
||||
private readonly int $enchantability
|
||||
){
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that defines how enchantable the item is.
|
||||
*
|
||||
* The higher an item's enchantability is, the more likely it will be to gain high-level enchantments
|
||||
* or multiple enchantments upon being enchanted in an enchanting table.
|
||||
*/
|
||||
public function getEnchantability() : int{
|
||||
return $this->enchantability;
|
||||
}
|
||||
}
|
@ -24,13 +24,18 @@ declare(strict_types=1);
|
||||
namespace pocketmine\item;
|
||||
|
||||
class ArmorTypeInfo{
|
||||
private ArmorMaterial $material;
|
||||
|
||||
public function __construct(
|
||||
private int $defensePoints,
|
||||
private int $maxDurability,
|
||||
private int $armorSlot,
|
||||
private int $toughness = 0,
|
||||
private bool $fireProof = false
|
||||
){}
|
||||
private bool $fireProof = false,
|
||||
?ArmorMaterial $material = null
|
||||
){
|
||||
$this->material = $material ?? VanillaArmorMaterials::LEATHER();
|
||||
}
|
||||
|
||||
public function getDefensePoints() : int{
|
||||
return $this->defensePoints;
|
||||
@ -51,4 +56,8 @@ class ArmorTypeInfo{
|
||||
public function isFireProof() : bool{
|
||||
return $this->fireProof;
|
||||
}
|
||||
|
||||
public function getMaterial() : ArmorMaterial{
|
||||
return $this->material;
|
||||
}
|
||||
}
|
||||
|
@ -56,15 +56,17 @@ class ChorusFruit extends Food{
|
||||
$maxY = $minY + 16;
|
||||
$maxZ = $minZ + 16;
|
||||
|
||||
$worldMinY = $world->getMinY();
|
||||
|
||||
for($attempts = 0; $attempts < 16; ++$attempts){
|
||||
$x = mt_rand($minX, $maxX);
|
||||
$y = mt_rand($minY, $maxY);
|
||||
$z = mt_rand($minZ, $maxZ);
|
||||
|
||||
while($y >= 0 && !$world->getBlockAt($x, $y, $z)->isSolid()){
|
||||
while($y >= $worldMinY && !$world->getBlockAt($x, $y, $z)->isSolid()){
|
||||
$y--;
|
||||
}
|
||||
if($y < 0){
|
||||
if($y < $worldMinY){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
30
src/item/EnchantedBook.php
Normal file
30
src/item/EnchantedBook.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?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\item;
|
||||
|
||||
class EnchantedBook extends Item{
|
||||
public function getMaxStackSize() : int{
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -107,10 +107,13 @@ class Item implements \JsonSerializable{
|
||||
* NOTE: This should NOT BE USED for creating items to set into an inventory. Use VanillaItems for that
|
||||
* purpose.
|
||||
* @see VanillaItems
|
||||
*
|
||||
* @param string[] $enchantmentTags
|
||||
*/
|
||||
public function __construct(
|
||||
private ItemIdentifier $identifier,
|
||||
protected string $name = "Unknown"
|
||||
protected string $name = "Unknown",
|
||||
private array $enchantmentTags = []
|
||||
){
|
||||
$this->nbt = new CompoundTag();
|
||||
}
|
||||
@ -455,6 +458,29 @@ class Item implements \JsonSerializable{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tags that represent the type of item being enchanted and are used to determine
|
||||
* what enchantments can be applied to this item during in-game enchanting (enchanting table, anvil, fishing, etc.).
|
||||
* @see ItemEnchantmentTags
|
||||
* @see ItemEnchantmentTagRegistry
|
||||
* @see AvailableEnchantmentRegistry
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getEnchantmentTags() : array{
|
||||
return $this->enchantmentTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that defines how enchantable the item is.
|
||||
*
|
||||
* The higher an item's enchantability is, the more likely it will be to gain high-level enchantments
|
||||
* or multiple enchantments upon being enchanted in an enchanting table.
|
||||
*/
|
||||
public function getEnchantability() : int{
|
||||
return 1;
|
||||
}
|
||||
|
||||
final public function canBePlaced() : bool{
|
||||
return $this->getBlock()->canBePlaced();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ final class ItemBlock extends Item{
|
||||
public function __construct(
|
||||
private Block $block
|
||||
){
|
||||
parent::__construct(ItemIdentifier::fromBlock($block), $block->getName());
|
||||
parent::__construct(ItemIdentifier::fromBlock($block), $block->getName(), $block->getEnchantmentTags());
|
||||
}
|
||||
|
||||
protected function describeState(RuntimeDataDescriber $w) : void{
|
||||
|
@ -303,8 +303,9 @@ final class ItemTypeIds{
|
||||
public const MANGROVE_BOAT = 20264;
|
||||
public const GLOW_BERRIES = 20265;
|
||||
public const CHERRY_SIGN = 20266;
|
||||
public const ENCHANTED_BOOK = 20267;
|
||||
|
||||
public const FIRST_UNUSED_ITEM_ID = 20267;
|
||||
public const FIRST_UNUSED_ITEM_ID = 20268;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;
|
||||
|
||||
|
@ -1277,6 +1277,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->register("egg", fn() => Items::EGG());
|
||||
$result->register("elixir", fn() => Items::MEDICINE()->setType(MedicineType::ELIXIR()));
|
||||
$result->register("emerald", fn() => Items::EMERALD());
|
||||
$result->register("enchanted_book", fn() => Items::ENCHANTED_BOOK());
|
||||
$result->register("enchanted_golden_apple", fn() => Items::ENCHANTED_GOLDEN_APPLE());
|
||||
$result->register("enchanting_bottle", fn() => Items::EXPERIENCE_BOTTLE());
|
||||
$result->register("ender_pearl", fn() => Items::ENDER_PEARL());
|
||||
|
@ -26,8 +26,11 @@ namespace pocketmine\item;
|
||||
abstract class TieredTool extends Tool{
|
||||
protected ToolTier $tier;
|
||||
|
||||
public function __construct(ItemIdentifier $identifier, string $name, ToolTier $tier){
|
||||
parent::__construct($identifier, $name);
|
||||
/**
|
||||
* @param string[] $enchantmentTags
|
||||
*/
|
||||
public function __construct(ItemIdentifier $identifier, string $name, ToolTier $tier, array $enchantmentTags = []){
|
||||
parent::__construct($identifier, $name, $enchantmentTags);
|
||||
$this->tier = $tier;
|
||||
}
|
||||
|
||||
@ -43,6 +46,10 @@ abstract class TieredTool extends Tool{
|
||||
return $this->tier->getBaseEfficiency();
|
||||
}
|
||||
|
||||
public function getEnchantability() : int{
|
||||
return $this->tier->getEnchantability();
|
||||
}
|
||||
|
||||
public function getFuelTime() : int{
|
||||
if($this->tier->equals(ToolTier::WOOD())){
|
||||
return 200;
|
||||
|
@ -45,12 +45,12 @@ final class ToolTier{
|
||||
|
||||
protected static function setup() : void{
|
||||
self::registerAll(
|
||||
new self("wood", 1, 60, 5, 2),
|
||||
new self("gold", 2, 33, 5, 12),
|
||||
new self("stone", 3, 132, 6, 4),
|
||||
new self("iron", 4, 251, 7, 6),
|
||||
new self("diamond", 5, 1562, 8, 8),
|
||||
new self("netherite", 6, 2032, 9, 9)
|
||||
new self("wood", 1, 60, 5, 2, 15),
|
||||
new self("gold", 2, 33, 5, 12, 22),
|
||||
new self("stone", 3, 132, 6, 4, 5),
|
||||
new self("iron", 4, 251, 7, 6, 14),
|
||||
new self("diamond", 5, 1562, 8, 8, 10),
|
||||
new self("netherite", 6, 2032, 9, 9, 15)
|
||||
);
|
||||
}
|
||||
|
||||
@ -59,7 +59,8 @@ final class ToolTier{
|
||||
private int $harvestLevel,
|
||||
private int $maxDurability,
|
||||
private int $baseAttackPoints,
|
||||
private int $baseEfficiency
|
||||
private int $baseEfficiency,
|
||||
private int $enchantability
|
||||
){
|
||||
$this->Enum___construct($name);
|
||||
}
|
||||
@ -79,4 +80,14 @@ final class ToolTier{
|
||||
public function getBaseEfficiency() : int{
|
||||
return $this->baseEfficiency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that defines how enchantable the item is.
|
||||
*
|
||||
* The higher an item's enchantability is, the more likely it will be to gain high-level enchantments
|
||||
* or multiple enchantments upon being enchanted in an enchanting table.
|
||||
*/
|
||||
public function getEnchantability() : int{
|
||||
return $this->enchantability;
|
||||
}
|
||||
}
|
||||
|
73
src/item/VanillaArmorMaterials.php
Normal file
73
src/item/VanillaArmorMaterials.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?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\item;
|
||||
|
||||
use pocketmine\utils\RegistryTrait;
|
||||
|
||||
/**
|
||||
* This doc-block is generated automatically, do not modify it manually.
|
||||
* This must be regenerated whenever registry members are added, removed or changed.
|
||||
* @see build/generate-registry-annotations.php
|
||||
* @generate-registry-docblock
|
||||
*
|
||||
* @method static ArmorMaterial CHAINMAIL()
|
||||
* @method static ArmorMaterial DIAMOND()
|
||||
* @method static ArmorMaterial GOLD()
|
||||
* @method static ArmorMaterial IRON()
|
||||
* @method static ArmorMaterial LEATHER()
|
||||
* @method static ArmorMaterial NETHERITE()
|
||||
* @method static ArmorMaterial TURTLE()
|
||||
*/
|
||||
final class VanillaArmorMaterials{
|
||||
use RegistryTrait;
|
||||
|
||||
private function __construct(){
|
||||
// NOOP
|
||||
}
|
||||
|
||||
protected static function register(string $name, ArmorMaterial $armorMaterial) : void{
|
||||
self::_registryRegister($name, $armorMaterial);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArmorMaterial[]
|
||||
* @phpstan-return array<string, ArmorMaterial>
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
// phpstan doesn't support generic traits yet :(
|
||||
/** @var ArmorMaterial[] $result */
|
||||
$result = self::_registryGetAll();
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected static function setup() : void{
|
||||
self::register("leather", new ArmorMaterial(15));
|
||||
self::register("chainmail", new ArmorMaterial(12));
|
||||
self::register("iron", new ArmorMaterial(9));
|
||||
self::register("turtle", new ArmorMaterial(9));
|
||||
self::register("gold", new ArmorMaterial(25));
|
||||
self::register("diamond", new ArmorMaterial(10));
|
||||
self::register("netherite", new ArmorMaterial(15));
|
||||
}
|
||||
}
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\block\utils\RecordType;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\block\VanillaBlocks as Blocks;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Location;
|
||||
@ -32,8 +31,10 @@ use pocketmine\entity\Squid;
|
||||
use pocketmine\entity\Villager;
|
||||
use pocketmine\entity\Zombie;
|
||||
use pocketmine\inventory\ArmorInventory;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags as EnchantmentTags;
|
||||
use pocketmine\item\ItemIdentifier as IID;
|
||||
use pocketmine\item\ItemTypeIds as Ids;
|
||||
use pocketmine\item\VanillaArmorMaterials as ArmorMaterials;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\CloningRegistryTrait;
|
||||
@ -151,6 +152,7 @@ use pocketmine\world\World;
|
||||
* @method static Item ECHO_SHARD()
|
||||
* @method static Egg EGG()
|
||||
* @method static Item EMERALD()
|
||||
* @method static EnchantedBook ENCHANTED_BOOK()
|
||||
* @method static GoldenAppleEnchanted ENCHANTED_GOLDEN_APPLE()
|
||||
* @method static EnderPearl ENDER_PEARL()
|
||||
* @method static ExperienceBottle EXPERIENCE_BOTTLE()
|
||||
@ -337,7 +339,7 @@ final class VanillaItems{
|
||||
self::registerSpawnEggs();
|
||||
self::registerTierToolItems();
|
||||
|
||||
self::register("air", VanillaBlocks::AIR()->asItem()->setCount(0));
|
||||
self::register("air", Blocks::AIR()->asItem()->setCount(0));
|
||||
|
||||
self::register("acacia_sign", new ItemBlockWallOrFloor(new IID(Ids::ACACIA_SIGN), Blocks::ACACIA_SIGN(), Blocks::ACACIA_WALL_SIGN()));
|
||||
self::register("amethyst_shard", new Item(new IID(Ids::AMETHYST_SHARD), "Amethyst Shard"));
|
||||
@ -355,8 +357,8 @@ final class VanillaItems{
|
||||
self::register("bleach", new Item(new IID(Ids::BLEACH), "Bleach"));
|
||||
self::register("bone", new Item(new IID(Ids::BONE), "Bone"));
|
||||
self::register("bone_meal", new Fertilizer(new IID(Ids::BONE_MEAL), "Bone Meal"));
|
||||
self::register("book", new Book(new IID(Ids::BOOK), "Book"));
|
||||
self::register("bow", new Bow(new IID(Ids::BOW), "Bow"));
|
||||
self::register("book", new Book(new IID(Ids::BOOK), "Book", [EnchantmentTags::ALL]));
|
||||
self::register("bow", new Bow(new IID(Ids::BOW), "Bow", [EnchantmentTags::BOW]));
|
||||
self::register("bowl", new Bowl(new IID(Ids::BOWL), "Bowl"));
|
||||
self::register("bread", new Bread(new IID(Ids::BREAD), "Bread"));
|
||||
self::register("brick", new Item(new IID(Ids::BRICK), "Brick"));
|
||||
@ -408,7 +410,7 @@ final class VanillaItems{
|
||||
self::register("clownfish", new Clownfish(new IID(Ids::CLOWNFISH), "Clownfish"));
|
||||
self::register("coal", new Coal(new IID(Ids::COAL), "Coal"));
|
||||
self::register("cocoa_beans", new CocoaBeans(new IID(Ids::COCOA_BEANS), "Cocoa Beans"));
|
||||
self::register("compass", new Compass(new IID(Ids::COMPASS), "Compass"));
|
||||
self::register("compass", new Compass(new IID(Ids::COMPASS), "Compass", [EnchantmentTags::COMPASS]));
|
||||
self::register("cooked_chicken", new CookedChicken(new IID(Ids::COOKED_CHICKEN), "Cooked Chicken"));
|
||||
self::register("cooked_fish", new CookedFish(new IID(Ids::COOKED_FISH), "Cooked Fish"));
|
||||
self::register("cooked_mutton", new CookedMutton(new IID(Ids::COOKED_MUTTON), "Cooked Mutton"));
|
||||
@ -429,15 +431,16 @@ final class VanillaItems{
|
||||
self::register("echo_shard", new Item(new IID(Ids::ECHO_SHARD), "Echo Shard"));
|
||||
self::register("egg", new Egg(new IID(Ids::EGG), "Egg"));
|
||||
self::register("emerald", new Item(new IID(Ids::EMERALD), "Emerald"));
|
||||
self::register("enchanted_book", new EnchantedBook(new IID(Ids::ENCHANTED_BOOK), "Enchanted Book"));
|
||||
self::register("enchanted_golden_apple", new GoldenAppleEnchanted(new IID(Ids::ENCHANTED_GOLDEN_APPLE), "Enchanted Golden Apple"));
|
||||
self::register("ender_pearl", new EnderPearl(new IID(Ids::ENDER_PEARL), "Ender Pearl"));
|
||||
self::register("experience_bottle", new ExperienceBottle(new IID(Ids::EXPERIENCE_BOTTLE), "Bottle o' Enchanting"));
|
||||
self::register("feather", new Item(new IID(Ids::FEATHER), "Feather"));
|
||||
self::register("fermented_spider_eye", new Item(new IID(Ids::FERMENTED_SPIDER_EYE), "Fermented Spider Eye"));
|
||||
self::register("fire_charge", new FireCharge(new IID(Ids::FIRE_CHARGE), "Fire Charge"));
|
||||
self::register("fishing_rod", new FishingRod(new IID(Ids::FISHING_ROD), "Fishing Rod"));
|
||||
self::register("fishing_rod", new FishingRod(new IID(Ids::FISHING_ROD), "Fishing Rod", [EnchantmentTags::FISHING_ROD]));
|
||||
self::register("flint", new Item(new IID(Ids::FLINT), "Flint"));
|
||||
self::register("flint_and_steel", new FlintSteel(new IID(Ids::FLINT_AND_STEEL), "Flint and Steel"));
|
||||
self::register("flint_and_steel", new FlintSteel(new IID(Ids::FLINT_AND_STEEL), "Flint and Steel", [EnchantmentTags::FLINT_AND_STEEL]));
|
||||
self::register("ghast_tear", new Item(new IID(Ids::GHAST_TEAR), "Ghast Tear"));
|
||||
self::register("glass_bottle", new GlassBottle(new IID(Ids::GLASS_BOTTLE), "Glass Bottle"));
|
||||
self::register("glistering_melon", new Item(new IID(Ids::GLISTERING_MELON), "Glistering Melon"));
|
||||
@ -521,7 +524,7 @@ final class VanillaItems{
|
||||
self::register("redstone_dust", new Redstone(new IID(Ids::REDSTONE_DUST), "Redstone"));
|
||||
self::register("rotten_flesh", new RottenFlesh(new IID(Ids::ROTTEN_FLESH), "Rotten Flesh"));
|
||||
self::register("scute", new Item(new IID(Ids::SCUTE), "Scute"));
|
||||
self::register("shears", new Shears(new IID(Ids::SHEARS), "Shears"));
|
||||
self::register("shears", new Shears(new IID(Ids::SHEARS), "Shears", [EnchantmentTags::SHEARS]));
|
||||
self::register("shulker_shell", new Item(new IID(Ids::SHULKER_SHELL), "Shulker Shell"));
|
||||
self::register("slimeball", new Item(new IID(Ids::SLIMEBALL), "Slimeball"));
|
||||
self::register("snowball", new Snowball(new IID(Ids::SNOWBALL), "Snowball"));
|
||||
@ -577,67 +580,67 @@ final class VanillaItems{
|
||||
}
|
||||
|
||||
private static function registerTierToolItems() : void{
|
||||
self::register("diamond_axe", new Axe(new IID(Ids::DIAMOND_AXE), "Diamond Axe", ToolTier::DIAMOND()));
|
||||
self::register("golden_axe", new Axe(new IID(Ids::GOLDEN_AXE), "Golden Axe", ToolTier::GOLD()));
|
||||
self::register("iron_axe", new Axe(new IID(Ids::IRON_AXE), "Iron Axe", ToolTier::IRON()));
|
||||
self::register("netherite_axe", new Axe(new IID(Ids::NETHERITE_AXE), "Netherite Axe", ToolTier::NETHERITE()));
|
||||
self::register("stone_axe", new Axe(new IID(Ids::STONE_AXE), "Stone Axe", ToolTier::STONE()));
|
||||
self::register("wooden_axe", new Axe(new IID(Ids::WOODEN_AXE), "Wooden Axe", ToolTier::WOOD()));
|
||||
self::register("diamond_hoe", new Hoe(new IID(Ids::DIAMOND_HOE), "Diamond Hoe", ToolTier::DIAMOND()));
|
||||
self::register("golden_hoe", new Hoe(new IID(Ids::GOLDEN_HOE), "Golden Hoe", ToolTier::GOLD()));
|
||||
self::register("iron_hoe", new Hoe(new IID(Ids::IRON_HOE), "Iron Hoe", ToolTier::IRON()));
|
||||
self::register("netherite_hoe", new Hoe(new IID(Ids::NETHERITE_HOE), "Netherite Hoe", ToolTier::NETHERITE()));
|
||||
self::register("stone_hoe", new Hoe(new IID(Ids::STONE_HOE), "Stone Hoe", ToolTier::STONE()));
|
||||
self::register("wooden_hoe", new Hoe(new IID(Ids::WOODEN_HOE), "Wooden Hoe", ToolTier::WOOD()));
|
||||
self::register("diamond_pickaxe", new Pickaxe(new IID(Ids::DIAMOND_PICKAXE), "Diamond Pickaxe", ToolTier::DIAMOND()));
|
||||
self::register("golden_pickaxe", new Pickaxe(new IID(Ids::GOLDEN_PICKAXE), "Golden Pickaxe", ToolTier::GOLD()));
|
||||
self::register("iron_pickaxe", new Pickaxe(new IID(Ids::IRON_PICKAXE), "Iron Pickaxe", ToolTier::IRON()));
|
||||
self::register("netherite_pickaxe", new Pickaxe(new IID(Ids::NETHERITE_PICKAXE), "Netherite Pickaxe", ToolTier::NETHERITE()));
|
||||
self::register("stone_pickaxe", new Pickaxe(new IID(Ids::STONE_PICKAXE), "Stone Pickaxe", ToolTier::STONE()));
|
||||
self::register("wooden_pickaxe", new Pickaxe(new IID(Ids::WOODEN_PICKAXE), "Wooden Pickaxe", ToolTier::WOOD()));
|
||||
self::register("diamond_shovel", new Shovel(new IID(Ids::DIAMOND_SHOVEL), "Diamond Shovel", ToolTier::DIAMOND()));
|
||||
self::register("golden_shovel", new Shovel(new IID(Ids::GOLDEN_SHOVEL), "Golden Shovel", ToolTier::GOLD()));
|
||||
self::register("iron_shovel", new Shovel(new IID(Ids::IRON_SHOVEL), "Iron Shovel", ToolTier::IRON()));
|
||||
self::register("netherite_shovel", new Shovel(new IID(Ids::NETHERITE_SHOVEL), "Netherite Shovel", ToolTier::NETHERITE()));
|
||||
self::register("stone_shovel", new Shovel(new IID(Ids::STONE_SHOVEL), "Stone Shovel", ToolTier::STONE()));
|
||||
self::register("wooden_shovel", new Shovel(new IID(Ids::WOODEN_SHOVEL), "Wooden Shovel", ToolTier::WOOD()));
|
||||
self::register("diamond_sword", new Sword(new IID(Ids::DIAMOND_SWORD), "Diamond Sword", ToolTier::DIAMOND()));
|
||||
self::register("golden_sword", new Sword(new IID(Ids::GOLDEN_SWORD), "Golden Sword", ToolTier::GOLD()));
|
||||
self::register("iron_sword", new Sword(new IID(Ids::IRON_SWORD), "Iron Sword", ToolTier::IRON()));
|
||||
self::register("netherite_sword", new Sword(new IID(Ids::NETHERITE_SWORD), "Netherite Sword", ToolTier::NETHERITE()));
|
||||
self::register("stone_sword", new Sword(new IID(Ids::STONE_SWORD), "Stone Sword", ToolTier::STONE()));
|
||||
self::register("wooden_sword", new Sword(new IID(Ids::WOODEN_SWORD), "Wooden Sword", ToolTier::WOOD()));
|
||||
self::register("diamond_axe", new Axe(new IID(Ids::DIAMOND_AXE), "Diamond Axe", ToolTier::DIAMOND(), [EnchantmentTags::AXE]));
|
||||
self::register("golden_axe", new Axe(new IID(Ids::GOLDEN_AXE), "Golden Axe", ToolTier::GOLD(), [EnchantmentTags::AXE]));
|
||||
self::register("iron_axe", new Axe(new IID(Ids::IRON_AXE), "Iron Axe", ToolTier::IRON(), [EnchantmentTags::AXE]));
|
||||
self::register("netherite_axe", new Axe(new IID(Ids::NETHERITE_AXE), "Netherite Axe", ToolTier::NETHERITE(), [EnchantmentTags::AXE]));
|
||||
self::register("stone_axe", new Axe(new IID(Ids::STONE_AXE), "Stone Axe", ToolTier::STONE(), [EnchantmentTags::AXE]));
|
||||
self::register("wooden_axe", new Axe(new IID(Ids::WOODEN_AXE), "Wooden Axe", ToolTier::WOOD(), [EnchantmentTags::AXE]));
|
||||
self::register("diamond_hoe", new Hoe(new IID(Ids::DIAMOND_HOE), "Diamond Hoe", ToolTier::DIAMOND(), [EnchantmentTags::HOE]));
|
||||
self::register("golden_hoe", new Hoe(new IID(Ids::GOLDEN_HOE), "Golden Hoe", ToolTier::GOLD(), [EnchantmentTags::HOE]));
|
||||
self::register("iron_hoe", new Hoe(new IID(Ids::IRON_HOE), "Iron Hoe", ToolTier::IRON(), [EnchantmentTags::HOE]));
|
||||
self::register("netherite_hoe", new Hoe(new IID(Ids::NETHERITE_HOE), "Netherite Hoe", ToolTier::NETHERITE(), [EnchantmentTags::HOE]));
|
||||
self::register("stone_hoe", new Hoe(new IID(Ids::STONE_HOE), "Stone Hoe", ToolTier::STONE(), [EnchantmentTags::HOE]));
|
||||
self::register("wooden_hoe", new Hoe(new IID(Ids::WOODEN_HOE), "Wooden Hoe", ToolTier::WOOD(), [EnchantmentTags::HOE]));
|
||||
self::register("diamond_pickaxe", new Pickaxe(new IID(Ids::DIAMOND_PICKAXE), "Diamond Pickaxe", ToolTier::DIAMOND(), [EnchantmentTags::PICKAXE]));
|
||||
self::register("golden_pickaxe", new Pickaxe(new IID(Ids::GOLDEN_PICKAXE), "Golden Pickaxe", ToolTier::GOLD(), [EnchantmentTags::PICKAXE]));
|
||||
self::register("iron_pickaxe", new Pickaxe(new IID(Ids::IRON_PICKAXE), "Iron Pickaxe", ToolTier::IRON(), [EnchantmentTags::PICKAXE]));
|
||||
self::register("netherite_pickaxe", new Pickaxe(new IID(Ids::NETHERITE_PICKAXE), "Netherite Pickaxe", ToolTier::NETHERITE(), [EnchantmentTags::PICKAXE]));
|
||||
self::register("stone_pickaxe", new Pickaxe(new IID(Ids::STONE_PICKAXE), "Stone Pickaxe", ToolTier::STONE(), [EnchantmentTags::PICKAXE]));
|
||||
self::register("wooden_pickaxe", new Pickaxe(new IID(Ids::WOODEN_PICKAXE), "Wooden Pickaxe", ToolTier::WOOD(), [EnchantmentTags::PICKAXE]));
|
||||
self::register("diamond_shovel", new Shovel(new IID(Ids::DIAMOND_SHOVEL), "Diamond Shovel", ToolTier::DIAMOND(), [EnchantmentTags::SHOVEL]));
|
||||
self::register("golden_shovel", new Shovel(new IID(Ids::GOLDEN_SHOVEL), "Golden Shovel", ToolTier::GOLD(), [EnchantmentTags::SHOVEL]));
|
||||
self::register("iron_shovel", new Shovel(new IID(Ids::IRON_SHOVEL), "Iron Shovel", ToolTier::IRON(), [EnchantmentTags::SHOVEL]));
|
||||
self::register("netherite_shovel", new Shovel(new IID(Ids::NETHERITE_SHOVEL), "Netherite Shovel", ToolTier::NETHERITE(), [EnchantmentTags::SHOVEL]));
|
||||
self::register("stone_shovel", new Shovel(new IID(Ids::STONE_SHOVEL), "Stone Shovel", ToolTier::STONE(), [EnchantmentTags::SHOVEL]));
|
||||
self::register("wooden_shovel", new Shovel(new IID(Ids::WOODEN_SHOVEL), "Wooden Shovel", ToolTier::WOOD(), [EnchantmentTags::SHOVEL]));
|
||||
self::register("diamond_sword", new Sword(new IID(Ids::DIAMOND_SWORD), "Diamond Sword", ToolTier::DIAMOND(), [EnchantmentTags::SWORD]));
|
||||
self::register("golden_sword", new Sword(new IID(Ids::GOLDEN_SWORD), "Golden Sword", ToolTier::GOLD(), [EnchantmentTags::SWORD]));
|
||||
self::register("iron_sword", new Sword(new IID(Ids::IRON_SWORD), "Iron Sword", ToolTier::IRON(), [EnchantmentTags::SWORD]));
|
||||
self::register("netherite_sword", new Sword(new IID(Ids::NETHERITE_SWORD), "Netherite Sword", ToolTier::NETHERITE(), [EnchantmentTags::SWORD]));
|
||||
self::register("stone_sword", new Sword(new IID(Ids::STONE_SWORD), "Stone Sword", ToolTier::STONE(), [EnchantmentTags::SWORD]));
|
||||
self::register("wooden_sword", new Sword(new IID(Ids::WOODEN_SWORD), "Wooden Sword", ToolTier::WOOD(), [EnchantmentTags::SWORD]));
|
||||
}
|
||||
|
||||
private static function registerArmorItems() : void{
|
||||
self::register("chainmail_boots", new Armor(new IID(Ids::CHAINMAIL_BOOTS), "Chainmail Boots", new ArmorTypeInfo(1, 196, ArmorInventory::SLOT_FEET)));
|
||||
self::register("diamond_boots", new Armor(new IID(Ids::DIAMOND_BOOTS), "Diamond Boots", new ArmorTypeInfo(3, 430, ArmorInventory::SLOT_FEET, 2)));
|
||||
self::register("golden_boots", new Armor(new IID(Ids::GOLDEN_BOOTS), "Golden Boots", new ArmorTypeInfo(1, 92, ArmorInventory::SLOT_FEET)));
|
||||
self::register("iron_boots", new Armor(new IID(Ids::IRON_BOOTS), "Iron Boots", new ArmorTypeInfo(2, 196, ArmorInventory::SLOT_FEET)));
|
||||
self::register("leather_boots", new Armor(new IID(Ids::LEATHER_BOOTS), "Leather Boots", new ArmorTypeInfo(1, 66, ArmorInventory::SLOT_FEET)));
|
||||
self::register("netherite_boots", new Armor(new IID(Ids::NETHERITE_BOOTS), "Netherite Boots", new ArmorTypeInfo(3, 482, ArmorInventory::SLOT_FEET, 3, true)));
|
||||
self::register("chainmail_boots", new Armor(new IID(Ids::CHAINMAIL_BOOTS), "Chainmail Boots", new ArmorTypeInfo(1, 196, ArmorInventory::SLOT_FEET, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::BOOTS]));
|
||||
self::register("diamond_boots", new Armor(new IID(Ids::DIAMOND_BOOTS), "Diamond Boots", new ArmorTypeInfo(3, 430, ArmorInventory::SLOT_FEET, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::BOOTS]));
|
||||
self::register("golden_boots", new Armor(new IID(Ids::GOLDEN_BOOTS), "Golden Boots", new ArmorTypeInfo(1, 92, ArmorInventory::SLOT_FEET, material: ArmorMaterials::GOLD()), [EnchantmentTags::BOOTS]));
|
||||
self::register("iron_boots", new Armor(new IID(Ids::IRON_BOOTS), "Iron Boots", new ArmorTypeInfo(2, 196, ArmorInventory::SLOT_FEET, material: ArmorMaterials::IRON()), [EnchantmentTags::BOOTS]));
|
||||
self::register("leather_boots", new Armor(new IID(Ids::LEATHER_BOOTS), "Leather Boots", new ArmorTypeInfo(1, 66, ArmorInventory::SLOT_FEET, material: ArmorMaterials::LEATHER()), [EnchantmentTags::BOOTS]));
|
||||
self::register("netherite_boots", new Armor(new IID(Ids::NETHERITE_BOOTS), "Netherite Boots", new ArmorTypeInfo(3, 482, ArmorInventory::SLOT_FEET, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::BOOTS]));
|
||||
|
||||
self::register("chainmail_chestplate", new Armor(new IID(Ids::CHAINMAIL_CHESTPLATE), "Chainmail Chestplate", new ArmorTypeInfo(5, 241, ArmorInventory::SLOT_CHEST)));
|
||||
self::register("diamond_chestplate", new Armor(new IID(Ids::DIAMOND_CHESTPLATE), "Diamond Chestplate", new ArmorTypeInfo(8, 529, ArmorInventory::SLOT_CHEST, 2)));
|
||||
self::register("golden_chestplate", new Armor(new IID(Ids::GOLDEN_CHESTPLATE), "Golden Chestplate", new ArmorTypeInfo(5, 113, ArmorInventory::SLOT_CHEST)));
|
||||
self::register("iron_chestplate", new Armor(new IID(Ids::IRON_CHESTPLATE), "Iron Chestplate", new ArmorTypeInfo(6, 241, ArmorInventory::SLOT_CHEST)));
|
||||
self::register("leather_tunic", new Armor(new IID(Ids::LEATHER_TUNIC), "Leather Tunic", new ArmorTypeInfo(3, 81, ArmorInventory::SLOT_CHEST)));
|
||||
self::register("netherite_chestplate", new Armor(new IID(Ids::NETHERITE_CHESTPLATE), "Netherite Chestplate", new ArmorTypeInfo(8, 593, ArmorInventory::SLOT_CHEST, 3, true)));
|
||||
self::register("chainmail_chestplate", new Armor(new IID(Ids::CHAINMAIL_CHESTPLATE), "Chainmail Chestplate", new ArmorTypeInfo(5, 241, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("diamond_chestplate", new Armor(new IID(Ids::DIAMOND_CHESTPLATE), "Diamond Chestplate", new ArmorTypeInfo(8, 529, ArmorInventory::SLOT_CHEST, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("golden_chestplate", new Armor(new IID(Ids::GOLDEN_CHESTPLATE), "Golden Chestplate", new ArmorTypeInfo(5, 113, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::GOLD()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("iron_chestplate", new Armor(new IID(Ids::IRON_CHESTPLATE), "Iron Chestplate", new ArmorTypeInfo(6, 241, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::IRON()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("leather_tunic", new Armor(new IID(Ids::LEATHER_TUNIC), "Leather Tunic", new ArmorTypeInfo(3, 81, ArmorInventory::SLOT_CHEST, material: ArmorMaterials::LEATHER()), [EnchantmentTags::CHESTPLATE]));
|
||||
self::register("netherite_chestplate", new Armor(new IID(Ids::NETHERITE_CHESTPLATE), "Netherite Chestplate", new ArmorTypeInfo(8, 593, ArmorInventory::SLOT_CHEST, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::CHESTPLATE]));
|
||||
|
||||
self::register("chainmail_helmet", new Armor(new IID(Ids::CHAINMAIL_HELMET), "Chainmail Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD)));
|
||||
self::register("diamond_helmet", new Armor(new IID(Ids::DIAMOND_HELMET), "Diamond Helmet", new ArmorTypeInfo(3, 364, ArmorInventory::SLOT_HEAD, 2)));
|
||||
self::register("golden_helmet", new Armor(new IID(Ids::GOLDEN_HELMET), "Golden Helmet", new ArmorTypeInfo(2, 78, ArmorInventory::SLOT_HEAD)));
|
||||
self::register("iron_helmet", new Armor(new IID(Ids::IRON_HELMET), "Iron Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD)));
|
||||
self::register("leather_cap", new Armor(new IID(Ids::LEATHER_CAP), "Leather Cap", new ArmorTypeInfo(1, 56, ArmorInventory::SLOT_HEAD)));
|
||||
self::register("netherite_helmet", new Armor(new IID(Ids::NETHERITE_HELMET), "Netherite Helmet", new ArmorTypeInfo(3, 408, ArmorInventory::SLOT_HEAD, 3, true)));
|
||||
self::register("turtle_helmet", new TurtleHelmet(new IID(Ids::TURTLE_HELMET), "Turtle Shell", new ArmorTypeInfo(2, 276, ArmorInventory::SLOT_HEAD)));
|
||||
self::register("chainmail_helmet", new Armor(new IID(Ids::CHAINMAIL_HELMET), "Chainmail Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::HELMET]));
|
||||
self::register("diamond_helmet", new Armor(new IID(Ids::DIAMOND_HELMET), "Diamond Helmet", new ArmorTypeInfo(3, 364, ArmorInventory::SLOT_HEAD, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::HELMET]));
|
||||
self::register("golden_helmet", new Armor(new IID(Ids::GOLDEN_HELMET), "Golden Helmet", new ArmorTypeInfo(2, 78, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::GOLD()), [EnchantmentTags::HELMET]));
|
||||
self::register("iron_helmet", new Armor(new IID(Ids::IRON_HELMET), "Iron Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::IRON()), [EnchantmentTags::HELMET]));
|
||||
self::register("leather_cap", new Armor(new IID(Ids::LEATHER_CAP), "Leather Cap", new ArmorTypeInfo(1, 56, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::LEATHER()), [EnchantmentTags::HELMET]));
|
||||
self::register("netherite_helmet", new Armor(new IID(Ids::NETHERITE_HELMET), "Netherite Helmet", new ArmorTypeInfo(3, 408, ArmorInventory::SLOT_HEAD, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::HELMET]));
|
||||
self::register("turtle_helmet", new TurtleHelmet(new IID(Ids::TURTLE_HELMET), "Turtle Shell", new ArmorTypeInfo(2, 276, ArmorInventory::SLOT_HEAD, material: ArmorMaterials::TURTLE()), [EnchantmentTags::HELMET]));
|
||||
|
||||
self::register("chainmail_leggings", new Armor(new IID(Ids::CHAINMAIL_LEGGINGS), "Chainmail Leggings", new ArmorTypeInfo(4, 226, ArmorInventory::SLOT_LEGS)));
|
||||
self::register("diamond_leggings", new Armor(new IID(Ids::DIAMOND_LEGGINGS), "Diamond Leggings", new ArmorTypeInfo(6, 496, ArmorInventory::SLOT_LEGS, 2)));
|
||||
self::register("golden_leggings", new Armor(new IID(Ids::GOLDEN_LEGGINGS), "Golden Leggings", new ArmorTypeInfo(3, 106, ArmorInventory::SLOT_LEGS)));
|
||||
self::register("iron_leggings", new Armor(new IID(Ids::IRON_LEGGINGS), "Iron Leggings", new ArmorTypeInfo(5, 226, ArmorInventory::SLOT_LEGS)));
|
||||
self::register("leather_pants", new Armor(new IID(Ids::LEATHER_PANTS), "Leather Pants", new ArmorTypeInfo(2, 76, ArmorInventory::SLOT_LEGS)));
|
||||
self::register("netherite_leggings", new Armor(new IID(Ids::NETHERITE_LEGGINGS), "Netherite Leggings", new ArmorTypeInfo(6, 556, ArmorInventory::SLOT_LEGS, 3, true)));
|
||||
self::register("chainmail_leggings", new Armor(new IID(Ids::CHAINMAIL_LEGGINGS), "Chainmail Leggings", new ArmorTypeInfo(4, 226, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::CHAINMAIL()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("diamond_leggings", new Armor(new IID(Ids::DIAMOND_LEGGINGS), "Diamond Leggings", new ArmorTypeInfo(6, 496, ArmorInventory::SLOT_LEGS, 2, material: ArmorMaterials::DIAMOND()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("golden_leggings", new Armor(new IID(Ids::GOLDEN_LEGGINGS), "Golden Leggings", new ArmorTypeInfo(3, 106, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::GOLD()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("iron_leggings", new Armor(new IID(Ids::IRON_LEGGINGS), "Iron Leggings", new ArmorTypeInfo(5, 226, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::IRON()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("leather_pants", new Armor(new IID(Ids::LEATHER_PANTS), "Leather Pants", new ArmorTypeInfo(2, 76, ArmorInventory::SLOT_LEGS, material: ArmorMaterials::LEATHER()), [EnchantmentTags::LEGGINGS]));
|
||||
self::register("netherite_leggings", new Armor(new IID(Ids::NETHERITE_LEGGINGS), "Netherite Leggings", new ArmorTypeInfo(6, 556, ArmorInventory::SLOT_LEGS, 3, true, material: ArmorMaterials::NETHERITE()), [EnchantmentTags::LEGGINGS]));
|
||||
}
|
||||
|
||||
}
|
||||
|
211
src/item/enchantment/AvailableEnchantmentRegistry.php
Normal file
211
src/item/enchantment/AvailableEnchantmentRegistry.php
Normal file
@ -0,0 +1,211 @@
|
||||
<?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\item\enchantment;
|
||||
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTagRegistry as TagRegistry;
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags as Tags;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments as Enchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use function array_filter;
|
||||
use function array_values;
|
||||
use function count;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* Registry of enchantments that can be applied to items during in-game enchanting (enchanting table, anvil, fishing, etc.).
|
||||
*/
|
||||
final class AvailableEnchantmentRegistry{
|
||||
use SingletonTrait;
|
||||
|
||||
/** @var Enchantment[] */
|
||||
private array $enchantments = [];
|
||||
|
||||
/** @var string[][] */
|
||||
private array $primaryItemTags = [];
|
||||
|
||||
/** @var string[][] */
|
||||
private array $secondaryItemTags = [];
|
||||
|
||||
private function __construct(){
|
||||
$this->register(Enchantments::PROTECTION(), [Tags::ARMOR], []);
|
||||
$this->register(Enchantments::FIRE_PROTECTION(), [Tags::ARMOR], []);
|
||||
$this->register(Enchantments::FEATHER_FALLING(), [Tags::BOOTS], []);
|
||||
$this->register(Enchantments::BLAST_PROTECTION(), [Tags::ARMOR], []);
|
||||
$this->register(Enchantments::PROJECTILE_PROTECTION(), [Tags::ARMOR], []);
|
||||
$this->register(Enchantments::THORNS(), [Tags::CHESTPLATE], [Tags::HELMET, Tags::LEGGINGS, Tags::BOOTS]);
|
||||
$this->register(Enchantments::RESPIRATION(), [Tags::HELMET], []);
|
||||
$this->register(Enchantments::SHARPNESS(), [Tags::SWORD, Tags::AXE], []);
|
||||
$this->register(Enchantments::KNOCKBACK(), [Tags::SWORD], []);
|
||||
$this->register(Enchantments::FIRE_ASPECT(), [Tags::SWORD], []);
|
||||
$this->register(Enchantments::EFFICIENCY(), [Tags::DIG_TOOLS], [Tags::SHEARS]);
|
||||
$this->register(Enchantments::FORTUNE(), [Tags::DIG_TOOLS], []);
|
||||
$this->register(Enchantments::SILK_TOUCH(), [Tags::DIG_TOOLS], [Tags::SHEARS]);
|
||||
$this->register(
|
||||
Enchantments::UNBREAKING(),
|
||||
[Tags::ARMOR, Tags::WEAPONS, Tags::FISHING_ROD],
|
||||
[Tags::SHEARS, Tags::FLINT_AND_STEEL, Tags::SHIELD, Tags::CARROT_ON_STICK, Tags::ELYTRA, Tags::BRUSH]
|
||||
);
|
||||
$this->register(Enchantments::POWER(), [Tags::BOW], []);
|
||||
$this->register(Enchantments::PUNCH(), [Tags::BOW], []);
|
||||
$this->register(Enchantments::FLAME(), [Tags::BOW], []);
|
||||
$this->register(Enchantments::INFINITY(), [Tags::BOW], []);
|
||||
$this->register(
|
||||
Enchantments::MENDING(),
|
||||
[],
|
||||
[Tags::ARMOR, Tags::WEAPONS, Tags::FISHING_ROD,
|
||||
Tags::SHEARS, Tags::FLINT_AND_STEEL, Tags::SHIELD, Tags::CARROT_ON_STICK, Tags::ELYTRA, Tags::BRUSH]
|
||||
);
|
||||
$this->register(Enchantments::VANISHING(), [], [Tags::ALL]);
|
||||
$this->register(Enchantments::SWIFT_SNEAK(), [], [Tags::LEGGINGS]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $primaryItemTags
|
||||
* @param string[] $secondaryItemTags
|
||||
*/
|
||||
public function register(Enchantment $enchantment, array $primaryItemTags, array $secondaryItemTags) : void{
|
||||
$this->enchantments[spl_object_id($enchantment)] = $enchantment;
|
||||
$this->setPrimaryItemTags($enchantment, $primaryItemTags);
|
||||
$this->setSecondaryItemTags($enchantment, $secondaryItemTags);
|
||||
}
|
||||
|
||||
public function unregister(Enchantment $enchantment) : void{
|
||||
unset($this->enchantments[spl_object_id($enchantment)]);
|
||||
unset($this->primaryItemTags[spl_object_id($enchantment)]);
|
||||
unset($this->secondaryItemTags[spl_object_id($enchantment)]);
|
||||
}
|
||||
|
||||
public function unregisterAll() : void{
|
||||
$this->enchantments = [];
|
||||
$this->primaryItemTags = [];
|
||||
$this->secondaryItemTags = [];
|
||||
}
|
||||
|
||||
public function isRegistered(Enchantment $enchantment) : bool{
|
||||
return isset($this->enchantments[spl_object_id($enchantment)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns primary compatibility tags for the specified enchantment.
|
||||
*
|
||||
* An item matching at least one of these tags (or its descendents) can be:
|
||||
* - Offered this enchantment in an enchanting table
|
||||
* - Enchanted by any means allowed by secondary tags
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrimaryItemTags(Enchantment $enchantment) : array{
|
||||
return $this->primaryItemTags[spl_object_id($enchantment)] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
*/
|
||||
public function setPrimaryItemTags(Enchantment $enchantment, array $tags) : void{
|
||||
if(!$this->isRegistered($enchantment)){
|
||||
throw new \LogicException("Cannot set primary item tags for non-registered enchantment");
|
||||
}
|
||||
$this->primaryItemTags[spl_object_id($enchantment)] = array_values($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns secondary compatibility tags for the specified enchantment.
|
||||
*
|
||||
* An item matching at least one of these tags (or its descendents) can be:
|
||||
* - Combined with an enchanted book with this enchantment in an anvil
|
||||
* - Obtained as loot with this enchantment, e.g. fishing, treasure chests, mob equipment, etc.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSecondaryItemTags(Enchantment $enchantment) : array{
|
||||
return $this->secondaryItemTags[spl_object_id($enchantment)] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
*/
|
||||
public function setSecondaryItemTags(Enchantment $enchantment, array $tags) : void{
|
||||
if(!$this->isRegistered($enchantment)){
|
||||
throw new \LogicException("Cannot set secondary item tags for non-registered enchantment");
|
||||
}
|
||||
$this->secondaryItemTags[spl_object_id($enchantment)] = array_values($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns enchantments that can be applied to the specified item in an enchanting table (primary only).
|
||||
*
|
||||
* @return Enchantment[]
|
||||
*/
|
||||
public function getPrimaryEnchantmentsForItem(Item $item) : array{
|
||||
$itemTags = $item->getEnchantmentTags();
|
||||
if(count($itemTags) === 0 || $item->hasEnchantments()){
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_filter(
|
||||
$this->enchantments,
|
||||
fn(Enchantment $e) => TagRegistry::getInstance()->isTagArrayIntersection($this->getPrimaryItemTags($e), $itemTags)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available enchantments compatible with the item.
|
||||
*
|
||||
* Warning: not suitable for obtaining enchantments for an enchanting table
|
||||
* (use {@link AvailableEnchantmentRegistry::getPrimaryEnchantmentsForItem()} for that).
|
||||
*
|
||||
* @return Enchantment[]
|
||||
*/
|
||||
public function getAllEnchantmentsForItem(Item $item) : array{
|
||||
if(count($item->getEnchantmentTags()) === 0){
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_filter(
|
||||
$this->enchantments,
|
||||
fn(Enchantment $enchantment) => $this->isAvailableForItem($enchantment, $item)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified enchantment can be applied to the particular item.
|
||||
*
|
||||
* Warning: not suitable for checking the availability of enchantment for an enchanting table.
|
||||
*/
|
||||
public function isAvailableForItem(Enchantment $enchantment, Item $item) : bool{
|
||||
$itemTags = $item->getEnchantmentTags();
|
||||
$tagRegistry = TagRegistry::getInstance();
|
||||
|
||||
return $tagRegistry->isTagArrayIntersection($this->getPrimaryItemTags($enchantment), $itemTags) ||
|
||||
$tagRegistry->isTagArrayIntersection($this->getSecondaryItemTags($enchantment), $itemTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Enchantment[]
|
||||
*/
|
||||
public function getAll() : array{
|
||||
return $this->enchantments;
|
||||
}
|
||||
}
|
66
src/item/enchantment/EnchantOption.php
Normal file
66
src/item/enchantment/EnchantOption.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?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\item\enchantment;
|
||||
|
||||
/**
|
||||
* Represents an option on the enchanting table menu.
|
||||
* If selected, all the enchantments in the option will be applied to the item.
|
||||
*/
|
||||
class EnchantOption{
|
||||
|
||||
/**
|
||||
* @param EnchantmentInstance[] $enchantments
|
||||
*/
|
||||
public function __construct(
|
||||
private int $requiredXpLevel,
|
||||
private string $displayName,
|
||||
private array $enchantments
|
||||
){}
|
||||
|
||||
/**
|
||||
* Returns the minimum amount of XP levels required to select this enchantment option.
|
||||
* It's NOT the number of XP levels that will be subtracted after enchanting.
|
||||
*/
|
||||
public function getRequiredXpLevel() : int{
|
||||
return $this->requiredXpLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name that will be translated to the 'Standard Galactic Alphabet' client-side.
|
||||
* This can be any arbitrary text string, since the vanilla client cannot read the text anyway.
|
||||
* Example: 'bless creature range free'.
|
||||
*/
|
||||
public function getDisplayName() : string{
|
||||
return $this->displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enchantments that will be applied to the item when this option is clicked.
|
||||
*
|
||||
* @return EnchantmentInstance[]
|
||||
*/
|
||||
public function getEnchantments() : array{
|
||||
return $this->enchantments;
|
||||
}
|
||||
}
|
@ -23,9 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item\enchantment;
|
||||
|
||||
use DaveRandom\CallbackValidator\CallbackType;
|
||||
use DaveRandom\CallbackValidator\ParameterType;
|
||||
use DaveRandom\CallbackValidator\ReturnType;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\utils\NotCloneable;
|
||||
use pocketmine\utils\NotSerializable;
|
||||
use pocketmine\utils\Utils;
|
||||
|
||||
/**
|
||||
* Manages enchantment type data.
|
||||
@ -34,13 +38,32 @@ class Enchantment{
|
||||
use NotCloneable;
|
||||
use NotSerializable;
|
||||
|
||||
/** @var \Closure(int $level) : int $minEnchantingPower */
|
||||
private \Closure $minEnchantingPower;
|
||||
|
||||
/**
|
||||
* @phpstan-param null|(\Closure(int $level) : int) $minEnchantingPower
|
||||
*
|
||||
* @param int $primaryItemFlags @deprecated
|
||||
* @param int $secondaryItemFlags @deprecated
|
||||
* @param int $enchantingPowerRange Value used to calculate the maximum enchanting power (minEnchantingPower + enchantingPowerRange)
|
||||
*/
|
||||
public function __construct(
|
||||
private Translatable|string $name,
|
||||
private int $rarity,
|
||||
private int $primaryItemFlags,
|
||||
private int $secondaryItemFlags,
|
||||
private int $maxLevel
|
||||
){}
|
||||
private int $maxLevel,
|
||||
?\Closure $minEnchantingPower = null,
|
||||
private int $enchantingPowerRange = 50
|
||||
){
|
||||
$this->minEnchantingPower = $minEnchantingPower ?? fn(int $level) : int => 1;
|
||||
|
||||
Utils::validateCallableSignature(new CallbackType(
|
||||
new ReturnType("int"),
|
||||
new ParameterType("level", "int")
|
||||
), $this->minEnchantingPower);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a translation key for this enchantment's name.
|
||||
@ -58,6 +81,8 @@ class Enchantment{
|
||||
|
||||
/**
|
||||
* Returns a bitset indicating what item types can have this item applied from an enchanting table.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function getPrimaryItemFlags() : int{
|
||||
return $this->primaryItemFlags;
|
||||
@ -66,6 +91,8 @@ class Enchantment{
|
||||
/**
|
||||
* Returns a bitset indicating what item types cannot have this item applied from an enchanting table, but can from
|
||||
* an anvil.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function getSecondaryItemFlags() : int{
|
||||
return $this->secondaryItemFlags;
|
||||
@ -73,6 +100,8 @@ class Enchantment{
|
||||
|
||||
/**
|
||||
* Returns whether this enchantment can apply to the item type from an enchanting table.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function hasPrimaryItemType(int $flag) : bool{
|
||||
return ($this->primaryItemFlags & $flag) !== 0;
|
||||
@ -80,6 +109,8 @@ class Enchantment{
|
||||
|
||||
/**
|
||||
* Returns whether this enchantment can apply to the item type from an anvil, if it is not a primary item.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function hasSecondaryItemType(int $flag) : bool{
|
||||
return ($this->secondaryItemFlags & $flag) !== 0;
|
||||
@ -92,5 +123,34 @@ class Enchantment{
|
||||
return $this->maxLevel;
|
||||
}
|
||||
|
||||
//TODO: methods for min/max XP cost bounds based on enchantment level (not needed yet - enchanting is client-side)
|
||||
/**
|
||||
* Returns whether this enchantment can be applied to the item along with the given enchantment.
|
||||
*/
|
||||
public function isCompatibleWith(Enchantment $other) : bool{
|
||||
return IncompatibleEnchantmentRegistry::getInstance()->areCompatible($this, $other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum enchanting power value required for the particular level of the enchantment
|
||||
* to be available in an enchanting table.
|
||||
*
|
||||
* Enchanting power is a random value based on the number of bookshelves around an enchanting table
|
||||
* and the enchantability of the item being enchanted. It is only used when determining the available
|
||||
* enchantments for the enchantment options.
|
||||
*/
|
||||
public function getMinEnchantingPower(int $level) : int{
|
||||
return ($this->minEnchantingPower)($level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum enchanting power value allowed for the particular level of the enchantment
|
||||
* to be available in an enchanting table.
|
||||
*
|
||||
* Enchanting power is a random value based on the number of bookshelves around an enchanting table
|
||||
* and the enchantability of the item being enchanted. It is only used when determining the available
|
||||
* enchantments for the enchantment options.
|
||||
*/
|
||||
public function getMaxEnchantingPower(int $level) : int{
|
||||
return $this->getMinEnchantingPower($level) + $this->enchantingPowerRange;
|
||||
}
|
||||
}
|
||||
|
217
src/item/enchantment/EnchantmentHelper.php
Normal file
217
src/item/enchantment/EnchantmentHelper.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?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\item\enchantment;
|
||||
|
||||
use pocketmine\block\BlockTypeIds;
|
||||
use pocketmine\item\enchantment\AvailableEnchantmentRegistry as EnchantmentRegistry;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\item\VanillaItems as Items;
|
||||
use pocketmine\utils\Random;
|
||||
use pocketmine\world\Position;
|
||||
use function abs;
|
||||
use function array_filter;
|
||||
use function chr;
|
||||
use function count;
|
||||
use function floor;
|
||||
use function max;
|
||||
use function min;
|
||||
use function ord;
|
||||
use function round;
|
||||
|
||||
final class EnchantmentHelper{
|
||||
private const MAX_BOOKSHELF_COUNT = 15;
|
||||
|
||||
/**
|
||||
* @param EnchantmentInstance[] $enchantments
|
||||
*/
|
||||
public static function enchantItem(Item $item, array $enchantments) : Item{
|
||||
$resultItem = $item->getTypeId() === ItemTypeIds::BOOK ? Items::ENCHANTED_BOOK() : clone $item;
|
||||
|
||||
foreach($enchantments as $enchantment){
|
||||
$resultItem->addEnchantment($enchantment);
|
||||
}
|
||||
|
||||
return $resultItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EnchantOption[]
|
||||
*/
|
||||
public static function getEnchantOptions(Position $tablePos, Item $input, int $seed) : array{
|
||||
if($input->isNull() || $input->hasEnchantments()){
|
||||
return [];
|
||||
}
|
||||
|
||||
$random = new Random($seed);
|
||||
|
||||
$bookshelfCount = self::countBookshelves($tablePos);
|
||||
$baseRequiredLevel = $random->nextRange(1, 8) + ($bookshelfCount >> 1) + $random->nextRange(0, $bookshelfCount);
|
||||
$topRequiredLevel = (int) floor(max($baseRequiredLevel / 3, 1));
|
||||
$middleRequiredLevel = (int) floor($baseRequiredLevel * 2 / 3 + 1);
|
||||
$bottomRequiredLevel = max($baseRequiredLevel, $bookshelfCount * 2);
|
||||
|
||||
return [
|
||||
self::createEnchantOption($random, $input, $topRequiredLevel),
|
||||
self::createEnchantOption($random, $input, $middleRequiredLevel),
|
||||
self::createEnchantOption($random, $input, $bottomRequiredLevel),
|
||||
];
|
||||
}
|
||||
|
||||
private static function countBookshelves(Position $tablePos) : int{
|
||||
$bookshelfCount = 0;
|
||||
$world = $tablePos->getWorld();
|
||||
|
||||
for($x = -2; $x <= 2; $x++){
|
||||
for($z = -2; $z <= 2; $z++){
|
||||
// We only check blocks at a distance of 2 blocks from the enchanting table
|
||||
if(abs($x) !== 2 && abs($z) !== 2){
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure the space between the bookshelf stack at this X/Z and the enchanting table is empty
|
||||
for($y = 0; $y <= 1; $y++){
|
||||
// Calculate the coordinates of the space between the bookshelf and the enchanting table
|
||||
$spaceX = max(min($x, 1), -1);
|
||||
$spaceZ = max(min($z, 1), -1);
|
||||
$spaceBlock = $world->getBlock($tablePos->add($spaceX, $y, $spaceZ));
|
||||
if($spaceBlock->getTypeId() !== BlockTypeIds::AIR){
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, check the number of bookshelves at the current position
|
||||
for($y = 0; $y <= 1; $y++){
|
||||
$block = $world->getBlock($tablePos->add($x, $y, $z));
|
||||
if($block->getTypeId() === BlockTypeIds::BOOKSHELF){
|
||||
$bookshelfCount++;
|
||||
if($bookshelfCount === self::MAX_BOOKSHELF_COUNT){
|
||||
return $bookshelfCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $bookshelfCount;
|
||||
}
|
||||
|
||||
private static function createEnchantOption(Random $random, Item $inputItem, int $requiredXpLevel) : EnchantOption{
|
||||
$enchantingPower = $requiredXpLevel;
|
||||
|
||||
$enchantability = $inputItem->getEnchantability();
|
||||
$enchantingPower = $enchantingPower + $random->nextRange(0, $enchantability >> 2) + $random->nextRange(0, $enchantability >> 2) + 1;
|
||||
// Random bonus for enchanting power between 0.85 and 1.15
|
||||
$bonus = 1 + ($random->nextFloat() + $random->nextFloat() - 1) * 0.15;
|
||||
$enchantingPower = (int) round($enchantingPower * $bonus);
|
||||
|
||||
$resultEnchantments = [];
|
||||
$availableEnchantments = self::getAvailableEnchantments($enchantingPower, $inputItem);
|
||||
|
||||
$lastEnchantment = self::getRandomWeightedEnchantment($random, $availableEnchantments);
|
||||
if($lastEnchantment !== null){
|
||||
$resultEnchantments[] = $lastEnchantment;
|
||||
|
||||
// With probability (power + 1) / 50, continue adding enchantments
|
||||
while($random->nextFloat() <= ($enchantingPower + 1) / 50){
|
||||
// Remove from the list of available enchantments anything that conflicts
|
||||
// with previously-chosen enchantments
|
||||
$availableEnchantments = array_filter(
|
||||
$availableEnchantments,
|
||||
function(EnchantmentInstance $e) use ($lastEnchantment){
|
||||
return $e->getType() !== $lastEnchantment->getType() &&
|
||||
$e->getType()->isCompatibleWith($lastEnchantment->getType());
|
||||
}
|
||||
);
|
||||
|
||||
$lastEnchantment = self::getRandomWeightedEnchantment($random, $availableEnchantments);
|
||||
if($lastEnchantment === null){
|
||||
break;
|
||||
}
|
||||
|
||||
$resultEnchantments[] = $lastEnchantment;
|
||||
$enchantingPower >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return new EnchantOption($requiredXpLevel, self::getRandomOptionName($random), $resultEnchantments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EnchantmentInstance[]
|
||||
*/
|
||||
private static function getAvailableEnchantments(int $enchantingPower, Item $item) : array{
|
||||
$list = [];
|
||||
|
||||
foreach(EnchantmentRegistry::getInstance()->getPrimaryEnchantmentsForItem($item) as $enchantment){
|
||||
for($lvl = $enchantment->getMaxLevel(); $lvl > 0; $lvl--){
|
||||
if($enchantingPower >= $enchantment->getMinEnchantingPower($lvl) &&
|
||||
$enchantingPower <= $enchantment->getMaxEnchantingPower($lvl)
|
||||
){
|
||||
$list[] = new EnchantmentInstance($enchantment, $lvl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EnchantmentInstance[] $enchantments
|
||||
*/
|
||||
private static function getRandomWeightedEnchantment(Random $random, array $enchantments) : ?EnchantmentInstance{
|
||||
if(count($enchantments) === 0){
|
||||
return null;
|
||||
}
|
||||
|
||||
$totalWeight = 0;
|
||||
foreach($enchantments as $enchantment){
|
||||
$totalWeight += $enchantment->getType()->getRarity();
|
||||
}
|
||||
|
||||
$result = null;
|
||||
$randomWeight = $random->nextRange(1, $totalWeight);
|
||||
|
||||
foreach($enchantments as $enchantment){
|
||||
$randomWeight -= $enchantment->getType()->getRarity();
|
||||
|
||||
if($randomWeight <= 0){
|
||||
$result = $enchantment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function getRandomOptionName(Random $random) : string{
|
||||
$name = "";
|
||||
for($i = $random->nextRange(5, 15); $i > 0; $i--){
|
||||
$name .= chr($random->nextRange(ord("a"), ord("z")));
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
34
src/item/enchantment/IncompatibleEnchantmentGroups.php
Normal file
34
src/item/enchantment/IncompatibleEnchantmentGroups.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?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\item\enchantment;
|
||||
|
||||
/**
|
||||
* Constants for groupings of incompatible enchantments.
|
||||
* Enchantments belonging to the same incompatibility group cannot be applied side-by-side on the same item.
|
||||
*/
|
||||
final class IncompatibleEnchantmentGroups{
|
||||
public const PROTECTION = "protection";
|
||||
public const BOW_INFINITE = "bow_infinite";
|
||||
public const DIG_DROP = "dig_drop";
|
||||
}
|
94
src/item/enchantment/IncompatibleEnchantmentRegistry.php
Normal file
94
src/item/enchantment/IncompatibleEnchantmentRegistry.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?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\item\enchantment;
|
||||
|
||||
use pocketmine\item\enchantment\IncompatibleEnchantmentGroups as Groups;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments as Enchantments;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use function array_intersect_key;
|
||||
use function count;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* Manages which enchantments are incompatible with each other.
|
||||
* Enchantments can be added to groups to make them incompatible with all other enchantments already in that group.
|
||||
*/
|
||||
final class IncompatibleEnchantmentRegistry{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @phpstan-var array<int, array<string, true>>
|
||||
* @var true[][]
|
||||
*/
|
||||
private array $incompatibilityMap = [];
|
||||
|
||||
private function __construct(){
|
||||
$this->register(Groups::PROTECTION, [Enchantments::PROTECTION(), Enchantments::FIRE_PROTECTION(), Enchantments::BLAST_PROTECTION(), Enchantments::PROJECTILE_PROTECTION()]);
|
||||
$this->register(Groups::BOW_INFINITE, [Enchantments::INFINITY(), Enchantments::MENDING()]);
|
||||
$this->register(Groups::DIG_DROP, [Enchantments::FORTUNE(), Enchantments::SILK_TOUCH()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register incompatibility for an enchantment group.
|
||||
*
|
||||
* All enchantments belonging to the same group are incompatible with each other,
|
||||
* i.e. they cannot be added together on the same item.
|
||||
*
|
||||
* @param Enchantment[] $enchantments
|
||||
*/
|
||||
public function register(string $tag, array $enchantments) : void{
|
||||
foreach($enchantments as $enchantment){
|
||||
$this->incompatibilityMap[spl_object_id($enchantment)][$tag] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister incompatibility for some enchantments of a particular group.
|
||||
*
|
||||
* @param Enchantment[] $enchantments
|
||||
*/
|
||||
public function unregister(string $tag, array $enchantments) : void{
|
||||
foreach($enchantments as $enchantment){
|
||||
unset($this->incompatibilityMap[spl_object_id($enchantment)][$tag]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister incompatibility for all enchantments of a particular group.
|
||||
*/
|
||||
public function unregisterAll(string $tag) : void{
|
||||
foreach($this->incompatibilityMap as $id => $tags){
|
||||
unset($this->incompatibilityMap[$id][$tag]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether two enchantments can be applied to the same item.
|
||||
*/
|
||||
public function areCompatible(Enchantment $first, Enchantment $second) : bool{
|
||||
$firstIncompatibilities = $this->incompatibilityMap[spl_object_id($first)] ?? [];
|
||||
$secondIncompatibilities = $this->incompatibilityMap[spl_object_id($second)] ?? [];
|
||||
return count(array_intersect_key($firstIncompatibilities, $secondIncompatibilities)) === 0;
|
||||
}
|
||||
}
|
190
src/item/enchantment/ItemEnchantmentTagRegistry.php
Normal file
190
src/item/enchantment/ItemEnchantmentTagRegistry.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?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\item\enchantment;
|
||||
|
||||
use pocketmine\item\enchantment\ItemEnchantmentTags as Tags;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_diff;
|
||||
use function array_intersect;
|
||||
use function array_merge;
|
||||
use function array_search;
|
||||
use function array_shift;
|
||||
use function array_unique;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Manages known item enchantment tags and the relations between them.
|
||||
* Used to determine which tags belong to which other tags, and to check if lists of tags intersect.
|
||||
*/
|
||||
final class ItemEnchantmentTagRegistry{
|
||||
use SingletonTrait;
|
||||
|
||||
/**
|
||||
* @phpstan-var array<string, list<string>>
|
||||
* @var string[][]
|
||||
*/
|
||||
private array $tagMap = [];
|
||||
|
||||
private function __construct(){
|
||||
$this->register(Tags::ARMOR, [Tags::HELMET, Tags::CHESTPLATE, Tags::LEGGINGS, Tags::BOOTS]);
|
||||
$this->register(Tags::SHIELD);
|
||||
$this->register(Tags::SWORD);
|
||||
$this->register(Tags::TRIDENT);
|
||||
$this->register(Tags::BOW);
|
||||
$this->register(Tags::CROSSBOW);
|
||||
$this->register(Tags::SHEARS);
|
||||
$this->register(Tags::FLINT_AND_STEEL);
|
||||
$this->register(Tags::DIG_TOOLS, [Tags::AXE, Tags::PICKAXE, Tags::SHOVEL, Tags::HOE]);
|
||||
$this->register(Tags::FISHING_ROD);
|
||||
$this->register(Tags::CARROT_ON_STICK);
|
||||
$this->register(Tags::COMPASS);
|
||||
$this->register(Tags::MASK);
|
||||
$this->register(Tags::ELYTRA);
|
||||
$this->register(Tags::BRUSH);
|
||||
$this->register(Tags::WEAPONS, [
|
||||
Tags::SWORD,
|
||||
Tags::TRIDENT,
|
||||
Tags::BOW,
|
||||
Tags::CROSSBOW,
|
||||
Tags::DIG_TOOLS,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register tag and its nested tags.
|
||||
*
|
||||
* @param string[] $nestedTags
|
||||
*/
|
||||
public function register(string $tag, array $nestedTags = []) : void{
|
||||
$this->assertNotInternalTag($tag);
|
||||
|
||||
foreach($nestedTags as $nestedTag){
|
||||
if(!isset($this->tagMap[$nestedTag])){
|
||||
$this->register($nestedTag);
|
||||
}
|
||||
$this->tagMap[$tag][] = $nestedTag;
|
||||
}
|
||||
|
||||
if(!isset($this->tagMap[$tag])){
|
||||
$this->tagMap[$tag] = [];
|
||||
$this->tagMap[Tags::ALL][] = $tag;
|
||||
}
|
||||
}
|
||||
|
||||
public function unregister(string $tag) : void{
|
||||
if(!isset($this->tagMap[$tag])){
|
||||
return;
|
||||
}
|
||||
$this->assertNotInternalTag($tag);
|
||||
|
||||
unset($this->tagMap[$tag]);
|
||||
|
||||
foreach(Utils::stringifyKeys($this->tagMap) as $key => $nestedTags){
|
||||
if(($nestedKey = array_search($tag, $nestedTags, true)) !== false){
|
||||
unset($this->tagMap[$key][$nestedKey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove specified nested tags.
|
||||
*
|
||||
* @param string[] $nestedTags
|
||||
*/
|
||||
public function removeNested(string $tag, array $nestedTags) : void{
|
||||
$this->assertNotInternalTag($tag);
|
||||
$this->tagMap[$tag] = array_diff($this->tagMap[$tag], $nestedTags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns nested tags of a particular tag.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNested(string $tag) : array{
|
||||
return $this->tagMap[$tag] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $firstTags
|
||||
* @param string[] $secondTags
|
||||
*/
|
||||
public function isTagArrayIntersection(array $firstTags, array $secondTags) : bool{
|
||||
if(count($firstTags) === 0 || count($secondTags) === 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$firstLeafTags = $this->getLeafTagsForArray($firstTags);
|
||||
$secondLeafTags = $this->getLeafTagsForArray($secondTags);
|
||||
|
||||
return count(array_intersect($firstLeafTags, $secondLeafTags)) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all tags that are recursively nested within each tag in the array and do not have any nested tags.
|
||||
*
|
||||
* @param string[] $tags
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function getLeafTagsForArray(array $tags) : array{
|
||||
$leafTagArrays = [];
|
||||
foreach($tags as $tag){
|
||||
$leafTagArrays[] = $this->getLeafTags($tag);
|
||||
}
|
||||
return array_unique(array_merge(...$leafTagArrays));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all tags that are recursively nested within the given tag and do not have any nested tags.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function getLeafTags(string $tag) : array{
|
||||
$result = [];
|
||||
$tagsToHandle = [$tag];
|
||||
|
||||
while(count($tagsToHandle) !== 0){
|
||||
$currentTag = array_shift($tagsToHandle);
|
||||
$nestedTags = $this->getNested($currentTag);
|
||||
|
||||
if(count($nestedTags) === 0){
|
||||
$result[] = $currentTag;
|
||||
}else{
|
||||
$tagsToHandle = array_merge($tagsToHandle, $nestedTags);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function assertNotInternalTag(string $tag) : void{
|
||||
if($tag === Tags::ALL){
|
||||
throw new \InvalidArgumentException(
|
||||
"Cannot perform any operations on the internal item enchantment tag '$tag'"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
57
src/item/enchantment/ItemEnchantmentTags.php
Normal file
57
src/item/enchantment/ItemEnchantmentTags.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?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\item\enchantment;
|
||||
|
||||
/**
|
||||
* Tags used by items and enchantments to determine which enchantments can be applied to which items.
|
||||
* Some tags may contain other tags.
|
||||
* @see ItemEnchantmentTagRegistry
|
||||
*/
|
||||
final class ItemEnchantmentTags{
|
||||
public const ALL = "all";
|
||||
public const ARMOR = "armor";
|
||||
public const HELMET = "helmet";
|
||||
public const CHESTPLATE = "chestplate";
|
||||
public const LEGGINGS = "leggings";
|
||||
public const BOOTS = "boots";
|
||||
public const SHIELD = "shield";
|
||||
public const SWORD = "sword";
|
||||
public const TRIDENT = "trident";
|
||||
public const BOW = "bow";
|
||||
public const CROSSBOW = "crossbow";
|
||||
public const SHEARS = "shears";
|
||||
public const FLINT_AND_STEEL = "flint_and_steel";
|
||||
public const DIG_TOOLS = "dig_tools";
|
||||
public const AXE = "axe";
|
||||
public const PICKAXE = "pickaxe";
|
||||
public const SHOVEL = "shovel";
|
||||
public const HOE = "hoe";
|
||||
public const FISHING_ROD = "fishing_rod";
|
||||
public const CARROT_ON_STICK = "carrot_on_stick";
|
||||
public const COMPASS = "compass";
|
||||
public const MASK = "mask";
|
||||
public const ELYTRA = "elytra";
|
||||
public const BRUSH = "brush";
|
||||
public const WEAPONS = "weapons";
|
||||
}
|
@ -23,14 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item\enchantment;
|
||||
|
||||
/** @deprecated */
|
||||
final class ItemFlags{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
//TODO: this should probably move to protocol
|
||||
|
||||
public const NONE = 0x0;
|
||||
public const ALL = 0xffff;
|
||||
public const ARMOR = self::HEAD | self::TORSO | self::LEGS | self::FEET;
|
||||
|
@ -36,10 +36,15 @@ class ProtectionEnchantment extends Enchantment{
|
||||
/**
|
||||
* ProtectionEnchantment constructor.
|
||||
*
|
||||
* @phpstan-param null|(\Closure(int $level) : int) $minEnchantingPower
|
||||
*
|
||||
* @param int $primaryItemFlags @deprecated
|
||||
* @param int $secondaryItemFlags @deprecated
|
||||
* @param int[]|null $applicableDamageTypes EntityDamageEvent::CAUSE_* constants which this enchantment type applies to, or null if it applies to all types of damage.
|
||||
* @param int $enchantingPowerRange Value used to calculate the maximum enchanting power (minEnchantingPower + enchantingPowerRange)
|
||||
*/
|
||||
public function __construct(Translatable|string $name, int $rarity, int $primaryItemFlags, int $secondaryItemFlags, int $maxLevel, float $typeModifier, ?array $applicableDamageTypes){
|
||||
parent::__construct($name, $rarity, $primaryItemFlags, $secondaryItemFlags, $maxLevel);
|
||||
public function __construct(Translatable|string $name, int $rarity, int $primaryItemFlags, int $secondaryItemFlags, int $maxLevel, float $typeModifier, ?array $applicableDamageTypes, ?\Closure $minEnchantingPower = null, int $enchantingPowerRange = 50){
|
||||
parent::__construct($name, $rarity, $primaryItemFlags, $secondaryItemFlags, $maxLevel, $minEnchantingPower, $enchantingPowerRange);
|
||||
|
||||
$this->typeModifier = $typeModifier;
|
||||
if($applicableDamageTypes !== null){
|
||||
|
@ -59,47 +59,224 @@ final class VanillaEnchantments{
|
||||
use RegistryTrait;
|
||||
|
||||
protected static function setup() : void{
|
||||
self::register("PROTECTION", new ProtectionEnchantment(KnownTranslationFactory::enchantment_protect_all(), Rarity::COMMON, ItemFlags::ARMOR, ItemFlags::NONE, 4, 0.75, null));
|
||||
self::register("FIRE_PROTECTION", new ProtectionEnchantment(KnownTranslationFactory::enchantment_protect_fire(), Rarity::UNCOMMON, ItemFlags::ARMOR, ItemFlags::NONE, 4, 1.25, [
|
||||
EntityDamageEvent::CAUSE_FIRE,
|
||||
EntityDamageEvent::CAUSE_FIRE_TICK,
|
||||
EntityDamageEvent::CAUSE_LAVA
|
||||
//TODO: check fireballs
|
||||
]));
|
||||
self::register("FEATHER_FALLING", new ProtectionEnchantment(KnownTranslationFactory::enchantment_protect_fall(), Rarity::UNCOMMON, ItemFlags::FEET, ItemFlags::NONE, 4, 2.5, [
|
||||
EntityDamageEvent::CAUSE_FALL
|
||||
]));
|
||||
self::register("BLAST_PROTECTION", new ProtectionEnchantment(KnownTranslationFactory::enchantment_protect_explosion(), Rarity::RARE, ItemFlags::ARMOR, ItemFlags::NONE, 4, 1.5, [
|
||||
EntityDamageEvent::CAUSE_BLOCK_EXPLOSION,
|
||||
EntityDamageEvent::CAUSE_ENTITY_EXPLOSION
|
||||
]));
|
||||
self::register("PROJECTILE_PROTECTION", new ProtectionEnchantment(KnownTranslationFactory::enchantment_protect_projectile(), Rarity::UNCOMMON, ItemFlags::ARMOR, ItemFlags::NONE, 4, 1.5, [
|
||||
EntityDamageEvent::CAUSE_PROJECTILE
|
||||
]));
|
||||
self::register("THORNS", new Enchantment(KnownTranslationFactory::enchantment_thorns(), Rarity::MYTHIC, ItemFlags::TORSO, ItemFlags::HEAD | ItemFlags::LEGS | ItemFlags::FEET, 3));
|
||||
self::register("RESPIRATION", new Enchantment(KnownTranslationFactory::enchantment_oxygen(), Rarity::RARE, ItemFlags::HEAD, ItemFlags::NONE, 3));
|
||||
self::register("PROTECTION", new ProtectionEnchantment(
|
||||
KnownTranslationFactory::enchantment_protect_all(),
|
||||
Rarity::COMMON,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
0.75,
|
||||
null,
|
||||
fn(int $level) : int => 11 * ($level - 1) + 1,
|
||||
20
|
||||
));
|
||||
self::register("FIRE_PROTECTION", new ProtectionEnchantment(
|
||||
KnownTranslationFactory::enchantment_protect_fire(),
|
||||
Rarity::UNCOMMON,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
1.25,
|
||||
[
|
||||
EntityDamageEvent::CAUSE_FIRE,
|
||||
EntityDamageEvent::CAUSE_FIRE_TICK,
|
||||
EntityDamageEvent::CAUSE_LAVA
|
||||
//TODO: check fireballs
|
||||
],
|
||||
fn(int $level) : int => 8 * ($level - 1) + 10,
|
||||
12
|
||||
));
|
||||
self::register("FEATHER_FALLING", new ProtectionEnchantment(
|
||||
KnownTranslationFactory::enchantment_protect_fall(),
|
||||
Rarity::UNCOMMON,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
2.5,
|
||||
[
|
||||
EntityDamageEvent::CAUSE_FALL
|
||||
],
|
||||
fn(int $level) : int => 6 * ($level - 1) + 5,
|
||||
10
|
||||
));
|
||||
self::register("BLAST_PROTECTION", new ProtectionEnchantment(
|
||||
KnownTranslationFactory::enchantment_protect_explosion(),
|
||||
Rarity::RARE,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
1.5,
|
||||
[
|
||||
EntityDamageEvent::CAUSE_BLOCK_EXPLOSION,
|
||||
EntityDamageEvent::CAUSE_ENTITY_EXPLOSION
|
||||
],
|
||||
fn(int $level) : int => 8 * ($level - 1) + 5,
|
||||
12
|
||||
));
|
||||
self::register("PROJECTILE_PROTECTION", new ProtectionEnchantment(
|
||||
KnownTranslationFactory::enchantment_protect_projectile(),
|
||||
Rarity::UNCOMMON,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
1.5,
|
||||
[
|
||||
EntityDamageEvent::CAUSE_PROJECTILE
|
||||
],
|
||||
fn(int $level) : int => 6 * ($level - 1) + 3,
|
||||
15
|
||||
));
|
||||
self::register("THORNS", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_thorns(),
|
||||
Rarity::MYTHIC,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
fn(int $level) : int => 20 * ($level - 1) + 10,
|
||||
50
|
||||
));
|
||||
self::register("RESPIRATION", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_oxygen(),
|
||||
Rarity::RARE,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
fn(int $level) : int => 10 * $level,
|
||||
30
|
||||
));
|
||||
|
||||
self::register("SHARPNESS", new SharpnessEnchantment(KnownTranslationFactory::enchantment_damage_all(), Rarity::COMMON, ItemFlags::SWORD, ItemFlags::AXE, 5));
|
||||
//TODO: smite, bane of arthropods (these don't make sense now because their applicable mobs don't exist yet)
|
||||
self::register("SHARPNESS", new SharpnessEnchantment(
|
||||
KnownTranslationFactory::enchantment_damage_all(),
|
||||
Rarity::COMMON,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
fn(int $level) : int => 11 * ($level - 1) + 1,
|
||||
20
|
||||
));
|
||||
self::register("KNOCKBACK", new KnockbackEnchantment(
|
||||
KnownTranslationFactory::enchantment_knockback(),
|
||||
Rarity::UNCOMMON,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
fn(int $level) : int => 20 * ($level - 1) + 5,
|
||||
50
|
||||
));
|
||||
self::register("FIRE_ASPECT", new FireAspectEnchantment(
|
||||
KnownTranslationFactory::enchantment_fire(),
|
||||
Rarity::RARE,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
fn(int $level) : int => 20 * ($level - 1) + 10,
|
||||
50
|
||||
));
|
||||
//TODO: smite, bane of arthropods, looting (these don't make sense now because their applicable mobs don't exist yet)
|
||||
|
||||
self::register("KNOCKBACK", new KnockbackEnchantment(KnownTranslationFactory::enchantment_knockback(), Rarity::UNCOMMON, ItemFlags::SWORD, ItemFlags::NONE, 2));
|
||||
self::register("FIRE_ASPECT", new FireAspectEnchantment(KnownTranslationFactory::enchantment_fire(), Rarity::RARE, ItemFlags::SWORD, ItemFlags::NONE, 2));
|
||||
self::register("EFFICIENCY", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_digging(),
|
||||
Rarity::COMMON,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
fn(int $level) : int => 10 * ($level - 1) + 1,
|
||||
50
|
||||
));
|
||||
self::register("FORTUNE", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_lootBonusDigger(),
|
||||
Rarity::RARE,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
fn(int $level) : int => 9 * ($level - 1) + 15,
|
||||
50
|
||||
));
|
||||
self::register("SILK_TOUCH", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_untouching(),
|
||||
Rarity::MYTHIC,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
fn(int $level) : int => 15,
|
||||
50
|
||||
));
|
||||
self::register("UNBREAKING", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_durability(),
|
||||
Rarity::UNCOMMON,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
fn(int $level) : int => 8 * ($level - 1) + 5,
|
||||
50
|
||||
));
|
||||
|
||||
self::register("EFFICIENCY", new Enchantment(KnownTranslationFactory::enchantment_digging(), Rarity::COMMON, ItemFlags::DIG, ItemFlags::SHEARS, 5));
|
||||
self::register("FORTUNE", new Enchantment(KnownTranslationFactory::enchantment_lootBonusDigger(), Rarity::RARE, ItemFlags::DIG, ItemFlags::NONE, 3));
|
||||
self::register("SILK_TOUCH", new Enchantment(KnownTranslationFactory::enchantment_untouching(), Rarity::MYTHIC, ItemFlags::DIG, ItemFlags::SHEARS, 1));
|
||||
self::register("UNBREAKING", new Enchantment(KnownTranslationFactory::enchantment_durability(), Rarity::UNCOMMON, ItemFlags::DIG | ItemFlags::ARMOR | ItemFlags::FISHING_ROD | ItemFlags::BOW, ItemFlags::TOOL | ItemFlags::CARROT_STICK | ItemFlags::ELYTRA, 3));
|
||||
self::register("POWER", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_arrowDamage(),
|
||||
Rarity::COMMON,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
fn(int $level) : int => 10 * ($level - 1) + 1,
|
||||
15
|
||||
));
|
||||
self::register("PUNCH", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_arrowKnockback(),
|
||||
Rarity::RARE,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
fn(int $level) : int => 20 * ($level - 1) + 12,
|
||||
25
|
||||
));
|
||||
self::register("FLAME", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_arrowFire(),
|
||||
Rarity::RARE,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
fn(int $level) : int => 20,
|
||||
30
|
||||
));
|
||||
self::register("INFINITY", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_arrowInfinite(),
|
||||
Rarity::MYTHIC,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
fn(int $level) : int => 20,
|
||||
30
|
||||
));
|
||||
|
||||
self::register("POWER", new Enchantment(KnownTranslationFactory::enchantment_arrowDamage(), Rarity::COMMON, ItemFlags::BOW, ItemFlags::NONE, 5));
|
||||
self::register("PUNCH", new Enchantment(KnownTranslationFactory::enchantment_arrowKnockback(), Rarity::RARE, ItemFlags::BOW, ItemFlags::NONE, 2));
|
||||
self::register("FLAME", new Enchantment(KnownTranslationFactory::enchantment_arrowFire(), Rarity::RARE, ItemFlags::BOW, ItemFlags::NONE, 1));
|
||||
self::register("INFINITY", new Enchantment(KnownTranslationFactory::enchantment_arrowInfinite(), Rarity::MYTHIC, ItemFlags::BOW, ItemFlags::NONE, 1));
|
||||
self::register("MENDING", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_mending(),
|
||||
Rarity::RARE,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
fn(int $level) : int => 25,
|
||||
50
|
||||
));
|
||||
|
||||
self::register("MENDING", new Enchantment(KnownTranslationFactory::enchantment_mending(), Rarity::RARE, ItemFlags::NONE, ItemFlags::ALL, 1));
|
||||
self::register("VANISHING", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_curse_vanishing(),
|
||||
Rarity::MYTHIC,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
fn(int $level) : int => 25,
|
||||
25
|
||||
));
|
||||
|
||||
self::register("VANISHING", new Enchantment(KnownTranslationFactory::enchantment_curse_vanishing(), Rarity::MYTHIC, ItemFlags::NONE, ItemFlags::ALL, 1));
|
||||
|
||||
self::register("SWIFT_SNEAK", new Enchantment(KnownTranslationFactory::enchantment_swift_sneak(), Rarity::MYTHIC, ItemFlags::NONE, ItemFlags::LEGS, 3));
|
||||
self::register("SWIFT_SNEAK", new Enchantment(
|
||||
KnownTranslationFactory::enchantment_swift_sneak(),
|
||||
Rarity::MYTHIC,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
fn(int $level) : int => 10 * $level,
|
||||
5
|
||||
));
|
||||
}
|
||||
|
||||
protected static function register(string $name, Enchantment $member) : void{
|
||||
|
@ -35,9 +35,12 @@ use pocketmine\block\inventory\LoomInventory;
|
||||
use pocketmine\block\inventory\SmithingTableInventory;
|
||||
use pocketmine\block\inventory\StonecutterInventory;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\data\bedrock\EnchantmentIdMap;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\inventory\transaction\action\SlotChangeAction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\item\enchantment\EnchantmentInstance;
|
||||
use pocketmine\item\enchantment\EnchantOption;
|
||||
use pocketmine\network\mcpe\cache\CreativeInventoryCache;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
@ -46,7 +49,10 @@ use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerEnchantOptionsPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\Enchant;
|
||||
use pocketmine\network\mcpe\protocol\types\EnchantOption as ProtocolEnchantOption;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
@ -58,6 +64,7 @@ use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\ObjectSet;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_search;
|
||||
use function count;
|
||||
use function get_class;
|
||||
@ -103,6 +110,12 @@ class InventoryManager{
|
||||
|
||||
private bool $fullSyncRequested = false;
|
||||
|
||||
/** @var int[] network recipe ID => enchanting table option index */
|
||||
private array $enchantingTableOptions = [];
|
||||
//TODO: this should be based on the total number of crafting recipes - if there are ever 100k recipes, this will
|
||||
//conflict with regular recipes
|
||||
private int $nextEnchantingTableOptionId = 100000;
|
||||
|
||||
public function __construct(
|
||||
private Player $player,
|
||||
private NetworkSession $session
|
||||
@ -382,6 +395,7 @@ class InventoryManager{
|
||||
throw new AssumptionFailedError("We should not have opened a new window while a window was waiting to be closed");
|
||||
}
|
||||
$this->pendingCloseWindowId = $this->lastInventoryNetworkId;
|
||||
$this->enchantingTableOptions = [];
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,6 +617,39 @@ class InventoryManager{
|
||||
$this->session->sendDataPacket(CreativeInventoryCache::getInstance()->getCache($this->player->getCreativeInventory()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EnchantOption[] $options
|
||||
*/
|
||||
public function syncEnchantingTableOptions(array $options) : void{
|
||||
$protocolOptions = [];
|
||||
|
||||
foreach($options as $index => $option){
|
||||
$optionId = $this->nextEnchantingTableOptionId++;
|
||||
$this->enchantingTableOptions[$optionId] = $index;
|
||||
|
||||
$protocolEnchantments = array_map(
|
||||
fn(EnchantmentInstance $e) => new Enchant(EnchantmentIdMap::getInstance()->toId($e->getType()), $e->getLevel()),
|
||||
$option->getEnchantments()
|
||||
);
|
||||
// We don't pay attention to the $slotFlags, $heldActivatedEnchantments and $selfActivatedEnchantments
|
||||
// as everything works fine without them (perhaps these values are used somehow in the BDS).
|
||||
$protocolOptions[] = new ProtocolEnchantOption(
|
||||
$option->getRequiredXpLevel(),
|
||||
0, $protocolEnchantments,
|
||||
[],
|
||||
[],
|
||||
$option->getDisplayName(),
|
||||
$optionId
|
||||
);
|
||||
}
|
||||
|
||||
$this->session->sendDataPacket(PlayerEnchantOptionsPacket::create($protocolOptions));
|
||||
}
|
||||
|
||||
public function getEnchantingTableOptionIndex(int $recipeId) : ?int{
|
||||
return $this->enchantingTableOptions[$recipeId] ?? null;
|
||||
}
|
||||
|
||||
private function newItemStackId() : int{
|
||||
return $this->nextItemStackId++;
|
||||
}
|
||||
|
@ -23,11 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use pocketmine\block\inventory\EnchantInventory;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\inventory\transaction\action\CreateItemAction;
|
||||
use pocketmine\inventory\transaction\action\DestroyItemAction;
|
||||
use pocketmine\inventory\transaction\action\DropItemAction;
|
||||
use pocketmine\inventory\transaction\CraftingTransaction;
|
||||
use pocketmine\inventory\transaction\EnchantTransaction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
use pocketmine\inventory\transaction\TransactionBuilder;
|
||||
use pocketmine\inventory\transaction\TransactionBuilderInventory;
|
||||
@ -287,7 +289,7 @@ class ItemStackRequestExecutor{
|
||||
* @throws ItemStackRequestProcessException
|
||||
*/
|
||||
private function assertDoingCrafting() : void{
|
||||
if(!$this->specialTransaction instanceof CraftingTransaction){
|
||||
if(!$this->specialTransaction instanceof CraftingTransaction && !$this->specialTransaction instanceof EnchantTransaction){
|
||||
if($this->specialTransaction === null){
|
||||
throw new ItemStackRequestProcessException("Expected CraftRecipe or CraftRecipeAuto action to precede this action");
|
||||
}else{
|
||||
@ -333,7 +335,16 @@ class ItemStackRequestExecutor{
|
||||
|
||||
$this->setNextCreatedItem($item, true);
|
||||
}elseif($action instanceof CraftRecipeStackRequestAction){
|
||||
$this->beginCrafting($action->getRecipeId(), 1);
|
||||
$window = $this->player->getCurrentWindow();
|
||||
if($window instanceof EnchantInventory){
|
||||
$optionId = $this->inventoryManager->getEnchantingTableOptionIndex($action->getRecipeId());
|
||||
if($optionId !== null && ($option = $window->getOption($optionId)) !== null){
|
||||
$this->specialTransaction = new EnchantTransaction($this->player, $option, $optionId + 1);
|
||||
$this->setNextCreatedItem($window->getOutput($optionId));
|
||||
}
|
||||
}else{
|
||||
$this->beginCrafting($action->getRecipeId(), 1);
|
||||
}
|
||||
}elseif($action instanceof CraftRecipeAutoStackRequestAction){
|
||||
$this->beginCrafting($action->getRecipeId(), $action->getRepetitions());
|
||||
}elseif($action instanceof CraftingConsumeInputStackRequestAction){
|
||||
|
@ -52,9 +52,9 @@ final class GeneratorManager{
|
||||
}
|
||||
});
|
||||
$this->addGenerator(Normal::class, "normal", fn() => null);
|
||||
$this->addGenerator(Normal::class, "default", fn() => null);
|
||||
$this->addGenerator(Nether::class, "hell", fn() => null);
|
||||
$this->addAlias("normal", "default");
|
||||
$this->addGenerator(Nether::class, "nether", fn() => null);
|
||||
$this->addAlias("nether", "hell");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,6 +80,22 @@ final class GeneratorManager{
|
||||
$this->list[$name] = new GeneratorManagerEntry($class, $presetValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aliases an already-registered generator name to another name. Useful if you want to map a generator name to an
|
||||
* existing generator without having to replicate the parameters.
|
||||
*/
|
||||
public function addAlias(string $name, string $alias) : void{
|
||||
$name = strtolower($name);
|
||||
$alias = strtolower($alias);
|
||||
if(!isset($this->list[$name])){
|
||||
throw new \InvalidArgumentException("Alias \"$name\" is not assigned");
|
||||
}
|
||||
if(isset($this->list[$alias])){
|
||||
throw new \InvalidArgumentException("Alias \"$alias\" is already assigned");
|
||||
}
|
||||
$this->list[$alias] = $this->list[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of names for registered generators.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user