For Minecraft: Bedrock Edition 1.19.80
5.0.0 is a major update to PocketMine-MP, including many new features and API changes. It is not compatible with plugins written for previous versions of PocketMine-MP.
Released 1st June 2023.
- Worlds are now saved according to the Bedrock 1.19.80 format.
- Worlds generated by Bedrock from 1.13.0 and up are now supported (previously, only worlds up to 1.12 were supported).
/particle
now accepts strings for particle data instead of integers./particle
no longer accepts integers for block or item IDs.- The usage of
blockcrack
,iconcrack
andblockdust
particle types in/particle
now follows the same pattern as other particle types, with the data for each being passed in thedata
parameter instead of being baked into the particle name. - Commands are now enabled by default in worlds exported from PocketMine-MP to Bedrock.
build/generate-runtime-enum-serializers.php
has been added to generateRuntimeEnumSerializer
,RuntimeEnumSerializerTrait
, andRuntimeEnumSizeCalculatorTrait
.
- Localized disconnect messages are now used in the following cases:
- Server full
- Player not on the server whitelist
- Player on the server ban list
- Invalid skin
- Invalid username
- Kicked using
/kick
- Banned using
/ban
- Failure to find a safe spawn position
- Session open, session close and session player name discovery messages are now localized.
- All permissions now have localized descriptions. These are not currently used by PocketMine-MP, but may be useful for plugins.
- Improved performance of dropping block inventory contents when the block is destroyed.
- Improved light propagation performance by 10-15%.
ext-pmmpthread
version 6.0.0 is now used, featuring significant performance improvements for thread-safe objects and various threading use-cases.
- The following tool scripts have been added:
generate-block-palette-spec.php
- generates a JSON file with a readable overview of blocks, their state properties, and their possible valuesgenerate-blockstate-upgrade-schema.php
- generates JSON blockstate upgrade schemas like those found in BedrockBlockUpgradeSchemagenerate-item-upgrade-schema.php
- generates JSON item ID/meta upgrade schemas like those found in BedrockItemUpgradeSchemagenerate-bedrock-data-from-packets.php
- generates various files for BedrockData- This script accepts a txt file containing base64-encoded packet dumps.
- This script has been used to generate data for for several years, but has only now been open-sourced.
- It's used to generate data such as crafting recipes, creative inventory data, and various other blobs of data needed to support the current version of Minecraft: Bedrock Edition.
- Added the following new blocks:
- Amethyst Block
- Ancient Debris
- Azalea Leaves
- Basalt
- Blackstone blocks, slabs, stairs, and walls
- Cakes with Candle & Dyed Candle
- Calcite
- Candle & Dyed Candle
- Cartography Table (not currently usable due to maps not being implemented)
- Cauldron
- Cave Vines
- Chain
- Chiseled Deepslate
- Chiseled Nether Bricks
- Chiseled Polished Blackstone
- Chorus Flower
- Chorus Plant
- Cobbled Deepslate blocks, slabs, stairs, and walls
- Copper Ore
- Copper block (random oxidation not yet implemented)
- Crached Deepslate Tiles
- Cracked Deepslate Bricks
- Cracked Nether Bricks
- Cracked Polished Blackstone Bricks
- Crimson buttons, doors, fences, fence gates, hyphae, planks, pressure plates, signs, slabs, stairs, stems, and trapdoors
- Crying Obsidian
- Cut Copper block, stairs and slabs (random oxidation not yet implemented)
- Deepslate
- Deepslate Bricks blocks, slabs, stairs, and walls
- Deepslate Ores (coal, copper, diamond, emerald, gold, iron, lapis lazuli, redstone)
- Deepslate Tiles blocks, slabs, stairs, and walls
- Flowering Azalea Leaves
- Froglight (pearlescent, verdant, ochre)
- Gilded Blackstone
- Glow Item Frame
- Hanging Roots
- Honeycomb Block
- Light Block
- Lightning Rod
- Mangrove Leaves
- Mangrove Roots
- Mangrove buttons, doors, fences, fence gates, logs, planks, pressure plates, signs, slabs, stairs, trapdoors, and wood
- Mud Bricks blocks, slabs, stairs, and walls
- Muddy Mangrove Roots
- Nether Gold Ore
- Netherite Block
- Polished Basalt
- Polished Blackstone Bricks blocks, slabs, stairs, and walls
- Polished Blackstone blocks, buttons, pressure plates, slabs, stairs, and walls
- Polished Deepslate blocks, slabs, stairs, and walls
- Quartz Bricks
- Reinforced Deepslate
- Rooted Dirt
- Sculk
- Shroomlight
- Smithing Table
- Smooth Basalt
- Soul Fire
- Soul Lantern
- Soul Soil
- Soul Torch
- Spore Blossom
- Tinted Glass
- Tuff
- Twisting Vines
- Warped Wart Block
- Warped buttons, doors, fences, fence gates, hyphae, planks, pressure plates, signs, slabs, stairs, stems, and trapdoors
- Weeping Vines
- Wither Rose
- Added support for basalt generators
- Added support for dyeing sign text and making it glow.
- All-sided logs ("wood", for want of a better name) can now be placed in X, Y, and Z orientations.
- Coral and coral fans now behave correctly when placed out of water (they no longer immediately die).
- Fixed dead bush being able to be placed on some invalid blocks (e.g. stone).
- Fixed lava setting entities on fire for an incorrect duration (Java vs Bedrock inconsistency).
- Fixed sugarcane not being able to be placed on some blocks.
- Iron Ore and Gold Ore now drop Raw Iron and Raw Gold respectively, instead of the ore blocks.
- Item frames can now be placed on the top and bottom of blocks.
- Stripping logs by right-clicking them with an axe is now supported.
- TNT can now be ignited by fire charges.
- Vines can now only be placed on the side of full-cube blocks.
- Walls now connect when placed, following the pre-1.16 logic. (1.16 logic is planned to be implemented, but currently low priority.)
- Anvils are now damaged when they hit the ground after falling.
- Added missing sounds for anvils hitting the ground after falling.
- Anvils now damage entities when they fall on top of them.
- Added the following new items:
- Amethyst Shard
- Antidote (from Education Edition)
- Copper Ingot
- Disc Fragment (5)
- Echo Shard
- Elixir (from Education Edition)
- Eye Drops (from Education Edition)
- Fire Charge
- Glow Berries
- Glow Ink Sac
- Honey Bottle
- Honeycomb
- Mangrove Boat (incomplete)
- Music Disc (5)
- Music Disc (Otherside)
- Music Disc (Pigstep)
- Netherite Axe
- Netherite Boots
- Netherite Chestplate
- Netherite Helmet
- Netherite Ingot
- Netherite Leggings
- Netherite Pickaxe
- Netherite Scrap
- Netherite Shovel
- Netherite Sword
- Phantom Membrane
- Raw Copper
- Raw Gold
- Raw Iron
- Spyglass
- Suspicious Stew
- Tonic (from Education Edition)
- Glass bottles can now be filled with water by clicking on a water source block.
- Implemented Swift Sneak enchantment.
- Armour durability is now only reduced when the wearer receives a type of damage that the armour can protect against.
- Bells now ring when hit by a projectile.
- World height of -64 to 319 is now supported.
- Added support for 3D biomes. This isn't used by PocketMine-MP yet, but is necessary to be able to fully load 1.18 worlds.
- Union and mixed native parameter, return and property types are now used where appropriate.
- Protected and public properties now use native property types wherever possible.
- Parameter and return typehints have been applied in many places where it wasn't previously possible.
ext-pmmpthread
version 6.0.0 (renamed fromext-pthreads
) is now required. This version features major API changes and improvements. Please read the upgrading guide for details.pocketmine/snooze
version 0.5.0 is now required.pocketmine/raklib
version 0.15.0 is now required.pocketmine/raklib-ipc
version 0.2.0 is now required.pocketmine/classloader
andpocketmine/log-pthreads
packages have been removed. The relevant classes from these packages are now included in-house in thepocketmine/thread
namespace.BaseClassLoader
is replaced withpocketmine\thread\ThreadSafeClassLoader
ThreadedLogger
is replaced bypocketmine\thread\ThreadSafeLogger
AttachableThreadedLogger
is replaced bypocketmine\thread\AttachableThreadSafeLogger
ThreadedLoggerAttachment
is replaced bypocketmine\thread\ThreadSafeLoggerAttachment
webmozart/path-util
has been removed (replaced bysymfony/filesystem
).
- Blocks no longer use internal Minecraft IDs and metadata to identify themselves. All APIs associated with legacy IDs and meta have been removed.
- A new set of runtime IDs generated from
VanillaBlocks
is used to identify block types. These IDs are defined inBlockTypeIds
.- These new IDs are used for runtime representation of blocks on chunks, and for type comparison purposes.
- Block type IDs are used at runtime only. Do not store them in configs or databases, as they are subject to change without warning.
- Block type IDs are specific to PocketMine-MP and have no relation to the IDs used by Minecraft.
- Block type IDs cannot be negative
- Block type IDs must not be reused, even if overriding an already defined block
- Block state properties (e.g. facing, colour, etc.) are now represented by PM-specific state data instead of legacy
metadata. The state data consists of:
- Block-item state properties - retained by items when the block is broken (colour, wet/dry, coral type, etc.) - handled by
Block->describeBlockItemState()
- Block-only state data - discarded when the block is broken (facing direction, lit/unlit, powered/unpowered, etc.) - handled by
Block->describeBlockOnlyState()
- Block-item state properties - retained by items when the block is broken (colour, wet/dry, coral type, etc.) - handled by
- Chunks now store dynamic state ID derived from the runtime type ID and runtime (PocketMine-MP defined) state data.
- Introduced "type tags" concept, which allows marking certain blocks as having certain behaviours.
- The idea for this system was borrowed from the Minecraft Java tags system.
- It's still in very early concept stage, but is currently used for deciding which types of blocks plants can be placed on without needing to enumerate every single ID in every class, eliminating a bunch of boilerplate code and improving consistency.
- All
Block
descendents now acceptBlockTypeInfo
in the constructor, instead ofBlockBreakInfo
. This allows for future additions without needing to change dozens of overridden constructors. &$returnedItems
reference parameter is now used in some places such asBlock->onInteract()
to enable actions to return items to players without caring about whether they are in creative or anything else.- This eliminates boilerplate code of deciding whether to set the player's held item or not, as well as automatically dropping any overflow items that don't fit into the inventory.
- This is currently used when filling/emptying cauldrons using buckets or glass bottles.
- Dependency between
RuntimeBlockStateRegistry
(previouslyBlockFactory
) andVanillaBlocks
has been inverted.- Now, blocks types are defined in
VanillaBlocks
RuntimeBlockStateRegistry
automatically registers states for blocks defined inVanillaBlocks
.- Manual registration in
RuntimeBlockStateRegistry
is still required for custom blocks (see section below about registering new blocks).
- Now, blocks types are defined in
RuntimeBlockStateRegistry
now has only one purpose - to map internal blockstate IDs toBlock
objects when reading blocks from chunks. It should not be used by plugins unless registering new blocks.- To get a block at runtime, e.g. stone, use
VanillaBlocks::STONE()
- To load a block from old config or database data:
- Use
GlobalBlockStateHandlers::getUpgrader()->upgradeIntIdMeta()
to convert it to modern data - Pass the data to
GlobalBlockStateHandlers::getDeserializer()
to get a blockstate ID - Pass the blockstate ID to
RuntimeBlockStateRegistry::fromStateId()
to get aBlock
instance
- Use
- Prefer using
StringToItemParser
wherever possible for configs and databases (seelookupAliases()
andlookupBlockAliases()
).
- To get a block at runtime, e.g. stone, use
To add a vanilla block in a plugin which isn't yet supported by PocketMine-MP, do the following:
- Get a new type ID using
BlockTypeIds::newId()
- you'll want to keep this in a property somewhere if you want to compare usinggetTypeId()
later - Set up the block type somewhere - this can be anywhere you like, e.g. a plugin main class property, but using
a
RegistryTrait
class is recommended - you'll need this later to create new instances of the block - Register the block in
RuntimeBlockStateRegistry
- this informs the server of all the block's possible states so that it can be read from chunks at runtime - Register a deserializer for the block's Minecraft ID in
BlockStateToObjectDeserializer
- needed for the block to be recognized when loaded from disk - Register a serializer for the block in
BlockObjectToStateSerializer
- needed for the block to be saved to disk, and to be sent over the network - Optionally, register a string alias for the block in
StringToItemParser
- so that it can be given via/give
To see a demo of how to do this in a plugin, see this example plugin.
Registering custom blocks follows a similar process, but requires additional steps to modify BlockStateDictionary
which won't be covered here.
Since this is not currently officially supported by PocketMine-MP, this won't be covered here.
This is admittedly rather more of a hassle than in PM4, but this system offers significantly more flexibility than the old system.
To register a new vanilla block into the core, the process is slightly different:
- Instead of using
BlockTypeIds::newId()
, add a new constant for the block toBlockTypeIds
- Register the new block in
VanillaBlocks
-RuntimeBlockStateRegistry
will automagically take notice of all blocks defined inVanillaBlocks
- Follow steps 4 onwards above
- The following classes have been removed:
BlockIdentifierFlattened
BlockLegacyIdHelper
BlockLegacyIds
BlockLegacyMetadata
utils\BlockDataSerializer
utils\ColorInMetadataTrait
-utils\ColoredTrait
now implements colour type data serialization uniformlyutils\InvalidBlockStateException
- this has been superseded bypocketmine\data\runtime\InvalidSerializedRuntimeDataException
utils\NormalHorizontalFacingInMetadataTrait
-utils\HorizontalFacingTrait
now implements facing type data serialization uniformlyutils\PillarRotationInMetadataTrait
-utils\PillarRotationTrait
now implements rotation type data serialization uniformly
- The following classes have been renamed:
BlockFactory
->RuntimeBlockStateRegistry
- this class is now exclusively used for mapping state IDs to block instances for runtime chunk block readingSkull
->MobHead
utils\SkullType
->utils\MobHeadType
utils\TreeType
->pocketmine\world\generator\object\TreeType
- The following classes have been added:
BaseCake
BaseFire
BlockTypeIds
- list of type IDs, one for each entry inVanillaBlocks
BlockTypeInfo
BlockTypeTags
CakeWithCandle
CakeWithDyedCandle
Candle
CartographyTable
Chain
CopperOre
CopperSlab
CopperStairs
Copper
DyedCandle
GildedBlackstone
GoldOre
HangingRoots
IronOre
Light
LightningRod
NetherGoldOre
Sculk
SmithingTable
SoulFire
WitherRose
utils\CandleTrait
utils\CopperOxidation
utils\CopperTrait
utils\SaplingType
- enum of all sapling typesutils\WallConnectionType
- enum of all possible wall connection typesutils\WoodTypeTrait
utils\WoodType
- enum of all possible wood types, used for wood material blocks like planks and logs
- The following API methods have been removed:
Block->getId()
- for type comparisons, useBlock->getTypeId()
insteadBlock->getMeta()
- for state comparisons, useBlock->getStateId()
insteadBlock->getStateBitmask()
Block->readStateFromData()
Block->writeStateToItemMeta()
Block->writeStateToMeta()
BlockFactory->get()
- see notes above aboutRuntimeBlockStateRegistry
BlockIdentifier->getAllBlockIds()
BlockIdentifier->getBlockId()
BlockIdentifier->getItemId()
BlockIdentifier->getVariant()
Door->isPowered()
Door->setPowered()
MobHead->isNoDrops()
(previouslySkull->isNoDrops()
)MobHead->setNoDrops()
(previouslySkull->setNoDrops()
)VanillaBlocks::*_GLAZED_TERRACOTTA()
- useVanillaBlocks::GLAZED_TERRACOTTA()->setColor(DyeColor::WHATEVER())
insteadutils\FallableTrait->getId()
is no longer requiredutils\FallableTrait->getMeta()
is no longer requiredutils\MobHeadType->getMagicNumber()
(previouslyutils\SkullType->getMagicNumber()
)utils\MobHeadType::fromMagicNumber()
(previouslyutils\SkullType::fromMagicNumber()
)
- The following constants have been removed:
Block::INTERNAL_METADATA_BITS
Block::INTERNAL_METADATA_MASK
- The following API methods have been renamed:
Block->getFullId()
->Block->getStateId()
Block->isSameType()
->Block->hasSameTypeId()
MobHead->getSkullType()
->MobHead->getMobHeadType()
(previouslySkull->getSkullType()
)MobHead->setSkullType()
->MobHead->setMobHeadType()
(previouslySkull->setSkullType()
)
- The following API methods have signature changes:
Block->onBreak()
now acceptsarray<Item> &$returnedItems
reference parameter.Block->onInteract()
now acceptsarray<Item> &$returnedItems
reference parameter.Block->readStateFromWorld()
now returnsBlock
- this allows blocks to replace themselves with a different block entirely based on world conditions.BlockIdentifier->__construct()
now acceptsint $blockTypeId
, and no longer acceptsint $blockId, int $variant, ?int $itemId
ItemFrame->getFacing()
may now returnFacing::UP
andFacing::DOWN
ItemFrame->setFacing()
now acceptsFacing::UP
andFacing::DOWN
Leaves->__construct()
now acceptsLeavesType $leavesType
instead ofTreeType $treeType
RuntimeBlockStateRegistry->register()
no longer accepts an$override
parameter.Sapling::__construct()
now acceptsSaplingType $saplingType
instead ofTreeType $treeType
utils\SignText::__construct()
now accepts two new optional parameters:?Color $baseColor
andbool $glowing
utils\SignText::fromBlob()
now accepts two new optional parameters:?Color $baseColor
andbool $glowing
- The following API methods have been added:
protected Block->describeBlockOnlyState(RuntimeDataDescriber $w) : void
- describes state properties which are discarded when the block is broken or block-picked, such as facing, powered, etc.public Block->describeBlockItemState(RuntimeDataDescriber $w) : void
- describes state properties which are kept by the item when the block is broken or block-picked, such as dye colorpublic Block->generateStatePermutations() : \Generator<int, Block, void, void>
- yields all possible states this block type can be in (used forRuntimeBlockStateRegistry
)public Block->getTypeTags() : array<string>
public Block->hasTypeTag(string $tag) : bool
public Block->isFireProofAsItem() : bool
public Block->onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void
public BlockIdentifier->getBlockTypeId() : int
- returns the block's type ID according toBlockTypeIds
public Furnace->getFurnaceType() : utils\FurnaceType
public GlazedTerracotta->getColor() : utils\DyeColor
(fromColoredTrait
) - this was previously unsupported due to legacy limitationspublic GlazedTerracotta->setColor(utils\DyeColor $color) : $this
(fromColoredTrait
) - this was previously unsupported due to legacy limitationspublic Leaves->getLeavesType() : utils\LeavesType
- returns the type of leavespublic Wall->getConnection(int $face) : utils\WallConnectionType
public Wall->getConnections() : array<int, utils\WallConnectionType>
- returns the wall's connections and their types (seeutils\WallConnectionType
)public Wall->isPost() : bool
public Wall->setConnection(int $face, ?utils\WallConnectionType $type) : $this
public Wall->setConnections()
- sets the wall's connections and their types (seeutils\WallConnectionType
)public Wall->setPost(bool $post) : $this
public Wood->isStripped() : bool
public Wood->setStripped(bool $stripped) : $this
public static BlockBreakInfo::axe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfo
public static BlockBreakInfo::pickaxe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfo
public static BlockBreakInfo::shovel(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfo
public static BlockBreakInfo::tier(float $hardness, int $toolType, ToolTier $toolTier, ?float $blastResistance = null) : BlockBreakInfo
public tile\Spawnable->getRenderUpdateBugWorkaroundStateProperties(Block $block) : array<string, Tag>
- allows spawnable tiles to spoof block state properties to work around client-side rendering bugs without actually changing the block server-sidepublic utils\SignText->getBaseColor() : \pocketmine\color\Color
public utils\SignText->isGlowing() : bool
- The following classes now use new traits, adding API methods and/or properties:
FenceGate
usesutils\WoodTypeTrait
GlazedTerracotta
usesutils\ColoredTrait
Planks
usesutils\WoodTypeTrait
Wood
usesutils\WoodTypeTrait
WoodenButton
usesutils\WoodTypeTrait
WoodenDoor
usesutils\WoodTypeTrait
WoodenFence
usesutils\WoodTypeTrait
WoodenPressurePlate
usesutils\WoodTypeTrait
WoodenSlab
usesutils\WoodTypeTrait
WoodenStairs
usesutils\WoodTypeTrait
WoodenTrapdoor
usesutils\WoodTypeTrait
- The following API interface requirements have been added (BC breaking):
public utils\Fallable->getFallDamagePerBlock() : float
(default implementation provided byutils\FallableTrait
)public utils\Fallable->getLandSound() : ?Sound
(default implementation provided byutils\FallableTrait
)public utils\Fallable->getMaxFallDamage() : float
(default implementation provided byutils\FallableTrait
)public utils\Fallable->onHitGround(FallingBlock $blockEntity) : bool
(default implementation provided byutils\FallableTrait
)
- Command permissions are now always checked by the server when running a command.
- This only affects commands implemented by extending
Command
. Plugins usingPluginBase->onCommand()
are not affected by this change, since they already had permissions checked by the server anyway. - Previously, direct inheritors of
Command
were responsible for checking permissions, which required developers to duplicate the same code in every command, and opened lots of potential for security vulnerabilities. - If you want to do something on permission denied (e.g. sending a special message, or audit logging), you can do so by overriding
Command->testPermission()
, instead of baking the code directly intoCommand->execute()
. - If you don't want to use permissions at all, just create a permission with a default of
true
(or belonging topocketmine.group.user
) and assign that.
- This only affects commands implemented by extending
SimpleCommandMap
now requires all commands to have a permission set when registered.- If you actually want to allow everyone to use your command (not advised), you can add a new permission to the
pocketmine.group.user
group, or usedefault: true
forplugin.yml
permissions.
- If you actually want to allow everyone to use your command (not advised), you can add a new permission to the
- The following API methods have changed behaviour:
Command->testPermissionSilent()
now returnsfalse
if there are no permissions associated with the command. This is to prevent commands with no permissions being usable by everyone, which has previously been a source of security issues.
- The following API methods have been added:
public Command->getPermissions() : list<string>
- returns a list of permissions which grant usage access to this command. A user with one or more of these permissions will be able to invoke the command'sexecute()
methodpublic Command->setPermissions(list<string> $permissions) : void
- sets the permissions which grant usage access to this command. This should be used instead ofsetPermission()
with;
separators (which is now deprecated)
- JSON models have been updated to reflect updated crafting data format.
- The following enum classes have new members:
ShapelessRecipeType
has new membersCARTOGRAPHY
andSMITHING
- The following classes have been added:
ExactRecipeIngredient
- matches an exact itemMetaWildcardRecipeIngredient
- matches an item with the given legacy Minecraft ID, but any metadata valueRecipeIngredient
interfaceTagWildcardRecipeIngredient
- matches an item based on its Minecraft tags, e.g.minecraft:wooden_tier
- The following API methods have signature changes:
FurnaceRecipe->__construct()
now acceptsRecipeIngredient
instead ofItem
FurnaceRecipe->getInput()
now returnsRecipeIngredient
instead ofItem
PotionContainerChangeRecipe->__construct()
now acceptsstring, RecipeIngredient, string
(using Minecraft string IDs instead of legacy integers).PotionContainerChangeRecipe->getIngredient()
now returnsRecipeIngredient
instead ofItem
.PotionContainerChangeRecipe->getInputItemId()
now returnsstring
(using Minecraft string IDs instead of legacy integers).PotionContainerChangeRecipe->getOutputItemId()
now returnsstring
(using Minecraft string IDs instead of legacy integers).PotionTypeRecipe->__construct()
now acceptsRecipeIngredient
instead ofItem
PotionTypeRecipe->getIngredient()
now returnsRecipeIngredient
instead ofItem
PotionTypeRecipe->getInput()
now returnsRecipeIngredient
instead ofItem
ShapedRecipe->__construct()
now acceptsRecipeIngredient
instead ofItem
ShapedRecipe->getIngredient()
now returns?RecipeIngredient
instead of?Item
ShapedRecipe->getIngredientList()
now returnsRecipeIngredient[]
instead ofItem[]
ShapedRecipe->getIngredientMap()
now returnsRecipeIngredient[][]
instead ofItem[][]
ShapelessRecipe->__construct()
$type
parameter is now mandatory.ShapelessRecipe->__construct()
now acceptsRecipeIngredient
instead ofItem
ShapelessRecipe->getIngredientList()
now returnsRecipeIngredient[]
instead ofItem[]
- New packages
bedrock\block
andbedrock\item
have been added. These packages contain all the necessary code for loading and saving Bedrock blocks and items from disk. - New package
runtime
has been added. This package contains code for serializing runtime data for blocks and items. LegacyToStringBidirectionalIdMap
has been reduced toLegacyToStringIdMap
.- Since we never map from string ID to legacy ID, bidirectional mapping is no longer necessary.
- This affects the following subclasses:
LegacyBiomeIdToStringIdMap
LegacyBlockIdToStringIdMap
LegacyEntityIdToStringIdMap
LegacyItemIdToStringIdMap
- The following internal API methods have been added:
public LegacyToStringIdMap->add(string $string, int $legacy) : void
- adds a mapping from a custom legacy ID to custom string ID, needed for upgrading old saved data
Entity
now declares new abstract methods which must be implemented by subclasses:public Entity->getInitialDragMultiplier() : float
public Entity->getInitialGravity() : float
- The following new API methods have been added:
public Living->getDisplayName() : string
- The following API methods have changed signatures:
EntityFactory->register()
no longer accepts a$legacyMcpeSaveId
parameter (now handled by internal conversions instead).
- The following API methods have been renamed:
Entity->isImmobile()
->Entity->hasNoClientPredictions()
Entity->setImmobile()
->Entity->setNoClientPredictions()
- The following internal fields have been renamed:
Entity->immobile
->Entity->noClientPredictions
- The following classes have been removed:
EntityLegacyIds
-
The following classes have inheritance changes:
block\BlockPlaceEvent
no longer extendsBlockEvent
, and therefore no longer hasgetBlock()
. UsegetTransaction()
instead (may contain multiple blocks).
-
BlockFormEvent
now includes information about the block which caused the event. -
The following new classes have been added:
world\WorldDisplayNameChangeEvent
- called when a world's display name is changed
-
The following classes have been renamed:
entity\ExplosionPrimeEvent
->entity\EntityPreExplodeEvent
-
The following API methods have been added:
public block\BlockFormEvent->getCausingBlock() : Block
public block\BlockGrowEvent->getPlayer() : ?Player
- returns the player that triggered the block growth, ornull
if it was not triggered by a playerpublic block\BlockPlaceEvent->getTransaction() : BlockTransaction
- returns the transaction containing a list of changed block positions and the blockstates they will be changed topublic server\DataPacketSendEvent->setPackets(list<ClientboundPacket> $packets) : void
-
The following API methods have changed signatures:
block\BlockPlaceEvent->__construct()
now acceptsBlockTransaction $transaction
instead ofBlock $blockPlace, Block $blockReplace
entity\EntityPreExplodeEvent->__construct()
has the$force
parameter renamed to$radius
entity\EntityPreExplodeEvent->getForce() : float
->entity\EntityPreExplodeEvent->getRadius() : float
entity\EntityPreExplodeEvent->setForce(float $force) : void
->entity\EntityPreExplodeEvent->setRadius(float $radius) : void
-
The following API methods have been removed:
block\BlockPlaceEvent->getBlockReplaced()
- this information is now provided in theBlockTransaction
object returned byBlockPlaceEvent->getTransaction()
-
The following new API constants have been added:
entity\EntityDamageEvent::CAUSE_FALLING_BLOCK
entity\EntityDamageEvent::MODIFIER_ARMOR_HELMET
PlayerPreLoginEvent
,PlayerDuplicateLoginEvent
andPlayerKickEvent
now supports setting separate log reasons (disconnect reason) and disconnect screen messages.- The following classes have been removed:
PlayerCommandPreprocessEvent
- The following API methods have changed signatures:
PlayerDuplicateLoginEvent->getDisconnectMessage()
now returnsTranslatable|string
instead ofstring
PlayerDuplicateLoginEvent->setDisconnectMessage()
now acceptsTranslatable|string
instead ofstring
PlayerKickEvent->getReason()
now returnsTranslatable|string
instead ofstring
PlayerKickEvent->setReason()
now acceptsTranslatable|string
instead ofstring
PlayerLoginEvent->getKickMessage()
now returnsTranslatable|string
instead ofstring
PlayerLoginEvent->setKickMessage()
now acceptsTranslatable|string
instead ofstring
PlayerPreLoginEvent->getFinalKickMessage()
now returnsTranslatable|string
instead ofstring
PlayerPreLoginEvent->getKickMessage()
now returnsTranslatable|string|null
instead ofstring|null
PlayerPreLoginEvent->setKickFlag()
(previouslysetKickReason()
) now acceptsTranslatable|string $disconnectReason, Translatable|string|null $disconnectScreenMessage = null
instead ofTranslatable|string $message
PlayerPreLoginEvent->setKickReason()
now acceptsTranslatable|string
for the$message
parameter instead ofstring
PlayerQuitEvent->getQuitReason()
now returnsTranslatable|string
instead ofstring
- The following API methods have been removed:
PlayerChatEvent->getFormat()
(usePlayerChatEvent->getChatFormatter()
instead)PlayerChatEvent->setFormat()
(usePlayerChatEvent->setChatFormatter()
instead)PlayerDuplicateLoginEvent->getDisconnectMessage()
- replaced bygetDisconnectReason()
andgetDisconnectScreenMessage()
PlayerDuplicateLoginEvent->setDisconnectMessage()
- replaced bysetDisconnectReason()
andsetDisconnectScreenMessage()
PlayerKickEvent->getReason()
- replaced bygetDisconnectReason()
andgetDisconnectScreenMessage()
PlayerKickEvent->setReason()
- replaced bysetDisconnectReason()
andsetDisconnectScreenMessage()
- The following new API methods have been added:
public PlayerChatEvent->getChatFormatter() : \pocketmine\player\chat\ChatFormatter
- returns the chat formatter to be used for this eventpublic PlayerChatEvent->setChatFormatter(\pocketmine\player\chat\ChatFormatter $formatter) : void
- sets the chat formatter to be used for this eventpublic PlayerDeathEvent->getDeathScreenMessage() : Translatable|string
- returns the message to be displayed on the death screenpublic PlayerDeathEvent->setDeathScreenMessage(Translatable|string $deathScreenMessage) : void
- sets the message to be displayed on the death screenpublic PlayerDuplicateLoginEvent->getDisconnectReason() : Translatable|string
- returns the reason for the disconnection displayed in the console and server logpublic PlayerDuplicateLoginEvent->getDisconnectScreenMessage() : Translatable|string|null
- returns the message to be displayed on the disconnect screen (the message ingetDisconnectReason()
is used if null is returned)public PlayerDuplicateLoginEvent->setDisconnectReason(Translatable|string $disconnectReason) : void
- sets the reason for the disconnection displayed in the console and server logpublic PlayerDuplicateLoginEvent->setDisconnectScreenMessage(Translatable|string|null $disconnectScreenMessage) : void
- sets the message to be displayed on the disconnect screen (the message insetDisconnectReason()
is used if null is passed)public PlayerKickEvent->getDisconnectReason() : Translatable|string
- returns the reason for the disconnection displayed in the console and server logpublic PlayerKickEvent->getDisconnectScreenMessage() : Translatable|string|null
- returns the message to be displayed on the disconnect screen (the message ingetDisconnectReason()
is used if null is returned)public PlayerKickEvent->setDisconnectReason(Translatable|string $disconnectReason) : void
- sets the reason for the disconnection displayed in the console and server logpublic PlayerKickEvent->setDisconnectScreenMessage(Translatable|string|null $disconnectScreenMessage) : void
- sets the message to be displayed on the disconnect screen (the message insetDisconnectReason()
is used if null is passed)public PlayerPreLoginEvent->getDisconnectScreenMessage(int $flag) : Translatable|string|null
- returns the message to be displayed on the disconnect screen for the specified kick flag, if setpublic PlayerPreLoginEvent->getFinalDisconnectScreenMessage() : Translatable|string|null
- returns the message to be displayed on the disconnect screen, taking into account the kick flags set
- The following classes have inheritance changes:
PlayerPreLoginEvent
no longer implementsCancellable
. This caused unexpected behaviour for most plugin devs due to default-ignoring cancelled events, forcing people to usually have to use@handleCancelled
to handle the event when they wanted to use it.
- The following API constants have been renamed:
PlayerPreLoginEvent::KICK_REASON_BANNED
->PlayerPreLoginEvent::KICK_FLAG_BANNED
PlayerPreLoginEvent::KICK_REASON_PLUGIN
->PlayerPreLoginEvent::KICK_FLAG_PLUGIN
PlayerPreLoginEvent::KICK_REASON_PRIORITY
->PlayerPreLoginEvent::KICK_FLAG_PRIORITY
PlayerPreLoginEvent::KICK_REASON_SERVER_FULL
->PlayerPreLoginEvent::KICK_FLAG_SERVER_FULL
PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED
->PlayerPreLoginEvent::KICK_FLAG_SERVER_WHITELISTED
- The following API methods have been renamed:
PlayerPreLoginEvent->clearAllKickReasons()
->PlayerPreLoginEvent->clearAllKickFlags()
PlayerPreLoginEvent->clearKickReason()
->PlayerPreLoginEvent->clearKickFlag()
PlayerPreLoginEvent->getFinalKickMessage()
->PlayerPreLoginEvent->getFinalDisconnectReason()
(now used for logs only, if a disconnect screen message is set for the highest priority flag)PlayerPreLoginEvent->getKickMessage()
->PlayerPreLoginEvent->getDisconnectReason()
(now used for logs only, if a disconnect screen message is set for the flag)PlayerPreLoginEvent->getKickReasons()
->PlayerPreLoginEvent->getKickFlags()
PlayerPreLoginEvent->isKickReasonSet()
->PlayerPreLoginEvent->isKickFlagSet()
PlayerPreLoginEvent->setKickReason()
->PlayerPreLoginEvent->setKickFlag()
ItemFactory
has been removed. Vanilla item registration is now done viaVanillaItems
.- To get an item at runtime, e.g. iron ingot, use
VanillaItems::IRON_INGOT()
- To get a block as an item, e.g. stone, use
VanillaBlocks::STONE()->asItem()
- To load an item from legacy ID and meta:
- Use
GlobalItemDataHandlers::getUpgrader()->upgradeItemTypeDataInt()
to convert the legacy ID and meta toSavedItemStackData
- Pass the itemstack data to
GlobalItemDataHandlers::getDeserializer()
to get anItem
instance
- Use
- To get an item at runtime, e.g. iron ingot, use
- Items no longer use internal Minecraft string IDs and metadata to identify themselves. All APIs associated with legacy IDs and/or meta have been removed.
- A new set of runtime item IDs generated from
VanillaItems
is now used to identify item types. These IDs are defined inItemTypeIds
.- These new IDs are primarily intended for type comparison purposes.
- Item type IDs are used at runtime only. They should NOT be stored in configs or databases, as they are not guaranteed to remain the same between versions.
- In some cases, items may have additional "type data" which provides extra type information about an item. This
replaces item metadata in some cases.
- Type data may be used to store dynamic type information such as dye colour, potion type, etc.
- Items must have the same type ID and type data in order to be stackable.
- Blocks, when represented as items:
- retain their block type data, but not state data (for example, different colours of concrete don't stack, but things like facing don't affect stackability)
- use the negative of their block type ID (e.g. a block with type ID
1
will have an item type ID of-1
).
- Durable items (e.g. tools, armour) now use NBT
Damage
tag to store durability (like Minecraft 1.13+), instead of legacy meta values. &$returnedItems
reference parameter is now used in some places (e.g.onInteractBlock()
) to enable actions to return items to players without caring about whether they are in creative or anything else.- This eliminates boilerplate code of deciding whether to set the player's held item or not, as well as automatically dropping any overflow items that don't fit into the inventory.
- This is used for things like filling/emptying buckets and bottles, and equipping armor.
- Blocks which previously had separate items, such as mob heads and beds, no longer do. Their item form can be acquired using
Block->asItem()
in the same way as every other block. This is facilitated by the new serializer system.
This follows a similar process to registering blocks.
- Get a new type ID using
ItemTypeIds::newId()
- you'll want to keep this in a property somewhere if you want to compare usinggetTypeId()
later - Set up the item type somewhere - this can be anywhere you like, e.g. a plugin main class property, but using
a
RegistryTrait
class is recommended - you'll need this later to create new instances of the item - Register a deserializer in
ItemDeserializer
- needed for the item to be recognized when loaded from disk - Register a serializer in
ItemSerializer
- needed for the item to be saved to disk, and to be sent over the network - Optionally, register a string alias for the item in
StringToItemParser
- so that it can be given via/give
To see a demo of how to do this in a plugin, see this example plugin.
Again, it's acknowledged this is rather more cumbersome than it should be, but this is an ongoing process.
To register a new vanilla item into the core, the process is slightly different:
- Instead of using
ItemTypeIds::newId()
, add a new constant for the block toItemTypeIds
- Register the new item in
VanillaItems
- Follow steps 3 onwards from the plugin instructions above
Item
is no longerjson_encode()
-able.- The original purpose of this was to allow items to be serialized to JSON for crafting data generated from
CraftingDataPacket
. Due to changes in the generation methodology, bypassingItem
s entirely, this is no longer necessary. - In addition,
jsonSerialize()
required the item to know about the method by which it will be serialized (since there is no way to inject context), creating a cyclic dependency between theItem
implementation and its serialization method. - It's relatively easy to write a replacement method to encode items to JSON as you desire.
Item::legacyJsonDeserialize()
(previouslyItem::jsonDeserialize()
) is retained to allow loading legacy data, although it may be removed in the future.
- The original purpose of this was to allow items to be serialized to JSON for crafting data generated from
- The following classes have been removed:
Bed
ItemFactory
ItemIds
Skull
- The following classes have been added:
BoatType
- enum of all boat typesCoralFan
HoneyBottle
MedicineType
Medicine
Spyglass
SuspiciousStewType
SuspiciousStew
- The following API methods have been added:
protected Item->describeState(RuntimeDataDescriber $w) : void
public Armor->clearCustomColor() : $this
- clears the custom color of an armor itempublic ArmorTypeInfo->getToughness() : int
public ArmorTypeInfo->isFireProof() : bool
public Boat->getType() : BoatType
public Dye->setColor(\pocketmine\block\utils\DyeColor $color) : $this
public Item->getStateId() : int
- returns a runtime numeric state ID for comparisons including information such as coral type, dye color, etc. - DO NOT save this to disk or databasespublic Item->getTypeId() : int
- returns a runtime numeric type ID for comparisons - DO NOT save this to disk or databasespublic Item->isFireProof() : bool
public ItemIdentifer->getTypeId() : int
public Potion->setType(PotionType $type) : $this
public SplashPotion->setType(PotionType $type) : $this
public StringToItemParser->lookupAliases(Item $item) : list<string>
- returns a list of all registered aliases for the given itempublic StringToItemParser->lookupBlockAliases(Block $block) : list<string>
- returns a list of all registered aliases for the given blockpublic static ItemIdentifier::fromBlock(Block $block) : self
- The following API methods have been removed:
Boat->getWoodType()
Item->getId()
- for type comparisons, useItem->getTypeId()
insteadItem->getMeta()
- use the item's specific API methods to compare information such as colour, potion type etc.Item->hasAnyDamageValue()
- for meta wildcard recipe ingredients, usepocketmine\crafting\MetaWildcardRecipeIngredient
insteadItemIdentifier->getId()
ItemIdentifier->getMeta()
- The following API methods have been renamed:
Item::jsonDeserialize()
->Item::legacyJsonDeserialize()
- The following API methods have signature changes:
ArmorTypeInfo->__construct()
now accepts optional parametersint $toughness
andbool $fireProof
BoatType::__construct()
now acceptsBoatType $boatType
instead ofTreeType $woodType
.Item->onAttackEntity()
now acceptsarray<Item> &$returnedItems
reference parameter.Item->onClickAir()
now acceptsarray<Item> &$returnedItems
reference parameter.Item->onDestroyBlock()
now acceptsarray<Item> &$returnedItems
reference parameter.Item->onInteractBlock()
now acceptsarray<Item> &$returnedItems
reference parameter.Item->onReleaseUsing()
now acceptsarray<Item> &$returnedItems
reference parameter.ItemIdentifier->__construct()
no longer accepts a$variant
parameter, and now expects an item type ID for the ID parameterLegacyStringToItemParser->addMapping()
now accepts a string for ID, instead of an integer
- The following API methods have behaviour changes:
Item->equals()
's$checkDamage
parameter is now ignored, as tool damage is now stored as an NBT tag. This parameter wasn't removed due to being followed by a secondbool
parameter, which would potentially end up in the wrong place and silently cause bugs in updated plugins.Item->equals()
's$checkTags
parameter will now cause tool and armor damage to be checked if true.
- The following enums have new members:
ToolTier
has new memberNETHERITE
- The following API methods have changed signatures:
NetworkSessionManager->close()
now accepts an additionalTranslatable|string|null $disconnectScreenMessage
parameter.
- The following API methods have changed signatures:
query\QueryInfo->getPlayerList()
now returnslist<string>
instead oflist<Player>
query\QueryInfo->setPlayerList()
now acceptslist<string>
instead oflist<Player>
- The following API methods have changed signatures:
Player->disconnect()
now acceptsTranslatable|string
for$reason
instead ofstring
(to allow localized disconnect messages)Player->disconnect()
now accepts an additionalTranslatable|string|null $disconnectScreenMessage
parameter, which is the message to be displayed on the disconnect screen (the message in$reason
is used if null is passed)Player->kick()
now acceptsTranslatable|string
for$reason
instead ofstring
(to allow localized kick messages)Player->kick()
now accepts an additionalTranslatable|string|null $disconnectScreenMessage
parameter, which is the message to be displayed on the disconnect screen (the message in$reason
is used if null is passed)Player->sendJukeboxPopup()
now acceptsTranslatable|string
instead ofstring, string[]
- The following classes have been removed:
PlayerChunkLoader
- deprecated in 4.19.0 (this was technically internal, but never marked as such)
- The following new classes have been added:
ChatFormatter
- interface implemented by chat formatters - this is far more powerful than the old APILegacyRawChatFormatter
- implements the same behaviour previously used byPlayerChatEvent->setFormat()
StandardChatFormatter
- formats chat messages in the vanilla Minecraft style
AsyncTask->setResult()
now works with thread-safe objects. This was previously not possible due to limitations in thepthreads
extension.
- The following API methods have been added:
public World->setDisplayName(string $name) : void
- The following API methods have changed signatures:
Explosion->__construct()
has the$size
parameter renamed to$radius
- The following public properties have been renamed:
Explosion->size
->Explosion->radius
- Chunks are now considered dirty (modified) by default, unless loaded from a
WorldProvider
byWorld
. Previously, chunks were considered unmodified by default, which allowed several pathways to bugs. - The following classes have been added:
io\GlobalBlockStateHandlers
- gives access to block data serializer, deserializer, and upgradersio\GlobalItemDataHandlers
- gives access to item data serializer, deserializer, and upgradersio\LoadedChunkData
- represents a chunk loaded from disk, along with information such as whether the chunk was upgraded and what fixes it requires
- The following new API methods have been added:
public SubChunk->getBiomeArray() : PalettedBlockArray
- The following classes have been removed:
BiomeArray
-PalettedBlockArray
is now used for 3D biome data
- The following API methods have changed signatures:
Chunk->getBiomeId()
now acceptsint $x, int $y, int $z
instead ofint $x, int $z
Chunk->setBiomeId()
now acceptsint $x, int $y, int $z
instead ofint $x, int $z
Chunk->__construct()
no longer acceptsBiomeArray
as a parameter (contained in each subchunk instead)SubChunk->__construct()
now acceptsint $emptyBlockId, list<PalettedBlockArray> $blockLayers, PalettedBlockArray $biomes, ?LightArray $blockLight, ?LightArray $skyLight
instead ofint, list<PalettedBlockArray>, ?LightArray, ?LightArray
io\WorldProvider->loadChunk()
now returnsLoadedChunkData
instead ofChunkData
io\WorldProvider->getAllChunks()
now yieldsLoadedChunkData
instead ofChunkData
io\ChunkData->__construct()
now acceptsarray<int, SubChunk>, bool $populated
instead ofChunk $chunk
- The following API methods have been renamed:
Chunk->getFullBlock()
->Chunk->getBlockStateId()
Chunk->setFullBlock()
->Chunk->setBlockStateId()
SubChunk->getFullBlock()
->SubChunk->getBlockStateId()
SubChunk->setFullBlock()
->SubChunk->setBlockStateId()
- The following API interface requirements have been added:
public io\data\WorldData->setDisplayName(string $value) : void
- The following API methods have been removed:
TreeType::fromMagicNumber()
TreeType->getMagicNumber()
- The following classes have been added:
CopperWaxApplySound
CopperWaxRemoveSound
DyeUseSound
InkSacUseSound
- The following enums have new members:
NoteInstrument
has new membersBELL
,FLUTE
,CHIME
,XYLOPHONE
,IRON_XYLOPHONE
,COW_BELL
,DIDGERIDOO
,BIT
,BANJO
,PLING
- The following API methods have been removed:
NoteInstrument::fromMagicNumber()
NoteInstrument->getMagicNumber()
- All external usages of
KnownTranslationKeys
are now removed. All localized messages are now sent usingTranslatable
objects (usually fromKnownTranslationFactory
). - All usages of NBT keys now use class constants instead of hardcoded strings (except for an occasional overlooked one).
- Built-in commands now declare their names inside the class constructor, rather than accepting them as parameters. This improves code consistency.
- Commands now use an array for permissions internally, instead of a string separated by
;
. - Make use of
Item->canStackWith()
instead ofItem->equals()
wherever possible, to make the code more readable. - Moved command timings to
Timings
. - Overriding of serializers and deserializers of items and blocks is now consistently disallowed. Since overriding stuff is non-cooperative, it doesn't make any sense in plugins, which must coexist with other plugins. If you want to modify the functionality of built-in stuff, you have several alternative options:
- Use existing API (e.g. events, API methods) - most uses of overrides in PM4 and earlier were abuses that could have been done with events
- Submit feature proposals or pull requests for new API to be added (e.g. new events)
- Register completely custom items, and reuse behaviour from the item you want to mimic
- Fork PocketMine-MP and alter the code directly - this way your plugins aren't pretending to be cooperative with other plugins
level.dat
, block, item, entity, tile and chunk data are now tagged with a version ID as perVersionInfo::WORLD_DATA_VERSION
. This allows the server to apply fixes to older worlds if necessary.- Protocol creative inventory entries are now cached in
CreativeInventoryCache
to improve performance of initial join and game mode changes. - Singletons in the
pocketmine\network\mcpe\convert
package have been centralized underTypeConverter
. In the future, this will be injected where needed, allowing different converters to be used for different sessions (useful for multiversion). BlockStateDictionary
memory usage is now reduced from 9 MB to 3.5 MB using various techniques, including string reuse and binary-encoded states.NetworkSession
disconnect APIs now acceptTranslatable|string
instead ofstring
to allow localized disconnect messages.NetworkSession
disconnect methods have been altered to allow specifying a different disconnect reason and disconnection screen message.RuntimeBlockMapping
has been renamed toBlockTranslator
.
I think this is supposed to be
RuntimeBlockStateRegistry::fromStateId()