diff --git a/README.md b/README.md index 802f9c1dc..e3aa3a6b1 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ GitHub release (latest SemVer) Docker image version (latest semver) Discord +
+ GitHub all releases + GitHub release (latest by SemVer)

## Getting started diff --git a/changelogs/3.26.md b/changelogs/3.26.md index 323c49c74..86a3a2d2e 100644 --- a/changelogs/3.26.md +++ b/changelogs/3.26.md @@ -12,3 +12,12 @@ Plugin developers should **only** update their required API to this version if y # 3.26.1 - Fixed a bug in chunk sending that caused double chests to not be paired, signs to be blank, and various other issues. + +# 3.26.2 +- Improved error messages shown by `start.cmd`, `start.sh` and `start.ps1` when the PHP binary was not found. +- The value of PHPRC is now shown when erroring out due to unsatisfied PHP requirements. +- Removed restriction on the range of valid channels for `auto-updater.channel` in `pocketmine.yml`. + +# 3.26.3 +- `PlayerExperienceChangeEvent->setNewProgress()` now performs range checks. This fixes the root of a very old and confusing crash bug which took several years to identify the cause of. + - Note that the defective plugin(s) which caused this problem will still cause a server crash, but the plugin responsible will now get blamed correctly. diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 6a97299c3..4fc8c4af4 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1523,3 +1523,27 @@ Please note that this was not written with plugins in mind and its API may chang ### Misc - Added support for emotes. + +# 4.0.1 +Released 9th December 2021. + +## General +- Added a script `tools/ping-server.php`. This was sitting in my workspace for many years. +- `Minecraft network interface running` messages are no longer shown if RakLib was prevented from starting. + +## Fixes +### Core +- Fixed server crash when `FallingBlock` has invalid block data that it can't understand. +- Fixed server crash when loading chunks containing tiles outside the world bounds. +- Fixed server crash when loading LevelDB chunks containing blockstates which are invalid or not yet supported - they are now treated as corrupted instead. +- Fixed `level.dat` becoming corrupted by world saves when the disk is full - now it will still fail to save, but it will leave the original data intact. Previously it would destroy the data and leave behind an empty file. +- Fixed configs becoming corrupted when saved when the disk is full - now they'll still fail to save, but the original file will remain intact. + +### API +- Fixed mistakes in the 4.0.0 changelog: + - Removal of `Player->getLowerCaseName()` is now mentioned. + - `CreativeInventory::reset()` is the successor to `Item::initCreativeItems()`, not `CreativeInventory::init()`. + - Note that the changelog when viewing from the 4.0.0 GitHub release will remain the same; only the changelog in the current repo will be different. +- `Config->save()` will no longer write empty data to the file when using JSON and the data fails to encode - an exception will be thrown instead. +- `StringToItemParser` now returns the correct items for `bamboo`, `shulker_box`, `stone_slab`, `stone_stairs` and `tall_grass`. +- `StringToItemParser` now recognizes `slime` and `slime_block` (these were previously missing). diff --git a/src/PocketMine.php b/src/PocketMine.php index 0ff3b5c64..3c38639ed 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -213,6 +213,8 @@ JIT_WARNING } critical_error("PHP binary used: " . $binary); critical_error("Loaded php.ini: " . (($file = php_ini_loaded_file()) !== false ? $file : "none")); + $phprc = getenv("PHPRC"); + critical_error("Value of PHPRC environment variable: " . ($phprc === false ? "" : $phprc)); critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html."); echo PHP_EOL; exit(1); diff --git a/src/command/SimpleCommandMap.php b/src/command/SimpleCommandMap.php index 6b8f392e6..2d18972c5 100644 --- a/src/command/SimpleCommandMap.php +++ b/src/command/SimpleCommandMap.php @@ -206,7 +206,7 @@ class SimpleCommandMap implements CommandMap{ foreach($matches[0] as $k => $_){ for($i = 1; $i <= 2; ++$i){ if($matches[$i][$k] !== ""){ - $args[$k] = stripslashes($matches[$i][$k]); + $args[$k] = $i === 1 ? stripslashes($matches[$i][$k]) : $matches[$i][$k]; break; } } diff --git a/src/entity/ExperienceManager.php b/src/entity/ExperienceManager.php index f06a29e59..f79fdd95f 100644 --- a/src/entity/ExperienceManager.php +++ b/src/entity/ExperienceManager.php @@ -27,7 +27,6 @@ use pocketmine\entity\utils\ExperienceUtils; use pocketmine\event\player\PlayerExperienceChangeEvent; use pocketmine\item\Durable; use pocketmine\item\enchantment\VanillaEnchantments; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Limits; use pocketmine\world\sound\XpCollectSound; use pocketmine\world\sound\XpLevelUpSound; @@ -36,7 +35,6 @@ use function ceil; use function count; use function max; use function min; -use function sprintf; class ExperienceManager{ @@ -146,9 +144,6 @@ class ExperienceManager{ $xpLevel = (int) $newLevel; $xpProgress = $newLevel - (int) $newLevel; - if($xpProgress > 1.0){ - throw new AssumptionFailedError(sprintf("newLevel - (int) newLevel should never be bigger than 1, but have %.53f (newLevel=%.53f)", $xpProgress, $newLevel)); - } return $this->setXpAndProgress($xpLevel, $xpProgress); } diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index d3c7aa70d..248b09d1e 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -71,7 +71,7 @@ class ItemEntity extends Entity{ if($item->isNull()){ throw new \InvalidArgumentException("Item entity must have a non-air item with a count of at least 1"); } - $this->item = $item; + $this->item = clone $item; parent::__construct($location, $nbt); } diff --git a/src/event/player/PlayerExperienceChangeEvent.php b/src/event/player/PlayerExperienceChangeEvent.php index f1569d79d..0ca195bdc 100644 --- a/src/event/player/PlayerExperienceChangeEvent.php +++ b/src/event/player/PlayerExperienceChangeEvent.php @@ -82,6 +82,9 @@ class PlayerExperienceChangeEvent extends EntityEvent implements Cancellable{ } public function setNewProgress(?float $newProgress) : void{ + if($newProgress < 0.0 || $newProgress > 1.0){ + throw new \InvalidArgumentException("XP progress must be in range 0-1"); + } $this->newProgress = $newProgress; } } diff --git a/src/item/WritableBookBase.php b/src/item/WritableBookBase.php index b19de34ba..db0b37574 100644 --- a/src/item/WritableBookBase.php +++ b/src/item/WritableBookBase.php @@ -31,6 +31,7 @@ use function array_push; use function array_slice; use function array_values; use function count; +use function mb_scrub; abstract class WritableBookBase extends Item{ public const TAG_PAGES = "pages"; //TAG_List @@ -168,12 +169,12 @@ abstract class WritableBookBase extends Item{ if($pages->getTagType() === NBT::TAG_Compound){ //PE format /** @var CompoundTag $page */ foreach($pages as $page){ - $this->pages[] = new WritableBookPage($page->getString(self::TAG_PAGE_TEXT), $page->getString(self::TAG_PAGE_PHOTONAME, "")); + $this->pages[] = new WritableBookPage(mb_scrub($page->getString(self::TAG_PAGE_TEXT), 'UTF-8'), $page->getString(self::TAG_PAGE_PHOTONAME, "")); } }elseif($pages->getTagType() === NBT::TAG_String){ //PC format /** @var StringTag $page */ foreach($pages as $page){ - $this->pages[] = new WritableBookPage($page->getValue()); + $this->pages[] = new WritableBookPage(mb_scrub($page->getValue(), 'UTF-8')); } } } diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index c1ab144fe..22949e673 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -28,6 +28,7 @@ use pocketmine\permission\PermissionParser; use pocketmine\permission\PermissionParserException; use function array_map; use function array_values; +use function get_debug_type; use function is_array; use function is_string; use function preg_match; @@ -85,7 +86,18 @@ class PluginDescription{ * @param string|mixed[] $yamlString */ public function __construct($yamlString){ - $this->loadMap(!is_array($yamlString) ? yaml_parse($yamlString) : $yamlString); + if(is_string($yamlString)){ + $map = yaml_parse($yamlString); + if($map === false){ + throw new PluginDescriptionParseException("YAML parsing error in plugin manifest"); + } + if(!is_array($map)){ + throw new PluginDescriptionParseException("Invalid structure of plugin manifest, expected array but have " . get_debug_type($map)); + } + }else{ + $map = $yamlString; + } + $this->loadMap($map); } /** diff --git a/src/updater/UpdateChecker.php b/src/updater/UpdateChecker.php index f7459a1ce..6edced2e0 100644 --- a/src/updater/UpdateChecker.php +++ b/src/updater/UpdateChecker.php @@ -153,6 +153,8 @@ class UpdateChecker{ if($currentVersion->getBuild() > 0 && $currentVersion->compare($newVersion) > 0){ $this->updateInfo = $updateInfo; + }else{ + $this->logger->debug("API reported version is an older version or the same version (" . $newVersion->getFullVersion() . "), not showing notification"); } } @@ -160,12 +162,7 @@ class UpdateChecker{ * Returns the channel used for update checking (stable, beta, dev) */ public function getChannel() : string{ - $channel = strtolower($this->server->getConfigGroup()->getPropertyString("auto-updater.preferred-channel", "stable")); - if($channel !== "stable" and $channel !== "beta" and $channel !== "alpha" and $channel !== "development"){ - $channel = "stable"; - } - - return $channel; + return strtolower($this->server->getConfigGroup()->getPropertyString("auto-updater.preferred-channel", "stable")); } /**