|
| 1 | +# 5.39.0 |
| 2 | +Released 17th December 2025. |
| 3 | + |
| 4 | +This is a minor feature release, including major performance improvements to world generation, new gameplay features, |
| 5 | +new API additions and other improvements. |
| 6 | + |
| 7 | +**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace. |
| 8 | +Do not update plugin minimum API versions unless you need new features added in this release. |
| 9 | + |
| 10 | +**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.** |
| 11 | +Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly. |
| 12 | + |
| 13 | +## General |
| 14 | +- The performance of the `Normal` world generator has been improved by over 500%. (@dktapps) This is a combination of several changes: |
| 15 | + - Restructuring of 3D lerp handling |
| 16 | + - Avoiding generating 3D noise when it's not useful |
| 17 | + - Improvements to `GroundCover` performance |
| 18 | + - Improvements to ore generation |
| 19 | + - Standardising highest-block calculation using faster APIs |
| 20 | +- The timings system will now automatically write timings to a file in the `timings` folder on server shutdown. (@remminiscent, @dktapps) |
| 21 | +- Timings files generated by the server now use the current date and time in the file name, similar to crashdumps. (@remminiscent, @dktapps) |
| 22 | +- Localised messages in various commands, including `/status`, `/setworldspawn`, `/plugins`, `/teleport`, and others. (@dktapps, Crowdin contributors) |
| 23 | +- Fixed translated messages in `/spawnpoint` command. (@siyFred) |
| 24 | +- Added support for `@s` command selector. (@dktapps) |
| 25 | +- `/effect` now accepts `infinite` for the duration. (@remminiscent) |
| 26 | + |
| 27 | +## Gameplay |
| 28 | +- Crouching and holding the sneak key are now treated separately by the server. This allows the player to use interactive blocks while in a 1.5 block high space (forced to crouch), and to disable block interaction while flying without visually crouching by pressing shift+space. (@Dasciam) |
| 29 | +- The following blocks have been added: |
| 30 | + - Crimson and Warped Fungus (@DavyCraft648) |
| 31 | + - Crimson and Warped Nylium (@DavyCraft648) |
| 32 | + - Infested Deepslate (@DavyCraft648) |
| 33 | + - Nether Sprouts (@DavyCraft648) |
| 34 | + - Structure Void (@dktapps) |
| 35 | +- The following items have been added: |
| 36 | + - Copper Helmet, Chestplate, Leggings, Boots and Nuggets (@ValresMC) |
| 37 | + - Copper Axe, Hoe, Pickaxe, Shovel and Sword (@dktapps) |
| 38 | +- Implemented Crimson and Warped Huge Fungi trees. (@DavyCraft648) |
| 39 | +- Netherrack can now be turned into crimson or warped nylium by using bone meal on it. (@DavyCraft648) |
| 40 | +- Added support for infinite effects. (@remminiscent, @dktapps) |
| 41 | +- Implemented magic critical hits when a mob is attacked by an enchanted weapon. (@Dasciam) |
| 42 | + |
| 43 | +## API |
| 44 | +### General |
| 45 | +- Script plugins may now omit the `@name` and `@version` tags in their manifest. These will be autofilled with `ScriptPlugin_<filename>` and `1.0.0` respectively. (@dktapps, @sof3) |
| 46 | +- Added example folder and script plugins in the `examples/plugins` folder. |
| 47 | + |
| 48 | +### `pocketmine\block` |
| 49 | +- The following classes have been added: |
| 50 | + - `InfestedPillar` - used by infested deepslate |
| 51 | + - `NetherFungus` |
| 52 | + - `NetherSprouts` |
| 53 | +- `InfestedStone` is no longer final. |
| 54 | +- The following registry cases have been added: |
| 55 | + - `VanillaBlocks::CRIMSON_FUNGUS()` |
| 56 | + - `VanillaBlocks::CRIMSON_NYLIUM()` |
| 57 | + - `VanillaBlocks::INFESTED_DEEPSLATE()` |
| 58 | + - `VanillaBlocks::NETHER_SPROUTS()` |
| 59 | + - `VanillaBlocks::STRUCTURE_VOID()` |
| 60 | + - `VanillaBlocks::WARPED_FUNGUS()` |
| 61 | + - `VanillaBlocks::WARPED_NYLIUM()` |
| 62 | +- The following constants have been added: |
| 63 | + - `BlockTypeTags::NYLIUM` |
| 64 | + - `BlockTypeTags::HUGE_FUNGUS_REPLACEABLE` |
| 65 | +- Right-clicking on an incomplete bed will now generate a localised message. |
| 66 | + |
| 67 | +### `pocketmine\command` |
| 68 | +- The following classes have been appropriately marked as `@internal` with some basic documentation about their purpose (@dktapps): |
| 69 | + - `CommandExecutor` |
| 70 | + - `FormattedCommandAlias` |
| 71 | + - `PluginCommand` |
| 72 | +- The following classes have been deprecated: |
| 73 | + - `ClosureCommand` |
| 74 | + - `CommandExecutor` |
| 75 | +- `VanillaCommand->fetchPermittedPlayerTarget()` now understands `@s` to mean the sender of the command. |
| 76 | + |
| 77 | +### `pocketmine\entity\effect` |
| 78 | +- `EffectInstance` now supports infinite effects. |
| 79 | + - Due to constraints imposed by `Effect->canTick()`, this is slightly hacky. |
| 80 | + - `Effect->getDuration()` will still tick down for infinite effects to allow effects like Poison to tick, but their durations will underflow to `Limits::INT32_MAX` if they would have reached zero. |
| 81 | + - `Effect->canTick()` has been deprecated in favour of the newly added `Effect->getApplyInterval()`, which constrains us less and will be used in PM6. |
| 82 | +- The following API methods have been added: |
| 83 | + - `public Effect->getApplyInterval(EffectInstance $instance) : int` - returns the tick interval of the effect, or 0 if it doesn't tick (@dktapps) |
| 84 | + - `public EffectInstance->isInfinite() : bool` - returns whether the effect will last forever (@remminiscent) |
| 85 | +- The following API methods have been deprecated: |
| 86 | + - `Effect->canTick()` - use (or implement, if you're making a custom effect) `getApplyInterval()` instead (@dktapps) |
| 87 | + |
| 88 | +### `pocketmine\entity\animation` |
| 89 | +- The following classes have been added: |
| 90 | + - `MagicHitAnimation` - displays critical hit particles normally seen when hitting a mob with an enchanted weapon (@Dasciam) |
| 91 | +- The following API methods have signature changes: |
| 92 | + - `CriticalHitAnimation->__construct()` has a new optional parameter `int $particleCount` (@Dasciam) |
| 93 | + |
| 94 | +### `pocketmine\event` |
| 95 | +- `PlayerToggleSneakEvent` may now be called by the server in a pre-cancelled state if the player's "sneak pressed" state changed, but they didn't start/stop crouching. This pre-cancelled event can be captured by event handlers with the `@handleCancelled` PHPDoc tag. (@Dasciam) |
| 96 | +- The following API methods have been added: |
| 97 | + - `PlayerToggleSneakEvent->isSneakPressed() : bool` - returns whether the player is intentionally activating sneak mode (@Dasciam) |
| 98 | + |
| 99 | +### `pocketmine\item` |
| 100 | +- The following enum cases have been added: |
| 101 | + - `ToolTier::COPPER` |
| 102 | +- The following registry cases have been added: |
| 103 | + - `VanillaArmorMaterials::COPPER()` |
| 104 | + - `VanillaItems::COPPER_AXE()` |
| 105 | + - `VanillaItems::COPPER_BOOTS()` |
| 106 | + - `VanillaItems::COPPER_CHESTPLATE()` |
| 107 | + - `VanillaItems::COPPER_HELMET()` |
| 108 | + - `VanillaItems::COPPER_HOE()` |
| 109 | + - `VanillaItems::COPPER_LEGGINGS()` |
| 110 | + - `VanillaItems::COPPER_NUGGET()` |
| 111 | + - `VanillaItems::COPPER_PICKAXE()` |
| 112 | + - `VanillaItems::COPPER_SHOVEL()` |
| 113 | + - `VanillaItems::COPPER_SWORD()` |
| 114 | + |
| 115 | +### `pocketmine\player` |
| 116 | +- The following API methods have been added: |
| 117 | + - `public Player->isSneakPressed() : bool` - returns whether the player has intentionally activated sneak mode; may differ from `isSneaking()` when e.g. the player is stuck in a 1.5 block space (@Dasciam) |
| 118 | + - `public Player->setSneakPressed() : void` - sets whether the player has intentionally activated sneak mode (@Dasciam) |
| 119 | +- The following API methods have signature changes: |
| 120 | + - `Player->toggleSneak()` now accepts an optional `bool $sneakPressed = true` parameter (@Dasciam) |
| 121 | + |
| 122 | +### `pocketmine\timings` |
| 123 | +- The following API methods have been added: |
| 124 | + - `public TimingsHandler::createReportFile(string $directory, ?string $fileName = null) : Promise<string>` - writes the current timings state to a file, used by `/timings report` |
| 125 | + |
| 126 | +### `pocketmine\world\generator` |
| 127 | +- `Gaussian` now has additional `kernel1D` and `weightSum1D` public fields. |
| 128 | + |
| 129 | +### `pocketmine\world\generator\object` |
| 130 | +- The following classes have been added: |
| 131 | + - `NetherTree` |
| 132 | +- The following enum cases have been added: |
| 133 | + - `TreeType::CRIMSON` |
| 134 | + - `TreeType::WARPED` |
| 135 | + |
| 136 | +### `pocketmine\world\sound` |
| 137 | +- The following classes have been added: |
| 138 | + - `ArmorEquipCopperSound` |
| 139 | + |
| 140 | +## Internals |
| 141 | +- Docker image source is now managed directly in the main repo for easier version management and first-class testing. (@dktapps) |
| 142 | +- Several improvements have been made to the Docker image (@dktapps): |
| 143 | + - Avoid unnecessary image rebuilds when only PM code changed |
| 144 | + - Caching of prebuilt PHP binaries now works |
| 145 | + - Consistent directory structure between different build stages to remove the need for `php.ini` hacks |
| 146 | + - Added support for `POCKETMINE_ARGS` environment variable to pass custom options to `PocketMine-MP.phar` (e.g. `--no-log-file`) |
| 147 | +- Docker image is now built and tested for every commit. (@dktapps) |
| 148 | +- TesterPlugin framework has been improved to no longer require creating a new class for each test. (@dktapps) |
| 149 | +- PHPStan template types have now been added to event handler internals wherever possible. This is enabled by newer PHPStan improvements. (@dktapps) |
| 150 | +- Reduced boilerplate code in `DefaultPermissions` registration. (@dktapps) |
| 151 | +- Added generated `KnownTranslationParameterInfo`, used by `DefaultPermissions` to check that its constructed translation keys are correct. (@dktapps) |
| 152 | +- `build/generate-registry-annotations.php` will now generate an intersection of parent class and implemented interfaces if an anonymous class is detected. (@dktapps) |
0 commit comments