From bd21feffc41e984719a7ade06e3756d5c05b1d38 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Mar 2023 21:45:18 +0000 Subject: [PATCH 01/14] Release 4.18.0-ALPHA1 --- changelogs/4.18-alpha.md | 45 ++++++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 6 +++--- 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 changelogs/4.18-alpha.md diff --git a/changelogs/4.18-alpha.md b/changelogs/4.18-alpha.md new file mode 100644 index 000000000..d2c5998fc --- /dev/null +++ b/changelogs/4.18-alpha.md @@ -0,0 +1,45 @@ +**For Minecraft: Bedrock Edition 1.19.70** + +### Note about API versions +Plugins which don't touch the `pocketmine\network\mcpe` namespace are compatible with any previous 4.x.y version will also run on these releases and do not need API bumps. +Plugin developers should **only** update their required API to this version if you need the changes in this build. + +**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.** +Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly. + +### Alpha release warning +Alpha releases are **experimental**. Features introduced in these releases are subject to change or removal. + +APIs which existed **prior** to this version will continue to work as normal, so plugins which use them will continue to work. + +### Highlights +This version makes changes to the internal network system to improve server performance and reduce memory usage. + +While these changes don't affect non-internal API, they are still significant enough to warrant a new minor version, as they may break plugins which use the internal network API (not recommended). + +# 4.18.0-ALPHA1 +Released 16th March 2023. + +## General +- Improved server performance in congested areas of the world (lots of players and/or entities in the same area). + +## API +### `pocketmine\event\server` +- The following new classes have been added: + - `DataPacketDecodeEvent` - called before a packet is decoded by a `NetworkSession`; useful to mitigate DoS attacks if PocketMine-MP hasn't been patched against new bugs yet + +## Internals +- Introduced new system for broadcasting entity events to network sessions. + - This change improves performance when lots of players and/or entities are in the same area. + - New interface `EntityEventBroadcaster` and class `StandardEntityEventBroadcaster` have been added to implement this. + - All entity-specific `on*()` and `sync*()` methods have been removed from `NetworkSession` (BC break). + - `NetworkSession` now accepts an `EntityEventBroadcaster` instance in its constructor. + - `NetworkBroadcastUtils::broadcastEntityEvent()` can be used to efficiently broadcast events to unique broadcasters shared by several network sessions. +- All network sessions now share the same `PacketSerializerContext` and `PacketBroadcaster` by default. + - Previously, every session had its own context, meaning that broadcast optimisations were not used, causing significant performance losses compared to 3.x. + - This change improves performance in congested areas by allowing reuse of previously encoded packet buffers for all sessions sharing the same context. + - Packet broadcasts are automatically encoded separately per unique `PacketSerializerContext` instance. This allows, for example, a multi-version fork to have a separate context for each protocol version, to ensure maximum broadcast efficiency while encoding different packets for different versions. + - `PacketSerializerContext` is now passed in `NetworkSession::__construct()`, instead of being created by the session. +- `StandardPacketBroadcaster` is now locked to a single `PacketSerializer` context, reducing complexity. +- Introduced `NetworkBroadcastUtils::broadcastPackets()`, replacing `Server->broadcastPackets()`. +- `Server->broadcastPackets()` has been deprecated. It will be removed in a future version. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 880fda698..cecefa7d7 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,9 +31,9 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.17.1"; - public const IS_DEVELOPMENT_BUILD = true; - public const BUILD_CHANNEL = "stable"; + public const BASE_VERSION = "4.18.0-ALPHA1"; + public const IS_DEVELOPMENT_BUILD = false; + public const BUILD_CHANNEL = "alpha"; private function __construct(){ //NOOP From 765aef0810900ac7eadb9b0691b4bddb03da0f43 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Mar 2023 21:45:21 +0000 Subject: [PATCH 02/14] 4.18.0-ALPHA2 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index cecefa7d7..b99f51fc9 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.18.0-ALPHA1"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.18.0-ALPHA2"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "alpha"; private function __construct(){ From 2135776c19f964161f1ad8acfd605f45f0da99fc Mon Sep 17 00:00:00 2001 From: Dylan T Date: Fri, 17 Mar 2023 16:21:57 +0000 Subject: [PATCH 03/14] readme: goodbye docker hub, won't miss you [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1075f1aa..d4a962070 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ ## Getting started - [Documentation](http://pmmp.readthedocs.org/) - [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html) -- [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp) +- [Docker image](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp) - [Plugin repository](https://poggit.pmmp.io/plugins) ## Discussion/Help From 471625e697f1f1fc85154a8a33c3f8c50e33c9b5 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Fri, 17 Mar 2023 16:24:13 +0000 Subject: [PATCH 04/14] readme: remove docker hub shield sadly there isn't any ghcr replacement right now. [ci skip] --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d4a962070..f91fdd31d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@

