Merge branch 'stable' into minor-next

This commit is contained in:
Dylan K. Taylor 2023-04-14 20:12:33 +01:00
commit 84cb070d56
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
10 changed files with 101 additions and 58 deletions

View File

@ -75,3 +75,22 @@ It works similarly to the `ChunkLoader` system, in that chunks will be ticked as
- The following API methods have been added: - The following API methods have been added:
- `public World->registerTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - registers a chunk to be ticked by the given `ChunkTicker` - `public World->registerTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - registers a chunk to be ticked by the given `ChunkTicker`
- `public World->unregisterTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - unregisters a chunk from being ticked by the given `ChunkTicker` - `public World->unregisterTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - unregisters a chunk from being ticked by the given `ChunkTicker`
# 4.19.1
Released 14th April 2023.
## Fixes
- Fixed inventory rollbacks when spreading items in ender chests.
- Fixed inventory rollbacks when shift-clicking to craft and the outputs would have been split across multiple inventory slots.
- Fixed incorrect spawn terrain generation for newly created worlds.
- Fixed `chunk-ticking.tick-radius` not disabling chunk ticking when set to `0`.
- Fixed chunks not being ticked if they previously left a player's simulation distance without leaving their view distance.
- Fixed height of collision boxes for Grass Path and Farmland blocks.
# 4.19.2
Released 14th April 2023.
## Fixes
- Fixed player timings duplication leading to extremely large timings reports when timings runs for a long time with many players.
- Packet timings are now indexed by class FQN instead of packet ID. This prevents erroneous timer reuse on packet ID reuse (e.g. multi version servers).
- Fixed entity timings being shared by different classes with the same short name. This led to incorrect timings being reported for some entities when custom entities were used.

View File

@ -56,7 +56,7 @@
"webmozart/path-util": "^2.3" "webmozart/path-util": "^2.3"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "1.10.11", "phpstan/phpstan": "1.10.13",
"phpstan/phpstan-phpunit": "^1.1.0", "phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0", "phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^9.2" "phpunit/phpunit": "^9.2"

