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).
/particlenow accepts strings for particle data instead of integers./particleno longer accepts integers for block or item IDs.- The usage of
blockcrack,iconcrackandblockdustparticle types in/particlenow follows the same pattern as other particle types, with the data for each being passed in thedataparameter 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.phphas 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-pmmpthreadversion 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-pmmpthreadversion 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/snoozeversion 0.5.0 is now required.pocketmine/raklibversion 0.15.0 is now required.pocketmine/raklib-ipcversion 0.2.0 is now required.pocketmine/classloaderandpocketmine/log-pthreadspackages have been removed. The relevant classes from these packages are now included in-house in thepocketmine/threadnamespace.BaseClassLoaderis replaced withpocketmine\thread\ThreadSafeClassLoaderThreadedLoggeris replaced bypocketmine\thread\ThreadSafeLoggerAttachableThreadedLoggeris replaced bypocketmine\thread\AttachableThreadSafeLoggerThreadedLoggerAttachmentis replaced bypocketmine\thread\ThreadSafeLoggerAttachment
webmozart/path-utilhas 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
VanillaBlocksis 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
Blockdescendents now acceptBlockTypeInfoin the constructor, instead ofBlockBreakInfo. This allows for future additions without needing to change dozens of overridden constructors. &$returnedItemsreference 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) andVanillaBlockshas been inverted.- Now, blocks types are defined in
VanillaBlocks RuntimeBlockStateRegistryautomatically registers states for blocks defined inVanillaBlocks.- Manual registration in
RuntimeBlockStateRegistryis still required for custom blocks (see section below about registering new blocks).
- Now, blocks types are defined in
RuntimeBlockStateRegistrynow has only one purpose - to map internal blockstate IDs toBlockobjects 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 aBlockinstance
- Use
- Prefer using
StringToItemParserwherever 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
RegistryTraitclass 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-RuntimeBlockStateRegistrywill automagically take notice of all blocks defined inVanillaBlocks - Follow steps 4 onwards above
- The following classes have been removed:
BlockIdentifierFlattenedBlockLegacyIdHelperBlockLegacyIdsBlockLegacyMetadatautils\BlockDataSerializerutils\ColorInMetadataTrait-utils\ColoredTraitnow implements colour type data serialization uniformlyutils\InvalidBlockStateException- this has been superseded bypocketmine\data\runtime\InvalidSerializedRuntimeDataExceptionutils\NormalHorizontalFacingInMetadataTrait-utils\HorizontalFacingTraitnow implements facing type data serialization uniformlyutils\PillarRotationInMetadataTrait-utils\PillarRotationTraitnow 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->MobHeadutils\SkullType->utils\MobHeadTypeutils\TreeType->pocketmine\world\generator\object\TreeType
- The following classes have been added:
BaseCakeBaseFireBlockTypeIds- list of type IDs, one for each entry inVanillaBlocksBlockTypeInfoBlockTypeTagsCakeWithCandleCakeWithDyedCandleCandleCartographyTableChainCopperOreCopperSlabCopperStairsCopperDyedCandleGildedBlackstoneGoldOreHangingRootsIronOreLightLightningRodNetherGoldOreSculkSmithingTableSoulFireWitherRoseutils\CandleTraitutils\CopperOxidationutils\CopperTraitutils\SaplingType- enum of all sapling typesutils\WallConnectionType- enum of all possible wall connection typesutils\WoodTypeTraitutils\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 aboutRuntimeBlockStateRegistryBlockIdentifier->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_BITSBlock::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> &$returnedItemsreference parameter.Block->onInteract()now acceptsarray<Item> &$returnedItemsreference 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 $itemIdItemFrame->getFacing()may now returnFacing::UPandFacing::DOWNItemFrame->setFacing()now acceptsFacing::UPandFacing::DOWNLeaves->__construct()now acceptsLeavesType $leavesTypeinstead ofTreeType $treeTypeRuntimeBlockStateRegistry->register()no longer accepts an$overrideparameter.Sapling::__construct()now acceptsSaplingType $saplingTypeinstead ofTreeType $treeTypeutils\SignText::__construct()now accepts two new optional parameters:?Color $baseColorandbool $glowingutils\SignText::fromBlob()now accepts two new optional parameters:?Color $baseColorandbool $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) : boolpublic Block->isFireProofAsItem() : boolpublic Block->onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : voidpublic BlockIdentifier->getBlockTypeId() : int- returns the block's type ID according toBlockTypeIdspublic Furnace->getFurnaceType() : utils\FurnaceTypepublic 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\WallConnectionTypepublic Wall->getConnections() : array<int, utils\WallConnectionType>- returns the wall's connections and their types (seeutils\WallConnectionType)public Wall->isPost() : boolpublic Wall->setConnection(int $face, ?utils\WallConnectionType $type) : $thispublic Wall->setConnections()- sets the wall's connections and their types (seeutils\WallConnectionType)public Wall->setPost(bool $post) : $thispublic Wood->isStripped() : boolpublic Wood->setStripped(bool $stripped) : $thispublic static BlockBreakInfo::axe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfopublic static BlockBreakInfo::pickaxe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfopublic static BlockBreakInfo::shovel(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : BlockBreakInfopublic static BlockBreakInfo::tier(float $hardness, int $toolType, ToolTier $toolTier, ?float $blastResistance = null) : BlockBreakInfopublic 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\Colorpublic utils\SignText->isGlowing() : bool
- The following classes now use new traits, adding API methods and/or properties:
FenceGateusesutils\WoodTypeTraitGlazedTerracottausesutils\ColoredTraitPlanksusesutils\WoodTypeTraitWoodusesutils\WoodTypeTraitWoodenButtonusesutils\WoodTypeTraitWoodenDoorusesutils\WoodTypeTraitWoodenFenceusesutils\WoodTypeTraitWoodenPressurePlateusesutils\WoodTypeTraitWoodenSlabusesutils\WoodTypeTraitWoodenStairsusesutils\WoodTypeTraitWoodenTrapdoorusesutils\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
Commandwere 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
SimpleCommandMapnow 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.usergroup, or usedefault: trueforplugin.ymlpermissions.
- 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 returnsfalseif 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:
ShapelessRecipeTypehas new membersCARTOGRAPHYandSMITHING
- The following classes have been added:
ExactRecipeIngredient- matches an exact itemMetaWildcardRecipeIngredient- matches an item with the given legacy Minecraft ID, but any metadata valueRecipeIngredientinterfaceTagWildcardRecipeIngredient- matches an item based on its Minecraft tags, e.g.minecraft:wooden_tier
- The following API methods have signature changes:
FurnaceRecipe->__construct()now acceptsRecipeIngredientinstead ofItemFurnaceRecipe->getInput()now returnsRecipeIngredientinstead ofItemPotionContainerChangeRecipe->__construct()now acceptsstring, RecipeIngredient, string(using Minecraft string IDs instead of legacy integers).PotionContainerChangeRecipe->getIngredient()now returnsRecipeIngredientinstead 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 acceptsRecipeIngredientinstead ofItemPotionTypeRecipe->getIngredient()now returnsRecipeIngredientinstead ofItemPotionTypeRecipe->getInput()now returnsRecipeIngredientinstead ofItemShapedRecipe->__construct()now acceptsRecipeIngredientinstead ofItemShapedRecipe->getIngredient()now returns?RecipeIngredientinstead of?ItemShapedRecipe->getIngredientList()now returnsRecipeIngredient[]instead ofItem[]ShapedRecipe->getIngredientMap()now returnsRecipeIngredient[][]instead ofItem[][]ShapelessRecipe->__construct()$typeparameter is now mandatory.ShapelessRecipe->__construct()now acceptsRecipeIngredientinstead ofItemShapelessRecipe->getIngredientList()now returnsRecipeIngredient[]instead ofItem[]
- New packages
bedrock\blockandbedrock\itemhave been added. These packages contain all the necessary code for loading and saving Bedrock blocks and items from disk. - New package
runtimehas been added. This package contains code for serializing runtime data for blocks and items. LegacyToStringBidirectionalIdMaphas been reduced toLegacyToStringIdMap.- Since we never map from string ID to legacy ID, bidirectional mapping is no longer necessary.
- This affects the following subclasses:
LegacyBiomeIdToStringIdMapLegacyBlockIdToStringIdMapLegacyEntityIdToStringIdMapLegacyItemIdToStringIdMap
- 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
Entitynow declares new abstract methods which must be implemented by subclasses:public Entity->getInitialDragMultiplier() : floatpublic 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$legacyMcpeSaveIdparameter (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\BlockPlaceEventno longer extendsBlockEvent, and therefore no longer hasgetBlock(). UsegetTransaction()instead (may contain multiple blocks).
-
BlockFormEventnow 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() : Blockpublic block\BlockGrowEvent->getPlayer() : ?Player- returns the player that triggered the block growth, ornullif 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 $transactioninstead ofBlock $blockPlace, Block $blockReplaceentity\EntityPreExplodeEvent->__construct()has the$forceparameter renamed to$radiusentity\EntityPreExplodeEvent->getForce() : float->entity\EntityPreExplodeEvent->getRadius() : floatentity\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 theBlockTransactionobject returned byBlockPlaceEvent->getTransaction()
-
The following new API constants have been added:
entity\EntityDamageEvent::CAUSE_FALLING_BLOCKentity\EntityDamageEvent::MODIFIER_ARMOR_HELMET
PlayerPreLoginEvent,PlayerDuplicateLoginEventandPlayerKickEventnow 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|stringinstead ofstringPlayerDuplicateLoginEvent->setDisconnectMessage()now acceptsTranslatable|stringinstead ofstringPlayerKickEvent->getReason()now returnsTranslatable|stringinstead ofstringPlayerKickEvent->setReason()now acceptsTranslatable|stringinstead ofstringPlayerLoginEvent->getKickMessage()now returnsTranslatable|stringinstead ofstringPlayerLoginEvent->setKickMessage()now acceptsTranslatable|stringinstead ofstringPlayerPreLoginEvent->getFinalKickMessage()now returnsTranslatable|stringinstead ofstringPlayerPreLoginEvent->getKickMessage()now returnsTranslatable|string|nullinstead ofstring|nullPlayerPreLoginEvent->setKickFlag()(previouslysetKickReason()) now acceptsTranslatable|string $disconnectReason, Translatable|string|null $disconnectScreenMessage = nullinstead ofTranslatable|string $messagePlayerPreLoginEvent->setKickReason()now acceptsTranslatable|stringfor the$messageparameter instead ofstringPlayerQuitEvent->getQuitReason()now returnsTranslatable|stringinstead 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:
PlayerPreLoginEventno longer implementsCancellable. This caused unexpected behaviour for most plugin devs due to default-ignoring cancelled events, forcing people to usually have to use@handleCancelledto handle the event when they wanted to use it.
- The following API constants have been renamed:
PlayerPreLoginEvent::KICK_REASON_BANNED->PlayerPreLoginEvent::KICK_FLAG_BANNEDPlayerPreLoginEvent::KICK_REASON_PLUGIN->PlayerPreLoginEvent::KICK_FLAG_PLUGINPlayerPreLoginEvent::KICK_REASON_PRIORITY->PlayerPreLoginEvent::KICK_FLAG_PRIORITYPlayerPreLoginEvent::KICK_REASON_SERVER_FULL->PlayerPreLoginEvent::KICK_FLAG_SERVER_FULLPlayerPreLoginEvent::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()
ItemFactoryhas 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 anIteminstance
- 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
VanillaItemsis 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
1will have an item type ID of-1).
- Durable items (e.g. tools, armour) now use NBT
Damagetag to store durability (like Minecraft 1.13+), instead of legacy meta values. &$returnedItemsreference 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
RegistryTraitclass 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
Itemis 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, bypassingItems 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 theItemimplementation 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:
BedItemFactoryItemIdsSkull
- The following classes have been added:
BoatType- enum of all boat typesCoralFanHoneyBottleMedicineTypeMedicineSpyglassSuspiciousStewTypeSuspiciousStew
- The following API methods have been added:
protected Item->describeState(RuntimeDataDescriber $w) : voidpublic Armor->clearCustomColor() : $this- clears the custom color of an armor itempublic ArmorTypeInfo->getToughness() : intpublic ArmorTypeInfo->isFireProof() : boolpublic Boat->getType() : BoatTypepublic Dye->setColor(\pocketmine\block\utils\DyeColor $color) : $thispublic 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() : boolpublic ItemIdentifer->getTypeId() : intpublic Potion->setType(PotionType $type) : $thispublic SplashPotion->setType(PotionType $type) : $thispublic 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\MetaWildcardRecipeIngredientinsteadItemIdentifier->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 $toughnessandbool $fireProofBoatType::__construct()now acceptsBoatType $boatTypeinstead ofTreeType $woodType.Item->onAttackEntity()now acceptsarray<Item> &$returnedItemsreference parameter.Item->onClickAir()now acceptsarray<Item> &$returnedItemsreference parameter.Item->onDestroyBlock()now acceptsarray<Item> &$returnedItemsreference parameter.Item->onInteractBlock()now acceptsarray<Item> &$returnedItemsreference parameter.Item->onReleaseUsing()now acceptsarray<Item> &$returnedItemsreference parameter.ItemIdentifier->__construct()no longer accepts a$variantparameter, 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$checkDamageparameter is now ignored, as tool damage is now stored as an NBT tag. This parameter wasn't removed due to being followed by a secondboolparameter, which would potentially end up in the wrong place and silently cause bugs in updated plugins.Item->equals()'s$checkTagsparameter will now cause tool and armor damage to be checked if true.
- The following enums have new members:
ToolTierhas new memberNETHERITE
- The following API methods have changed signatures:
NetworkSessionManager->close()now accepts an additionalTranslatable|string|null $disconnectScreenMessageparameter.
- 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|stringfor$reasoninstead ofstring(to allow localized disconnect messages)Player->disconnect()now accepts an additionalTranslatable|string|null $disconnectScreenMessageparameter, which is the message to be displayed on the disconnect screen (the message in$reasonis used if null is passed)Player->kick()now acceptsTranslatable|stringfor$reasoninstead ofstring(to allow localized kick messages)Player->kick()now accepts an additionalTranslatable|string|null $disconnectScreenMessageparameter, which is the message to be displayed on the disconnect screen (the message in$reasonis used if null is passed)Player->sendJukeboxPopup()now acceptsTranslatable|stringinstead 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 thepthreadsextension.
- The following API methods have been added:
public World->setDisplayName(string $name) : void
- The following API methods have changed signatures:
Explosion->__construct()has the$sizeparameter 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
WorldProviderbyWorld. 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-PalettedBlockArrayis now used for 3D biome data
- The following API methods have changed signatures:
Chunk->getBiomeId()now acceptsint $x, int $y, int $zinstead ofint $x, int $zChunk->setBiomeId()now acceptsint $x, int $y, int $zinstead ofint $x, int $zChunk->__construct()no longer acceptsBiomeArrayas a parameter (contained in each subchunk instead)SubChunk->__construct()now acceptsint $emptyBlockId, list<PalettedBlockArray> $blockLayers, PalettedBlockArray $biomes, ?LightArray $blockLight, ?LightArray $skyLightinstead ofint, list<PalettedBlockArray>, ?LightArray, ?LightArrayio\WorldProvider->loadChunk()now returnsLoadedChunkDatainstead ofChunkDataio\WorldProvider->getAllChunks()now yieldsLoadedChunkDatainstead ofChunkDataio\ChunkData->__construct()now acceptsarray<int, SubChunk>, bool $populatedinstead 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:
CopperWaxApplySoundCopperWaxRemoveSoundDyeUseSoundInkSacUseSound
- The following enums have new members:
NoteInstrumenthas 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
KnownTranslationKeysare now removed. All localized messages are now sent usingTranslatableobjects (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
CreativeInventoryCacheto improve performance of initial join and game mode changes. - Singletons in the
pocketmine\network\mcpe\convertpackage 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). BlockStateDictionarymemory usage is now reduced from 9 MB to 3.5 MB using various techniques, including string reuse and binary-encoded states.NetworkSessiondisconnect APIs now acceptTranslatable|stringinstead ofstringto allow localized disconnect messages.NetworkSessiondisconnect methods have been altered to allow specifying a different disconnect reason and disconnection screen message.RuntimeBlockMappinghas been renamed toBlockTranslator.
Thanks.