CI GitHub release (latest SemVer) - Docker image version (latest semver) Discord
GitHub all releases From 2177d8d35274c998486448fb17446e419aa6fe0d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 17 Mar 2023 16:30:37 +0000 Subject: [PATCH 05/14] Push Docker image tags to ghcr.io --- .github/workflows/build-docker-image.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 7ff0925df..4a4b0d35a 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -52,7 +52,7 @@ jobs: context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }} -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }} + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }} build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} @@ -65,7 +65,7 @@ jobs: context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }} -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }} + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }} build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} @@ -78,7 +78,7 @@ jobs: context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }} -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }} + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }} build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} @@ -91,7 +91,7 @@ jobs: context: ./pocketmine-mp tags: | ${{ steps.docker-repo-name.outputs.NAME }}:latest -# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest + ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest build-args: | PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }} PMMP_REPO=${{ github.repository }} From 195bc3b62327806069fa0f6aad227af6a46bf1b3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 18 Mar 2023 21:53:17 +0000 Subject: [PATCH 06/14] NetworkSession: prevent dev client asserts from missing ability flags --- src/network/mcpe/NetworkSession.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 2e3b5b8da..071c754b7 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -904,6 +904,7 @@ class NetworkSession{ AbilitiesLayer::ABILITY_OPEN_CONTAINERS => !$for->isSpectator(), AbilitiesLayer::ABILITY_ATTACK_PLAYERS => !$for->isSpectator(), AbilitiesLayer::ABILITY_ATTACK_MOBS => !$for->isSpectator(), + AbilitiesLayer::ABILITY_PRIVILEGED_BUILDER => false, ]; $this->sendDataPacket(UpdateAbilitiesPacket::create(new AbilitiesData( From 9a969e21c7933ca8f8c9f6f755a23aaa90eb0881 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 18 Mar 2023 22:49:52 +0000 Subject: [PATCH 07/14] =?UTF-8?q?=C3=82NetworkSession:=20ensure=20onResolv?= =?UTF-8?q?e=20handler=20for=20CompressBatchPromise=20is=20covered=20by=20?= =?UTF-8?q?network=20send=20timings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/network/mcpe/NetworkSession.php | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 80f992858..d5ccc3d04 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -561,20 +561,25 @@ class NetworkSession{ $this->compressedQueue->enqueue($payload); $payload->onResolve(function(CompressBatchPromise $payload) : void{ if($this->connected && $this->compressedQueue->bottom() === $payload){ - $this->compressedQueue->dequeue(); //result unused - $this->sendEncoded($payload->getResult()); + Timings::$playerNetworkSend->startTiming(); + try{ + $this->compressedQueue->dequeue(); //result unused + $this->sendEncoded($payload->getResult()); - while(!$this->compressedQueue->isEmpty()){ - /** @var CompressBatchPromise $current */ - $current = $this->compressedQueue->bottom(); - if($current->hasResult()){ - $this->compressedQueue->dequeue(); + while(!$this->compressedQueue->isEmpty()){ + /** @var CompressBatchPromise $current */ + $current = $this->compressedQueue->bottom(); + if($current->hasResult()){ + $this->compressedQueue->dequeue(); - $this->sendEncoded($current->getResult()); - }else{ - //can't send any more queued until this one is ready - break; + $this->sendEncoded($current->getResult()); + }else{ + //can't send any more queued until this one is ready + break; + } } + }finally{ + Timings::$playerNetworkSend->stopTiming(); } } }); From 3d56bd267cb435a422c1573f64f625b57a217c61 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 18 Mar 2023 23:13:25 +0000 Subject: [PATCH 08/14] Timings: fixup network timer inheritance --- src/timings/Timings.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/timings/Timings.php b/src/timings/Timings.php index 1faab0ea1..2d2dbbb0f 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -155,21 +155,22 @@ abstract class Timings{ self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager); self::$titleTick = new TimingsHandler("Console Title Tick"); - self::$playerNetworkSend = new TimingsHandler("Player Network Send"); + self::$connection = new TimingsHandler("Connection Handler"); + + self::$playerNetworkSend = new TimingsHandler("Player Network Send", self::$connection); self::$playerNetworkSendCompress = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression", self::$playerNetworkSend); self::$playerNetworkSendCompressBroadcast = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress); self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress); self::$playerNetworkSendEncrypt = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Encryption", self::$playerNetworkSend); - self::$playerNetworkReceive = new TimingsHandler("Player Network Receive"); + self::$playerNetworkReceive = new TimingsHandler("Player Network Receive", self::$connection); self::$playerNetworkReceiveDecompress = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Receive - Decompression", self::$playerNetworkReceive); self::$playerNetworkReceiveDecrypt = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Receive - Decryption", self::$playerNetworkReceive); self::$broadcastPackets = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Broadcast Packets", self::$playerNetworkSend); self::$playerChunkOrder = new TimingsHandler("Player Order Chunks"); - self::$playerChunkSend = new TimingsHandler("Player Send Chunks"); - self::$connection = new TimingsHandler("Connection Handler"); + self::$playerChunkSend = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Chunks", self::$playerNetworkSend); self::$scheduler = new TimingsHandler("Scheduler"); self::$serverCommand = new TimingsHandler("Server Command"); self::$worldLoad = new TimingsHandler("World Load"); From eec53f9ae0c3300f751e8f3c2f0104adcf781ac5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Mar 2023 15:39:44 +0000 Subject: [PATCH 09/14] Timings: clean up timer names --- src/timings/Timings.php | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/timings/Timings.php b/src/timings/Timings.php index 2d2dbbb0f..3bcaa6735 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -27,9 +27,7 @@ use pocketmine\block\tile\Tile; use pocketmine\entity\Entity; use pocketmine\network\mcpe\protocol\ClientboundPacket; use pocketmine\network\mcpe\protocol\ServerboundPacket; -use pocketmine\player\Player; use pocketmine\scheduler\TaskHandler; -use function dechex; abstract class Timings{ public const INCLUDED_BY_OTHER_TIMINGS_PREFIX = "** "; @@ -184,10 +182,10 @@ abstract class Timings{ self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load"); self::$syncPlayerDataSave = new TimingsHandler("Player Data Save"); - self::$entityMove = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "entityMove"); + self::$entityMove = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Movement"); self::$playerCheckNearEntities = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "checkNearEntities"); - self::$tickEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "tickEntity"); - self::$tickTileEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "tickTileEntity"); + self::$tickEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Tick"); + self::$tickTileEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Block Entity Tick"); self::$entityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "entityBaseTick"); self::$livingEntityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "livingEntityBaseTick"); @@ -195,8 +193,8 @@ abstract class Timings{ self::$schedulerSync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Sync Tasks"); self::$schedulerAsync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Async Tasks"); - self::$playerCommand = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "playerCommand"); - self::$craftingDataCacheRebuild = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "craftingDataCacheRebuild"); + self::$playerCommand = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Command"); + self::$craftingDataCacheRebuild = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Build CraftingDataPacket Cache"); } @@ -219,11 +217,7 @@ abstract class Timings{ public static function getEntityTimings(Entity $entity) : TimingsHandler{ $entityType = (new \ReflectionClass($entity))->getShortName(); if(!isset(self::$entityTypeTimingMap[$entityType])){ - if($entity instanceof Player){ - self::$entityTypeTimingMap[$entityType] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "tickEntity - EntityPlayer", self::$tickEntity); - }else{ - self::$entityTypeTimingMap[$entityType] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "tickEntity - " . $entityType, self::$tickEntity); - } + self::$entityTypeTimingMap[$entityType] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Tick - " . $entityType, self::$tickEntity); } return self::$entityTypeTimingMap[$entityType]; @@ -232,7 +226,7 @@ abstract class Timings{ public static function getTileEntityTimings(Tile $tile) : TimingsHandler{ $tileType = (new \ReflectionClass($tile))->getShortName(); if(!isset(self::$tileEntityTypeTimingMap[$tileType])){ - self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "tickTileEntity - " . $tileType, self::$tickTileEntity); + self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Block Entity Tick - " . $tileType, self::$tickTileEntity); } return self::$tileEntityTypeTimingMap[$tileType]; @@ -241,7 +235,7 @@ abstract class Timings{ public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ $pid = $pk->pid(); if(!isset(self::$packetReceiveTimingMap[$pid])){ - self::$packetReceiveTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "receivePacket - " . $pk->getName() . " [0x" . dechex($pid) . "]", self::$playerNetworkReceive); + self::$packetReceiveTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Receive - " . $pk->getName(), self::$playerNetworkReceive); } return self::$packetReceiveTimingMap[$pid]; @@ -250,7 +244,7 @@ abstract class Timings{ public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ $pid = $pk->pid(); return self::$packetDecodeTimingMap[$pid] ??= new TimingsHandler( - self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Decode - " . $pk->getName() . " [0x" . dechex($pid) . "]", + self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Decode - " . $pk->getName(), self::getReceiveDataPacketTimings($pk) ); } @@ -258,7 +252,7 @@ abstract class Timings{ public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ $pid = $pk->pid(); return self::$packetHandleTimingMap[$pid] ??= new TimingsHandler( - self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Handler - " . $pk->getName() . " [0x" . dechex($pid) . "]", + self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Handler - " . $pk->getName(), self::getReceiveDataPacketTimings($pk) ); } @@ -266,7 +260,7 @@ abstract class Timings{ public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{ $pid = $pk->pid(); return self::$packetEncodeTimingMap[$pid] ??= new TimingsHandler( - self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Encode - " . $pk->getName() . " [0x" . dechex($pid) . "]", + self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Encode - " . $pk->getName(), self::getSendDataPacketTimings($pk) ); } @@ -274,7 +268,7 @@ abstract class Timings{ public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{ $pid = $pk->pid(); if(!isset(self::$packetSendTimingMap[$pid])){ - self::$packetSendTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "sendPacket - " . $pk->getName() . " [0x" . dechex($pid) . "]", self::$playerNetworkSend); + self::$packetSendTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Send - " . $pk->getName(), self::$playerNetworkSend); } return self::$packetSendTimingMap[$pid]; From 607bdfa42f4724a136ba62014468571cfa2c4088 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Mar 2023 15:49:35 +0000 Subject: [PATCH 10/14] Timings: added new timers for entity move collision checks and projectile move ray tracing projectiles get their own distinct sub-timer, since the logic is completely different from regular entities. --- src/entity/Entity.php | 2 ++ src/entity/projectile/Projectile.php | 7 +++++-- src/timings/Timings.php | 11 +++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index c60f2c1c4..c388a741b 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -1139,6 +1139,7 @@ abstract class Entity{ $this->blocksAround = null; Timings::$entityMove->startTiming(); + Timings::$entityMoveCollision->startTiming(); $wantedX = $dx; $wantedY = $dy; @@ -1223,6 +1224,7 @@ abstract class Entity{ $this->boundingBox = $moveBB; } + Timings::$entityMoveCollision->stopTiming(); $this->location = new Location( ($this->boundingBox->minX + $this->boundingBox->maxX) / 2, diff --git a/src/entity/projectile/Projectile.php b/src/entity/projectile/Projectile.php index 68afabd08..b04f8c61b 100644 --- a/src/entity/projectile/Projectile.php +++ b/src/entity/projectile/Projectile.php @@ -175,7 +175,8 @@ abstract class Projectile extends Entity{ protected function move(float $dx, float $dy, float $dz) : void{ $this->blocksAround = null; - Timings::$entityMove->startTiming(); + Timings::$projectileMove->startTiming(); + Timings::$projectileMoveRayTrace->startTiming(); $start = $this->location->asVector3(); $end = $start->add($dx, $dy, $dz); @@ -221,6 +222,8 @@ abstract class Projectile extends Entity{ } } + Timings::$projectileMoveRayTrace->stopTiming(); + $this->location = Location::fromObject( $end, $this->location->world, @@ -268,7 +271,7 @@ abstract class Projectile extends Entity{ $this->getWorld()->onEntityMoved($this); $this->checkBlockIntersections(); - Timings::$entityMove->stopTiming(); + Timings::$projectileMove->stopTiming(); } /** diff --git a/src/timings/Timings.php b/src/timings/Timings.php index 3bcaa6735..fa21dace4 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -89,6 +89,12 @@ abstract class Timings{ /** @var TimingsHandler */ public static $entityMove; + + public static TimingsHandler $entityMoveCollision; + + public static TimingsHandler $projectileMove; + public static TimingsHandler $projectileMoveRayTrace; + /** @var TimingsHandler */ public static $playerCheckNearEntities; /** @var TimingsHandler */ @@ -183,6 +189,11 @@ abstract class Timings{ self::$syncPlayerDataSave = new TimingsHandler("Player Data Save"); self::$entityMove = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Movement"); + self::$entityMoveCollision = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Movement - Collision Checks", self::$entityMove); + + self::$projectileMove = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Projectile Movement", self::$entityMove); + self::$projectileMoveRayTrace = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Projectile Movement - Ray Tracing", self::$projectileMove); + self::$playerCheckNearEntities = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "checkNearEntities"); self::$tickEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Tick"); self::$tickTileEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Block Entity Tick"); From 7bc5d8c824d989eaaaa00d0a9c92355099e4fdfc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Mar 2023 15:57:36 +0000 Subject: [PATCH 11/14] Rename more timers --- src/timings/Timings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/timings/Timings.php b/src/timings/Timings.php index fa21dace4..ad5be83f1 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -198,8 +198,8 @@ abstract class Timings{ self::$tickEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Tick"); self::$tickTileEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Block Entity Tick"); - self::$entityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "entityBaseTick"); - self::$livingEntityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "livingEntityBaseTick"); + self::$entityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick"); + self::$livingEntityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick - Living"); self::$schedulerSync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Sync Tasks"); self::$schedulerAsync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Async Tasks"); From 054c06fab9fe5b050cc2b4802d1502233cfa335e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Mar 2023 15:59:06 +0000 Subject: [PATCH 12/14] Add specialized entityBaseTick timer for item entities since item merging is a potential hotspot, we want to know if this code section is a performance problem. Current timers only tell us whether overall ticking of a particular entity is slow, but that includes movement and therefore isn't particularly helpful. --- src/entity/object/ItemEntity.php | 83 +++++++++++++++++--------------- src/timings/Timings.php | 3 ++ 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index 109b0629c..d28d70773 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -41,6 +41,7 @@ use pocketmine\network\mcpe\protocol\AddItemActorPacket; use pocketmine\network\mcpe\protocol\types\entity\EntityIds; use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; use pocketmine\player\Player; +use pocketmine\timings\Timings; use function max; class ItemEntity extends Entity{ @@ -113,57 +114,63 @@ class ItemEntity extends Entity{ return false; } - $hasUpdate = parent::entityBaseTick($tickDiff); + Timings::$itemEntityBaseTick->startTiming(); + try{ - if($this->isFlaggedForDespawn()){ - return $hasUpdate; - } + $hasUpdate = parent::entityBaseTick($tickDiff); - if($this->pickupDelay !== self::NEVER_DESPAWN && $this->pickupDelay > 0){ //Infinite delay - $hasUpdate = true; - $this->pickupDelay -= $tickDiff; - if($this->pickupDelay < 0){ - $this->pickupDelay = 0; + if($this->isFlaggedForDespawn()){ + return $hasUpdate; } - } - if($this->hasMovementUpdate() && $this->despawnDelay % self::MERGE_CHECK_PERIOD === 0){ - $mergeable = [$this]; //in case the merge target ends up not being this - $mergeTarget = $this; - foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(0.5, 0.5, 0.5), $this) as $entity){ - if(!$entity instanceof ItemEntity || $entity->isFlaggedForDespawn()){ - continue; + if($this->pickupDelay !== self::NEVER_DESPAWN && $this->pickupDelay > 0){ //Infinite delay + $hasUpdate = true; + $this->pickupDelay -= $tickDiff; + if($this->pickupDelay < 0){ + $this->pickupDelay = 0; } + } - if($entity->isMergeable($this)){ - $mergeable[] = $entity; - if($entity->item->getCount() > $mergeTarget->item->getCount()){ - $mergeTarget = $entity; + if($this->hasMovementUpdate() && $this->despawnDelay % self::MERGE_CHECK_PERIOD === 0){ + $mergeable = [$this]; //in case the merge target ends up not being this + $mergeTarget = $this; + foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(0.5, 0.5, 0.5), $this) as $entity){ + if(!$entity instanceof ItemEntity || $entity->isFlaggedForDespawn()){ + continue; + } + + if($entity->isMergeable($this)){ + $mergeable[] = $entity; + if($entity->item->getCount() > $mergeTarget->item->getCount()){ + $mergeTarget = $entity; + } + } + } + foreach($mergeable as $itemEntity){ + if($itemEntity !== $mergeTarget){ + $itemEntity->tryMergeInto($mergeTarget); } } } - foreach($mergeable as $itemEntity){ - if($itemEntity !== $mergeTarget){ - $itemEntity->tryMergeInto($mergeTarget); + + if(!$this->isFlaggedForDespawn() && $this->despawnDelay !== self::NEVER_DESPAWN){ + $hasUpdate = true; + $this->despawnDelay -= $tickDiff; + if($this->despawnDelay <= 0){ + $ev = new ItemDespawnEvent($this); + $ev->call(); + if($ev->isCancelled()){ + $this->despawnDelay = self::DEFAULT_DESPAWN_DELAY; + }else{ + $this->flagForDespawn(); + } } } - } - if(!$this->isFlaggedForDespawn() && $this->despawnDelay !== self::NEVER_DESPAWN){ - $hasUpdate = true; - $this->despawnDelay -= $tickDiff; - if($this->despawnDelay <= 0){ - $ev = new ItemDespawnEvent($this); - $ev->call(); - if($ev->isCancelled()){ - $this->despawnDelay = self::DEFAULT_DESPAWN_DELAY; - }else{ - $this->flagForDespawn(); - } - } + return $hasUpdate; + }finally{ + Timings::$itemEntityBaseTick->stopTiming(); } - - return $hasUpdate; } /** diff --git a/src/timings/Timings.php b/src/timings/Timings.php index ad5be83f1..8e4477405 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -107,6 +107,8 @@ abstract class Timings{ /** @var TimingsHandler */ public static $livingEntityBaseTick; + public static TimingsHandler $itemEntityBaseTick; + /** @var TimingsHandler */ public static $schedulerSync; /** @var TimingsHandler */ @@ -200,6 +202,7 @@ abstract class Timings{ self::$entityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick"); self::$livingEntityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick - Living"); + self::$itemEntityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick - ItemEntity"); self::$schedulerSync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Sync Tasks"); self::$schedulerAsync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Async Tasks"); From 419962d3a2ee6339ac3ac7bf71841a6fc76446f4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Mar 2023 16:12:47 +0000 Subject: [PATCH 13/14] Added timer for player-specific movement code players use an entirely different pathway for movement processing, which could be costly. --- src/player/Player.php | 11 +++++++++++ src/timings/Timings.php | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/player/Player.php b/src/player/Player.php index 8d9afcbc1..e54db939e 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1212,6 +1212,15 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @param Vector3 $newPos Coordinates of the player's feet, centered horizontally at the base of their bounding box. */ public function handleMovement(Vector3 $newPos) : void{ + Timings::$playerMove->startTiming(); + try{ + $this->actuallyHandleMovement($newPos); + }finally{ + Timings::$playerMove->stopTiming(); + } + } + + private function actuallyHandleMovement(Vector3 $newPos) : void{ $this->moveRateLimit--; if($this->moveRateLimit < 0){ return; @@ -1365,6 +1374,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->timings->startTiming(); if($this->spawned){ + Timings::$playerMove->startTiming(); $this->processMostRecentMovements(); $this->motion = new Vector3(0, 0, 0); //TODO: HACK! (Fixes player knockback being messed up) if($this->onGround){ @@ -1372,6 +1382,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ }else{ $this->inAirTicks += $tickDiff; } + Timings::$playerMove->stopTiming(); Timings::$entityBaseTick->startTiming(); $this->entityBaseTick($tickDiff); diff --git a/src/timings/Timings.php b/src/timings/Timings.php index 8e4477405..3359a2eeb 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -148,6 +148,8 @@ abstract class Timings{ /** @var TimingsHandler */ public static $broadcastPackets; + public static TimingsHandler $playerMove; + public static function init() : void{ if(self::$initialized){ return; @@ -175,6 +177,7 @@ abstract class Timings{ self::$broadcastPackets = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Broadcast Packets", self::$playerNetworkSend); + self::$playerMove = new TimingsHandler("Player Movement"); self::$playerChunkOrder = new TimingsHandler("Player Order Chunks"); self::$playerChunkSend = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Chunks", self::$playerNetworkSend); self::$scheduler = new TimingsHandler("Scheduler"); From 2751e1ec02a70a4a53f61540a552714a9d872a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o?= <57811430+SmallkingDev@users.noreply.github.com> Date: Mon, 20 Mar 2023 12:54:28 +0000 Subject: [PATCH 14/14] replacing new Vector3(0, 0, 0) with Vector3::zero() (#5640) --- src/entity/Entity.php | 2 +- src/entity/EntityDataHelper.php | 2 +- src/entity/projectile/Projectile.php | 2 +- src/event/player/PlayerInteractEvent.php | 2 +- src/player/Player.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index c388a741b..69fc684a1 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -246,7 +246,7 @@ abstract class Entity{ if($nbt !== null){ $this->motion = EntityDataHelper::parseVec3($nbt, self::TAG_MOTION, true); }else{ - $this->motion = new Vector3(0, 0, 0); + $this->motion = Vector3::zero(); } $this->resetLastMovements(); diff --git a/src/entity/EntityDataHelper.php b/src/entity/EntityDataHelper.php index 1a15d7458..60e45e535 100644 --- a/src/entity/EntityDataHelper.php +++ b/src/entity/EntityDataHelper.php @@ -80,7 +80,7 @@ final class EntityDataHelper{ public static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional) : Vector3{ $pos = $nbt->getTag($tagName); if($pos === null && $optional){ - return new Vector3(0, 0, 0); + return Vector3::zero(); } if(!($pos instanceof ListTag) || ($pos->getTagType() !== NBT::TAG_Double && $pos->getTagType() !== NBT::TAG_Float)){ throw new SavedDataLoadingException("'$tagName' should be a List or List"); diff --git a/src/entity/projectile/Projectile.php b/src/entity/projectile/Projectile.php index b04f8c61b..56a7eb57e 100644 --- a/src/entity/projectile/Projectile.php +++ b/src/entity/projectile/Projectile.php @@ -255,7 +255,7 @@ abstract class Projectile extends Entity{ } $this->isCollided = $this->onGround = true; - $this->motion = new Vector3(0, 0, 0); + $this->motion = Vector3::zero(); }else{ $this->isCollided = $this->onGround = false; $this->blockHit = null; diff --git a/src/event/player/PlayerInteractEvent.php b/src/event/player/PlayerInteractEvent.php index f28391364..39e94b5d8 100644 --- a/src/event/player/PlayerInteractEvent.php +++ b/src/event/player/PlayerInteractEvent.php @@ -59,7 +59,7 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{ $this->player = $player; $this->item = $item; $this->blockTouched = $block; - $this->touchVector = $touchVector ?? new Vector3(0, 0, 0); + $this->touchVector = $touchVector ?? Vector3::zero(); $this->blockFace = $face; $this->action = $action; } diff --git a/src/player/Player.php b/src/player/Player.php index e54db939e..52eabac17 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1376,7 +1376,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if($this->spawned){ Timings::$playerMove->startTiming(); $this->processMostRecentMovements(); - $this->motion = new Vector3(0, 0, 0); //TODO: HACK! (Fixes player knockback being messed up) + $this->motion = Vector3::zero(); //TODO: HACK! (Fixes player knockback being messed up) if($this->onGround){ $this->inAirTicks = 0; }else{