24
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "6cd5185a409af08d842a5e41ba3b877b", "content-hash": "d819da2b086b38c4dd2a5028084e251c",
"packages": [ "packages": [
{ {
"name": "adhocore/json-comment", "name": "adhocore/json-comment",
@ -1884,16 +1884,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.11", "version": "1.10.13",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "8aa62e6ea8b58ffb650e02940e55a788cbc3fe21" "reference": "f07bf8c6980b81bf9e49d44bd0caf2e737614a70"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8aa62e6ea8b58ffb650e02940e55a788cbc3fe21", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f07bf8c6980b81bf9e49d44bd0caf2e737614a70",
"reference": "8aa62e6ea8b58ffb650e02940e55a788cbc3fe21", "reference": "f07bf8c6980b81bf9e49d44bd0caf2e737614a70",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1942,7 +1942,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-04-04T19:17:42+00:00" "time": "2023-04-12T19:29:52+00:00"
}, },
{ {
"name": "phpstan/phpstan-phpunit", "name": "phpstan/phpstan-phpunit",
@ -2365,16 +2365,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "9.6.6", "version": "9.6.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
"reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2448,7 +2448,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.7"
}, },
"funding": [ "funding": [
{ {
@ -2464,7 +2464,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-03-27T11:43:46+00:00" "time": "2023-04-14T08:58:40+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

View File

@ -31,7 +31,7 @@ use function str_repeat;
final class VersionInfo{ final class VersionInfo{
public const NAME = "PocketMine-MP"; public const NAME = "PocketMine-MP";
public const BASE_VERSION = "4.19.1"; public const BASE_VERSION = "4.19.3";
public const IS_DEVELOPMENT_BUILD = true; public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable"; public const BUILD_CHANNEL = "stable";

View File

@ -64,7 +64,7 @@ class Farmland extends Transparent{
* @return AxisAlignedBB[] * @return AxisAlignedBB[]
*/ */
protected function recalculateCollisionBoxes() : array{ protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()]; //TODO: this should be trimmed at the top by 1/16, but MCPE currently treats them as a full block (https://bugs.mojang.com/browse/MCPE-12109) return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{

View File

@ -33,7 +33,7 @@ class GrassPath extends Transparent{
* @return AxisAlignedBB[] * @return AxisAlignedBB[]
*/ */
protected function recalculateCollisionBoxes() : array{ protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()]; //TODO: this should be trimmed at the top by 1/16, but MCPE currently treats them as a full block (https://bugs.mojang.com/browse/MCPE-12109) return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{

View File

@ -167,7 +167,7 @@ class TimingsCommand extends VanillaCommand{
Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_timingsRead( Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_timingsRead(
"https://" . $host . "/?id=" . $response["id"])); "https://" . $host . "/?id=" . $response["id"]));
}else{ }else{
$sender->getServer()->getLogger()->debug("Invalid response from timings server: " . $result->getBody()); $sender->getServer()->getLogger()->debug("Invalid response from timings server (" . $result->getCode() . "): " . $result->getBody());
Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_pasteError()); Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_pasteError());
} }
} }

View File

@ -894,6 +894,31 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
} }
} }
/**
* @param true[] $oldTickingChunks
* @param true[] $newTickingChunks
*
* @phpstan-param array<int, true> $oldTickingChunks
* @phpstan-param array<int, true> $newTickingChunks
*/
private function updateTickingChunkRegistrations(array $oldTickingChunks, array $newTickingChunks) : void{
$world = $this->getWorld();
foreach($oldTickingChunks as $hash => $_){
if(!isset($newTickingChunks[$hash]) && !isset($this->loadQueue[$hash])){
//we are (probably) still using this chunk, but it's no longer within ticking range
World::getXZ($hash, $tickingChunkX, $tickingChunkZ);
$world->unregisterTickingChunk($this->chunkTicker, $tickingChunkX, $tickingChunkZ);
}
}
foreach($newTickingChunks as $hash => $_){
if(!isset($oldTickingChunks[$hash]) && !isset($this->loadQueue[$hash])){
//we were already using this chunk, but it is now within ticking range
World::getXZ($hash, $tickingChunkX, $tickingChunkZ);
$world->registerTickingChunk($this->chunkTicker, $tickingChunkX, $tickingChunkZ);
}
}
}
/** /**
* Calculates which new chunks this player needs to use, and which currently-used chunks it needs to stop using. * Calculates which new chunks this player needs to use, and which currently-used chunks it needs to stop using.
* This is based on factors including the player's current render radius and current position. * This is based on factors including the player's current render radius and current position.
@ -930,15 +955,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
World::getXZ($index, $X, $Z); World::getXZ($index, $X, $Z);
$this->unloadChunk($X, $Z); $this->unloadChunk($X, $Z);
} }
foreach($this->tickingChunks as $hash => $_){
//any chunks we encounter here are still used by the player, but may no longer be within ticking range
if(!isset($tickingChunks[$hash]) && !isset($newOrder[$hash])){
World::getXZ($hash, $tickingChunkX, $tickingChunkZ);
$world->unregisterTickingChunk($this->chunkTicker, $tickingChunkX, $tickingChunkZ);
}
}
$this->loadQueue = $newOrder; $this->loadQueue = $newOrder;
$this->updateTickingChunkRegistrations($this->tickingChunks, $tickingChunks);
$this->tickingChunks = $tickingChunks; $this->tickingChunks = $tickingChunks;
if(count($this->loadQueue) > 0 || count($unloadChunks) > 0){ if(count($this->loadQueue) > 0 || count($unloadChunks) > 0){

View File

@ -250,42 +250,54 @@ abstract class Timings{
return self::$pluginTaskTimingMap[$name]; return self::$pluginTaskTimingMap[$name];
} }
/**
* @phpstan-template T of object
* @phpstan-param class-string<T> $class
*/
private static function shortenCoreClassName(string $class, string $prefix) : string{
if(str_starts_with($class, $prefix)){
return (new \ReflectionClass($class))->getShortName();
}
return $class;
}
public static function getEntityTimings(Entity $entity) : TimingsHandler{ public static function getEntityTimings(Entity $entity) : TimingsHandler{
$reflect = new \ReflectionClass($entity); if(!isset(self::$entityTypeTimingMap[$entity::class])){
$entityType = $reflect->getShortName(); if($entity instanceof Player){
if(!isset(self::$entityTypeTimingMap[$entityType])){ //the timings viewer calculates average player count by looking at this timer, so we need to ensure it has
//the timings viewer calculates average player count by looking at this timer, so we need to ensure it has //a name it can identify. However, we also want to make it obvious if this is a custom Player class.
//a name it can identify. However, we also want to make it obvious if this is a custom Player class. $displayName = $entity::class !== Player::class ? "Player (" . $entity::class . ")" : "Player";
if($entity instanceof Player && $reflect->getName() !== Player::class){ }else{
$entityType = "Player (" . $reflect->getName() . ")"; $displayName = self::shortenCoreClassName($entity::class, "pocketmine\\entity\\");
} }
self::$entityTypeTimingMap[$entityType] = new TimingsHandler("Entity Tick - " . $entityType, self::$tickEntity, group: self::GROUP_BREAKDOWN); self::$entityTypeTimingMap[$entity::class] = new TimingsHandler("Entity Tick - " . $displayName, self::$tickEntity, group: self::GROUP_BREAKDOWN);
} }
return self::$entityTypeTimingMap[$entityType]; return self::$entityTypeTimingMap[$entity::class];
} }
public static function getTileEntityTimings(Tile $tile) : TimingsHandler{ public static function getTileEntityTimings(Tile $tile) : TimingsHandler{
$tileType = (new \ReflectionClass($tile))->getShortName(); if(!isset(self::$tileEntityTypeTimingMap[$tile::class])){
if(!isset(self::$tileEntityTypeTimingMap[$tileType])){ self::$tileEntityTypeTimingMap[$tile::class] = new TimingsHandler(
self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler("Block Entity Tick - " . $tileType, self::$tickTileEntity, group: self::GROUP_BREAKDOWN); "Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\"),
self::$tickTileEntity,
group: self::GROUP_BREAKDOWN
);
} }
return self::$tileEntityTypeTimingMap[$tileType]; return self::$tileEntityTypeTimingMap[$tile::class];
} }
public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
$pid = $pk->pid(); if(!isset(self::$packetReceiveTimingMap[$pk::class])){
if(!isset(self::$packetReceiveTimingMap[$pid])){ self::$packetReceiveTimingMap[$pk::class] = new TimingsHandler("Receive - " . $pk->getName(), self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
self::$packetReceiveTimingMap[$pid] = new TimingsHandler("Receive - " . $pk->getName(), self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
} }
return self::$packetReceiveTimingMap[$pid]; return self::$packetReceiveTimingMap[$pk::class];
} }
public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
$pid = $pk->pid(); return self::$packetDecodeTimingMap[$pk::class] ??= new TimingsHandler(
return self::$packetDecodeTimingMap[$pid] ??= new TimingsHandler(
"Decode - " . $pk->getName(), "Decode - " . $pk->getName(),
self::getReceiveDataPacketTimings($pk), self::getReceiveDataPacketTimings($pk),
group: self::GROUP_BREAKDOWN group: self::GROUP_BREAKDOWN
@ -293,8 +305,7 @@ abstract class Timings{
} }
public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
$pid = $pk->pid(); return self::$packetHandleTimingMap[$pk::class] ??= new TimingsHandler(
return self::$packetHandleTimingMap[$pid] ??= new TimingsHandler(
"Handler - " . $pk->getName(), "Handler - " . $pk->getName(),
self::getReceiveDataPacketTimings($pk), self::getReceiveDataPacketTimings($pk),
group: self::GROUP_BREAKDOWN group: self::GROUP_BREAKDOWN
@ -302,8 +313,7 @@ abstract class Timings{
} }
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{ public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
$pid = $pk->pid(); return self::$packetEncodeTimingMap[$pk::class] ??= new TimingsHandler(
return self::$packetEncodeTimingMap[$pid] ??= new TimingsHandler(
"Encode - " . $pk->getName(), "Encode - " . $pk->getName(),
self::getSendDataPacketTimings($pk), self::getSendDataPacketTimings($pk),
group: self::GROUP_BREAKDOWN group: self::GROUP_BREAKDOWN
@ -311,23 +321,17 @@ abstract class Timings{
} }
public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{ public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
$pid = $pk->pid(); if(!isset(self::$packetSendTimingMap[$pk::class])){
if(!isset(self::$packetSendTimingMap[$pid])){ self::$packetSendTimingMap[$pk::class] = new TimingsHandler("Send - " . $pk->getName(), self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
self::$packetSendTimingMap[$pid] = new TimingsHandler("Send - " . $pk->getName(), self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
} }
return self::$packetSendTimingMap[$pid]; return self::$packetSendTimingMap[$pk::class];
} }
public static function getEventTimings(Event $event) : TimingsHandler{ public static function getEventTimings(Event $event) : TimingsHandler{
$eventClass = get_class($event); $eventClass = get_class($event);
if(!isset(self::$events[$eventClass])){ if(!isset(self::$events[$eventClass])){
if(str_starts_with($eventClass, "pocketmine\\event\\")){ self::$events[$eventClass] = new TimingsHandler(self::shortenCoreClassName($eventClass, "pocketmine\\event\\"), group: "Events");
$name = (new \ReflectionClass($event))->getShortName();
}else{
$name = $eventClass;
}
self::$events[$eventClass] = new TimingsHandler($name, group: "Events");
} }
return self::$events[$eventClass]; return self::$events[$eventClass];

View File

@ -507,7 +507,7 @@ class World implements ChunkManager{
$this->time = $this->provider->getWorldData()->getTime(); $this->time = $this->provider->getWorldData()->getTime();
$cfg = $this->server->getConfigGroup(); $cfg = $this->server->getConfigGroup();
$this->chunkTickRadius = min($this->server->getViewDistance(), max(1, $cfg->getPropertyInt("chunk-ticking.tick-radius", 4))); $this->chunkTickRadius = min($this->server->getViewDistance(), max(0, $cfg->getPropertyInt("chunk-ticking.tick-radius", 4)));
if($cfg->getPropertyInt("chunk-ticking.per-tick", 40) <= 0){ if($cfg->getPropertyInt("chunk-ticking.per-tick", 40) <= 0){
//TODO: this needs l10n //TODO: this needs l10n
$this->logger->warning("\"chunk-ticking.per-tick\" setting is deprecated, but you've used it to disable chunk ticking. Set \"chunk-ticking.tick-radius\" to 0 in \"pocketmine.yml\" instead."); $this->logger->warning("\"chunk-ticking.per-tick\" setting is deprecated, but you've used it to disable chunk ticking. Set \"chunk-ticking.tick-radius\" to 0 in \"pocketmine.yml\" instead.");