From bcba064d69928c81510930fa114cc601f28b5070 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Jul 2022 15:16:34 +0100 Subject: [PATCH 01/15] Bump build/php from `1110349` to `f292501` (#5180) Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `1110349` to `f292501`. - [Release notes](https://github.com/pmmp/php-build-scripts/releases) - [Commits](https://github.com/pmmp/php-build-scripts/compare/11103498ca761be83598f9759cc7196c167fcb7e...f292501a703352ab793b07b7861f3e1b3860ed86) --- updated-dependencies: - dependency-name: build/php dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/php b/build/php index 11103498c..f292501a7 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit 11103498ca761be83598f9759cc7196c167fcb7e +Subproject commit f292501a703352ab793b07b7861f3e1b3860ed86 From 6cee428287633f20b8157442ede14383a1a8b4b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Jul 2022 15:18:38 +0100 Subject: [PATCH 02/15] Bump docker/build-push-action from 3.0.0 to 3.1.0 (#5182) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v3.0.0...v3.1.0) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .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 0d1553bcb..a9e6a2e31 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -46,7 +46,7 @@ jobs: run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}") - name: Build image for tag - uses: docker/build-push-action@v3.0.0 + uses: docker/build-push-action@v3.1.0 with: push: true context: ./pocketmine-mp @@ -59,7 +59,7 @@ jobs: - name: Build image for major tag if: steps.channel.outputs.CHANNEL == 'stable' - uses: docker/build-push-action@v3.0.0 + uses: docker/build-push-action@v3.1.0 with: push: true context: ./pocketmine-mp @@ -72,7 +72,7 @@ jobs: - name: Build image for minor tag if: steps.channel.outputs.CHANNEL == 'stable' - uses: docker/build-push-action@v3.0.0 + uses: docker/build-push-action@v3.1.0 with: push: true context: ./pocketmine-mp @@ -85,7 +85,7 @@ jobs: - name: Build image for latest tag if: steps.channel.outputs.CHANNEL == 'stable' - uses: docker/build-push-action@v3.0.0 + uses: docker/build-push-action@v3.1.0 with: push: true context: ./pocketmine-mp From c4f85e526bf9834bb58ebb63cd5c96e0291342b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Jul 2022 15:19:21 +0100 Subject: [PATCH 03/15] Bump shivammathur/setup-php from 2.20.0 to 2.21.0 (#5181) Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.20.0 to 2.21.0. - [Release notes](https://github.com/shivammathur/setup-php/releases) - [Commits](https://github.com/shivammathur/setup-php/compare/2.20.0...2.21.0) --- updated-dependencies: - dependency-name: shivammathur/setup-php dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/draft-release.yml | 2 +- .github/workflows/main.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index 711c9db64..9cb10390e 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -18,7 +18,7 @@ jobs: submodules: true - name: Setup PHP - uses: shivammathur/setup-php@2.20.0 + uses: shivammathur/setup-php@2.21.0 with: php-version: 8.0 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e4ad624f8..08b4e253c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -195,7 +195,7 @@ jobs: - uses: actions/checkout@v3 - name: Setup PHP and tools - uses: shivammathur/setup-php@2.20.0 + uses: shivammathur/setup-php@2.21.0 with: php-version: 8.0 tools: php-cs-fixer:3.2 From 4852f8029a5942f79e537861ae664e645259880a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 21 Jul 2022 23:26:35 +0100 Subject: [PATCH 04/15] AsyncTask: update documentation --- src/scheduler/AsyncTask.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/scheduler/AsyncTask.php b/src/scheduler/AsyncTask.php index 28c7a2957..c65552bf3 100644 --- a/src/scheduler/AsyncTask.php +++ b/src/scheduler/AsyncTask.php @@ -33,19 +33,31 @@ use function spl_object_id; /** * Class used to run async tasks in other threads. * - * An AsyncTask does not have its own thread. It is queued into an AsyncPool and executed if there is an async worker - * with no AsyncTask running. Therefore, an AsyncTask SHOULD NOT execute for more than a few seconds. For tasks that - * run for a long time or infinitely, start another thread instead. + * An AsyncTask is run by a thread pool of reusable threads, and doesn't have its own dedicated thread. A thread is + * usually chosen from the pool at random to run the task (though a specific thread in the pool may be selected + * manually, if needed). + * Reusing threads this way has a much lower performance cost than starting an entirely new thread for every operation. + * AsyncTasks are therefore suitable for brief CPU-bound tasks, such as world generation, compression/decompression of + * data, etc. + * + * AsyncTask SHOULD NOT be used for I/O-bound tasks, such as network I/O, file I/O, database I/O, etc. The server's + * central AsyncPool is used for things like compressing network packets for sending, so using AsyncTask for I/O will + * slow the whole server down, stall chunk loading, etc. + * + * An AsyncTask SHOULD NOT run for more than a few seconds. For tasks that run for a long time or indefinitely, create + * a dedicated thread instead. + * + * The Server instance is not accessible inside {@link AsyncTask::onRun()}. It can only be accessed in the main server + * thread, e.g. during {@link AsyncTask::onCompletion()} or {@link AsyncTask::onProgressUpdate()}. This means that + * whatever you do in onRun() must be able to work without the Server instance. * * WARNING: Any non-Threaded objects WILL BE SERIALIZED when assigned to members of AsyncTasks or other Threaded object. * If later accessed from said Threaded object, you will be operating on a COPY OF THE OBJECT, NOT THE ORIGINAL OBJECT. * If you want to store non-serializable objects to access when the task completes, store them using * {@link AsyncTask::storeLocal}. * - * WARNING: As of pthreads v3.1.6, arrays are converted to Volatile objects when assigned as members of Threaded objects. + * WARNING: Arrays are converted to Volatile objects when assigned as members of Threaded objects. * Keep this in mind when using arrays stored as members of your AsyncTask. - * - * WARNING: Do not call PocketMine-MP API methods from other Threads!! */ abstract class AsyncTask extends \Threaded{ /** From b20e04539d6f499c638750055d30f47941fc6b8a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 22 Jul 2022 19:34:57 +0100 Subject: [PATCH 05/15] Release 4.6.1 --- changelogs/4.6.md | 17 +++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/changelogs/4.6.md b/changelogs/4.6.md index 473edca1f..e32098da6 100644 --- a/changelogs/4.6.md +++ b/changelogs/4.6.md @@ -12,3 +12,20 @@ Released 13th July 2022. ## General - Added support for Minecraft: Bedrock Edition 1.19.10. - Removed support for older versions. + +# 4.6.1 +Released 22nd July 2022. + +## Tools +- `build/generate-registry-annotations.php` now supports processing single files (useful for PhpStorm file watchers). + +## API +- Updated documentation for `AsyncTask`. + +## Fixes +- Fixed incorrect items being displayed in item frames. +- Fixed books not showing in lecterns. +- Fixed incorrect damage interval of Wither status effect. +- Fixed incorrect fire ticks when being set on fire by lava (8 seconds in Bedrock instead of 15). +- `Entity->attack()` now cancels damage from `FIRE` and `FIRE_TICK` damage causes if the entity is fireproof. +- Fixed inventory windows getting force-closed when the client attempts to use an enchanting table or anvil. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 665a2c21d..cec39b47e 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.6.1"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From e10a624444248956e1c01ab49506ce152cc29532 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 22 Jul 2022 19:35:10 +0100 Subject: [PATCH 06/15] 4.6.2 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index cec39b47e..1be7896ff 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.6.1"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.6.2"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 5e3b3a0700956a8c4094696789c862c1d7cb023d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 17:51:02 +0100 Subject: [PATCH 07/15] Fix assert spam on debug clients --- src/entity/Human.php | 13 ++++++++++++- src/world/particle/FloatingTextParticle.php | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/entity/Human.php b/src/entity/Human.php index 683e0c7d6..ae323f0f8 100644 --- a/src/entity/Human.php +++ b/src/entity/Human.php @@ -50,6 +50,7 @@ use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket; +use pocketmine\network\mcpe\protocol\types\command\CommandPermissions; use pocketmine\network\mcpe\protocol\types\DeviceOS; use pocketmine\network\mcpe\protocol\types\entity\EntityIds; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; @@ -57,12 +58,15 @@ use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty; use pocketmine\network\mcpe\protocol\types\GameMode; use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; +use pocketmine\network\mcpe\protocol\types\PlayerPermissions; +use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer; use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket; use pocketmine\player\Player; use pocketmine\utils\Limits; use pocketmine\world\sound\TotemUseSound; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; +use function array_fill; use function array_filter; use function array_key_exists; use function array_merge; @@ -481,7 +485,14 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())), GameMode::SURVIVAL, $this->getAllNetworkData(), - UpdateAbilitiesPacket::create(0, 0, $this->getId() /* TODO: this should be unique ID */, []), + UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->getId() /* TODO: this should be unique ID */, [ + new UpdateAbilitiesPacketLayer( + UpdateAbilitiesPacketLayer::LAYER_BASE, + array_fill(0, UpdateAbilitiesPacketLayer::NUMBER_OF_ABILITIES, false), + 0.0, + 0.0 + ) + ]), [], //TODO: entity links "", //device ID (we intentionally don't send this - secvuln) DeviceOS::UNKNOWN //we intentionally don't send this (secvuln) diff --git a/src/world/particle/FloatingTextParticle.php b/src/world/particle/FloatingTextParticle.php index be1fdd5dc..1534d94fa 100644 --- a/src/world/particle/FloatingTextParticle.php +++ b/src/world/particle/FloatingTextParticle.php @@ -30,6 +30,7 @@ use pocketmine\network\mcpe\convert\SkinAdapterSingleton; use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\RemoveActorPacket; +use pocketmine\network\mcpe\protocol\types\command\CommandPermissions; use pocketmine\network\mcpe\protocol\types\DeviceOS; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; @@ -39,8 +40,11 @@ use pocketmine\network\mcpe\protocol\types\GameMode; use pocketmine\network\mcpe\protocol\types\inventory\ItemStack; use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; +use pocketmine\network\mcpe\protocol\types\PlayerPermissions; +use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer; use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket; use Ramsey\Uuid\Uuid; +use function array_fill; use function str_repeat; class FloatingTextParticle implements Particle{ @@ -119,7 +123,14 @@ class FloatingTextParticle implements Particle{ ItemStackWrapper::legacy(ItemStack::null()), GameMode::SURVIVAL, $actorMetadata, - UpdateAbilitiesPacket::create(0, 0, $this->entityId, []), + UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->entityId, [ + new UpdateAbilitiesPacketLayer( + UpdateAbilitiesPacketLayer::LAYER_BASE, + array_fill(0, UpdateAbilitiesPacketLayer::NUMBER_OF_ABILITIES, false), + 0.0, + 0.0 + ) + ]), [], "", DeviceOS::UNKNOWN From eb916fe43d9b51e63e9715f255d8f93d53373d73 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 24 Jul 2022 19:22:21 +0200 Subject: [PATCH 08/15] Use a falling block entity to improve client side performance of FloatingTextParticle (#4714) Performance tests show that this has a considerable client-side performance advantage over using players. In my local tests, using 1000 floating texts in a 10x10x10 area, I observed an FPS increase from 1.5 to 8.0. --- src/world/particle/FloatingTextParticle.php | 60 +++++++-------------- 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/src/world/particle/FloatingTextParticle.php b/src/world/particle/FloatingTextParticle.php index 1534d94fa..313e40d48 100644 --- a/src/world/particle/FloatingTextParticle.php +++ b/src/world/particle/FloatingTextParticle.php @@ -23,29 +23,20 @@ declare(strict_types=1); namespace pocketmine\world\particle; +use pocketmine\block\VanillaBlocks; use pocketmine\entity\Entity; -use pocketmine\entity\Skin; use pocketmine\math\Vector3; -use pocketmine\network\mcpe\convert\SkinAdapterSingleton; -use pocketmine\network\mcpe\protocol\AddPlayerPacket; -use pocketmine\network\mcpe\protocol\PlayerListPacket; +use pocketmine\network\mcpe\convert\RuntimeBlockMapping; +use pocketmine\network\mcpe\protocol\AddActorPacket; use pocketmine\network\mcpe\protocol\RemoveActorPacket; -use pocketmine\network\mcpe\protocol\types\command\CommandPermissions; -use pocketmine\network\mcpe\protocol\types\DeviceOS; +use pocketmine\network\mcpe\protocol\types\entity\ByteMetadataProperty; +use pocketmine\network\mcpe\protocol\types\entity\EntityIds; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty; +use pocketmine\network\mcpe\protocol\types\entity\IntMetadataProperty; use pocketmine\network\mcpe\protocol\types\entity\LongMetadataProperty; -use pocketmine\network\mcpe\protocol\types\GameMode; -use pocketmine\network\mcpe\protocol\types\inventory\ItemStack; -use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; -use pocketmine\network\mcpe\protocol\types\PlayerListEntry; -use pocketmine\network\mcpe\protocol\types\PlayerPermissions; -use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer; -use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket; -use Ramsey\Uuid\Uuid; -use function array_fill; -use function str_repeat; +use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty; class FloatingTextParticle implements Particle{ //TODO: HACK! @@ -98,45 +89,34 @@ class FloatingTextParticle implements Particle{ } if(!$this->invisible){ - $uuid = Uuid::uuid4(); $name = $this->title . ($this->text !== "" ? "\n" . $this->text : ""); - $p[] = PlayerListPacket::add([PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, SkinAdapterSingleton::get()->toSkinData(new Skin("Standard_Custom", str_repeat("\x00", 8192))))]); - $actorFlags = ( 1 << EntityMetadataFlags::IMMOBILE ); $actorMetadata = [ EntityMetadataProperties::FLAGS => new LongMetadataProperty($actorFlags), - EntityMetadataProperties::SCALE => new FloatMetadataProperty(0.01) //zero causes problems on debug builds + EntityMetadataProperties::SCALE => new FloatMetadataProperty(0.01), //zero causes problems on debug builds + EntityMetadataProperties::BOUNDING_BOX_WIDTH => new FloatMetadataProperty(0.0), + EntityMetadataProperties::BOUNDING_BOX_HEIGHT => new FloatMetadataProperty(0.0), + EntityMetadataProperties::NAMETAG => new StringMetadataProperty($name), + EntityMetadataProperties::VARIANT => new IntMetadataProperty(RuntimeBlockMapping::getInstance()->toRuntimeId(VanillaBlocks::AIR()->getFullId())), + EntityMetadataProperties::ALWAYS_SHOW_NAMETAG => new ByteMetadataProperty(1), ]; - $p[] = AddPlayerPacket::create( - $uuid, - $name, + $p[] = AddActorPacket::create( $this->entityId, //TODO: actor unique ID - "", - $pos, //TODO: check offset + $this->entityId, + EntityIds::FALLING_BLOCK, + $pos, //TODO: check offset (0.49?) null, 0, 0, 0, - ItemStackWrapper::legacy(ItemStack::null()), - GameMode::SURVIVAL, - $actorMetadata, - UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->entityId, [ - new UpdateAbilitiesPacketLayer( - UpdateAbilitiesPacketLayer::LAYER_BASE, - array_fill(0, UpdateAbilitiesPacketLayer::NUMBER_OF_ABILITIES, false), - 0.0, - 0.0 - ) - ]), + 0, [], - "", - DeviceOS::UNKNOWN + $actorMetadata, + [] ); - - $p[] = PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($uuid)]); } return $p; From 3724479be3ae98318624556e7fc38f94f21f3960 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 20:33:35 +0100 Subject: [PATCH 09/15] InGamePacketHandler: improve performance of input flag resolving --- src/network/mcpe/handler/InGamePacketHandler.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index de668992a..00494c71e 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -168,9 +168,10 @@ class InGamePacketHandler extends PacketHandler{ return true; } - private function resolveOnOffInputFlags(PlayerAuthInputPacket $packet, int $startFlag, int $stopFlag) : ?bool{ - $enabled = $packet->hasFlag($startFlag); - if($enabled !== $packet->hasFlag($stopFlag)){ + private function resolveOnOffInputFlags(int $inputFlags, int $startFlag, int $stopFlag) : ?bool{ + $enabled = ($inputFlags & (1 << $startFlag)) !== 0; + $disabled = ($inputFlags & (1 << $stopFlag)) !== 0; + if($enabled !== $disabled){ return $enabled; } //neither flag was set, or both were set @@ -206,10 +207,11 @@ class InGamePacketHandler extends PacketHandler{ // Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock $this->forceMoveSync = false; - $sneaking = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING); - $sprinting = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING); - $swimming = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING); - $gliding = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING); + $inputFlags = $packet->getInputFlags(); + $sneaking = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING); + $sprinting = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING); + $swimming = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING); + $gliding = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING); $mismatch = ($sneaking !== null && !$this->player->toggleSneak($sneaking)) | ($sprinting !== null && !$this->player->toggleSprint($sprinting)) | From b75bc61a6476a363a5c7d1431a39bc4715ae72a5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 20:35:49 +0100 Subject: [PATCH 10/15] InGamePacketHandler: don't bother checking for flag changes if the flag fields are identical we don't need to check this on a bit by bit level if the integers are the same. this saves 2-3 microseconds per packet on my machine, which doesn't sound like much, but it adds up when there are lots of players. --- .../mcpe/handler/InGamePacketHandler.php | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 00494c71e..c4e151d4f 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -145,6 +145,8 @@ class InGamePacketHandler extends PacketHandler{ /** @var UseItemTransactionData|null */ protected $lastRightClickData = null; + protected ?int $lastPlayerAuthInputFlags = null; + /** @var bool */ public $forceMoveSync = false; @@ -208,21 +210,25 @@ class InGamePacketHandler extends PacketHandler{ $this->forceMoveSync = false; $inputFlags = $packet->getInputFlags(); - $sneaking = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING); - $sprinting = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING); - $swimming = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING); - $gliding = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING); - $mismatch = - ($sneaking !== null && !$this->player->toggleSneak($sneaking)) | - ($sprinting !== null && !$this->player->toggleSprint($sprinting)) | - ($swimming !== null && !$this->player->toggleSwim($swimming)) | - ($gliding !== null && !$this->player->toggleGlide($gliding)); - if((bool) $mismatch){ - $this->player->sendData([$this->player]); - } + if($inputFlags !== $this->lastPlayerAuthInputFlags){ + $this->lastPlayerAuthInputFlags = $inputFlags; - if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){ - $this->player->jump(); + $sneaking = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING); + $sprinting = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING); + $swimming = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING); + $gliding = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING); + $mismatch = + ($sneaking !== null && !$this->player->toggleSneak($sneaking)) | + ($sprinting !== null && !$this->player->toggleSprint($sprinting)) | + ($swimming !== null && !$this->player->toggleSwim($swimming)) | + ($gliding !== null && !$this->player->toggleGlide($gliding)); + if((bool) $mismatch){ + $this->player->sendData([$this->player]); + } + + if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){ + $this->player->jump(); + } } if(!$this->forceMoveSync){ From c26631d06dd40fb6204c6135dba8117ffc0f1fc5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 20:44:27 +0100 Subject: [PATCH 11/15] InGamePacketHandler: avoid useless object allocations when forceMoveSync=false (99.9% of the time) --- .../mcpe/handler/InGamePacketHandler.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index c4e151d4f..0306be57c 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -197,17 +197,20 @@ class InGamePacketHandler extends PacketHandler{ $this->player->setRotation($yaw, $pitch); - $curPos = $this->player->getLocation(); $newPos = $rawPos->round(4)->subtract(0, 1.62, 0); - if($this->forceMoveSync && $newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks - $this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos); - //Still getting movements from before teleport, ignore them - return false; - } + if($this->forceMoveSync){ + $curPos = $this->player->getLocation(); - // Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock - $this->forceMoveSync = false; + if($newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks + $this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos); + //Still getting movements from before teleport, ignore them + return false; + } + + // Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock + $this->forceMoveSync = false; + } $inputFlags = $packet->getInputFlags(); if($inputFlags !== $this->lastPlayerAuthInputFlags){ From 608c6ed6db567981f785e484c70c8cc1244d4aa1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 20:51:28 +0100 Subject: [PATCH 12/15] Improved suboptimal code in Player::handleMovement() --- src/player/Player.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index 33be6c4e8..86e18a6c6 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1180,7 +1180,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return; } - $oldPos = $this->getLocation(); + $oldPos = $this->location; $distanceSquared = $newPos->distanceSquared($oldPos); $revert = false; @@ -1198,7 +1198,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * asking for help if you suffer the consequences of messing with this. */ $this->logger->debug("Moved too fast, reverting movement"); - $this->logger->debug("Old position: " . $this->location->asVector3() . ", new position: " . $newPos); + $this->logger->debug("Old position: " . $oldPos->asVector3() . ", new position: " . $newPos); $revert = true; }elseif(!$this->getWorld()->isInLoadedTerrain($newPos)){ $revert = true; @@ -1206,9 +1206,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } if(!$revert && $distanceSquared != 0){ - $dx = $newPos->x - $this->location->x; - $dy = $newPos->y - $this->location->y; - $dz = $newPos->z - $this->location->z; + $dx = $newPos->x - $oldPos->x; + $dy = $newPos->y - $oldPos->y; + $dz = $newPos->z - $oldPos->z; $this->move($dx, $dy, $dz); } From 01ca14c314f180441343bbdf6cff611064ebe330 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 21:00:12 +0100 Subject: [PATCH 13/15] InGamePacketHandler: avoid processing movement if position is unchanged since last tick --- src/network/mcpe/handler/InGamePacketHandler.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 0306be57c..a71fb230c 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -145,6 +145,7 @@ class InGamePacketHandler extends PacketHandler{ /** @var UseItemTransactionData|null */ protected $lastRightClickData = null; + protected ?Vector3 $lastPlayerAuthInputPosition = null; protected ?int $lastPlayerAuthInputFlags = null; /** @var bool */ @@ -197,9 +198,10 @@ class InGamePacketHandler extends PacketHandler{ $this->player->setRotation($yaw, $pitch); + $hasMoved = $this->lastPlayerAuthInputPosition === null || !$this->lastPlayerAuthInputPosition->equals($rawPos); $newPos = $rawPos->round(4)->subtract(0, 1.62, 0); - if($this->forceMoveSync){ + if($this->forceMoveSync && $hasMoved){ $curPos = $this->player->getLocation(); if($newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks @@ -234,7 +236,8 @@ class InGamePacketHandler extends PacketHandler{ } } - if(!$this->forceMoveSync){ + if(!$this->forceMoveSync && $hasMoved){ + $this->lastPlayerAuthInputPosition = $rawPos; //TODO: this packet has WAYYYYY more useful information that we're not using $this->player->handleMovement($newPos); } From 5d9f78303726a6ba58cdda8231976f57a54a73c4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 21:07:35 +0100 Subject: [PATCH 14/15] InGamePacketHandler: do not update player rotation if it didn't change setRotation() does an alarmingly large amount of work... --- .../mcpe/handler/InGamePacketHandler.php | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index a71fb230c..6cf39609e 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -146,6 +146,8 @@ class InGamePacketHandler extends PacketHandler{ protected $lastRightClickData = null; protected ?Vector3 $lastPlayerAuthInputPosition = null; + protected ?float $lastPlayerAuthInputYaw = null; + protected ?float $lastPlayerAuthInputPitch = null; protected ?int $lastPlayerAuthInputFlags = null; /** @var bool */ @@ -183,20 +185,27 @@ class InGamePacketHandler extends PacketHandler{ public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{ $rawPos = $packet->getPosition(); - foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){ + $rawYaw = $packet->getYaw(); + $rawPitch = $packet->getPitch(); + foreach([$rawPos->x, $rawPos->y, $rawPos->z, $rawYaw, $packet->getHeadYaw(), $rawPitch] as $float){ if(is_infinite($float) || is_nan($float)){ $this->session->getLogger()->debug("Invalid movement received, contains NAN/INF components"); return false; } } - $yaw = fmod($packet->getYaw(), 360); - $pitch = fmod($packet->getPitch(), 360); - if($yaw < 0){ - $yaw += 360; - } + if($rawYaw !== $this->lastPlayerAuthInputYaw || $rawPitch !== $this->lastPlayerAuthInputPitch){ + $this->lastPlayerAuthInputYaw = $rawYaw; + $this->lastPlayerAuthInputPitch = $rawPitch; - $this->player->setRotation($yaw, $pitch); + $yaw = fmod($rawYaw, 360); + $pitch = fmod($rawPitch, 360); + if($yaw < 0){ + $yaw += 360; + } + + $this->player->setRotation($yaw, $pitch); + } $hasMoved = $this->lastPlayerAuthInputPosition === null || !$this->lastPlayerAuthInputPosition->equals($rawPos); $newPos = $rawPos->round(4)->subtract(0, 1.62, 0); From 42f9336f7acdd1eecd6691ac4aeca6abfbbaa3c6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Jul 2022 21:16:52 +0100 Subject: [PATCH 15/15] Split packet receive timings into decode and handle subcomponents --- src/network/mcpe/NetworkSession.php | 11 +++++++++-- src/timings/Timings.php | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 9fde7ed23..ee965cfa1 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -374,9 +374,8 @@ class NetworkSession{ throw new PacketHandlingException("Unexpected non-serverbound packet"); } - $timings = Timings::getReceiveDataPacketTimings($packet); + $timings = Timings::getDecodeDataPacketTimings($packet); $timings->startTiming(); - try{ $stream = PacketSerializer::decoder($buffer, 0, $this->packetSerializerContext); try{ @@ -388,7 +387,15 @@ class NetworkSession{ $remains = substr($stream->getBuffer(), $stream->getOffset()); $this->logger->debug("Still " . strlen($remains) . " bytes unread in " . $packet->getName() . ": " . bin2hex($remains)); } + }finally{ + $timings->stopTiming(); + } + $timings = Timings::getHandleDataPacketTimings($packet); + $timings->startTiming(); + try{ + //TODO: I'm not sure DataPacketReceiveEvent should be included in the handler timings, but it needs to be + //included for now to ensure the receivePacket timings are counted the way they were before $ev = new DataPacketReceiveEvent($this, $packet); $ev->call(); if(!$ev->isCancelled() && ($this->handler === null || !$packet->handle($this->handler))){ diff --git a/src/timings/Timings.php b/src/timings/Timings.php index 6f0b38cc7..5d0ece80d 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -119,6 +119,12 @@ abstract class Timings{ public static $tileEntityTypeTimingMap = []; /** @var TimingsHandler[] */ public static $packetReceiveTimingMap = []; + + /** @var TimingsHandler[] */ + private static array $packetDecodeTimingMap = []; + /** @var TimingsHandler[] */ + private static array $packetHandleTimingMap = []; + /** @var TimingsHandler[] */ public static $packetSendTimingMap = []; /** @var TimingsHandler[] */ @@ -229,6 +235,22 @@ abstract class Timings{ return self::$packetReceiveTimingMap[$pid]; } + 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::getReceiveDataPacketTimings($pk) + ); + } + + 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::getReceiveDataPacketTimings($pk) + ); + } + public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{ $pid = $pk->pid(); if(!isset(self::$packetSendTimingMap[$pid])){