mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-23 19:34:15 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
commit
a0dadc6e37
@ -109,3 +109,15 @@ Released 5th April 2023.
|
|||||||
- Fixed not being able to drop items directly from the creative inventory on mobile.
|
- Fixed not being able to drop items directly from the creative inventory on mobile.
|
||||||
- Fixed `DataPacketReceiveEvent` not being called for packets sent by `EntityEventBroadcaster`.
|
- Fixed `DataPacketReceiveEvent` not being called for packets sent by `EntityEventBroadcaster`.
|
||||||
- `CreativeInventory::getItem()` and `CreativeInventory::getAll()` now return cloned itemstacks, to prevent accidental modification of the creative inventory.
|
- `CreativeInventory::getItem()` and `CreativeInventory::getAll()` now return cloned itemstacks, to prevent accidental modification of the creative inventory.
|
||||||
|
|
||||||
|
# 4.18.4
|
||||||
|
Released 10th April 2023.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Fixed movement becoming broken when the player moves at high speed (e.g. due to high levels of the Speed effect).
|
||||||
|
- Updated dependencies to get fixes in `pocketmine/nbt` and `pocketmine/bedrock-protocol`.
|
||||||
|
|
||||||
|
## Internals
|
||||||
|
### Network
|
||||||
|
- Game packets are now rate-limited in a similar manner to packet batches. This helps to more effectively mitigate certain types of DoS attacks.
|
||||||
|
- Added a new class `PacketRateLimiter`, implementing functionality previously baked directly into `NetworkSession` in a more generic way to allow reuse.
|
||||||
|
52
composer.lock
generated
52
composer.lock
generated
@ -199,16 +199,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "netresearch/jsonmapper",
|
"name": "netresearch/jsonmapper",
|
||||||
"version": "v4.1.0",
|
"version": "v4.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||||
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f"
|
"reference": "f60565f8c0566a31acf06884cdaa591867ecc956"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
|
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956",
|
||||||
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
|
"reference": "f60565f8c0566a31acf06884cdaa591867ecc956",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -244,9 +244,9 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"email": "cweiske@cweiske.de",
|
"email": "cweiske@cweiske.de",
|
||||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0"
|
"source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0"
|
||||||
},
|
},
|
||||||
"time": "2022-12-08T20:46:14+00:00"
|
"time": "2023-04-09T17:37:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||||
@ -328,16 +328,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-protocol",
|
"name": "pocketmine/bedrock-protocol",
|
||||||
"version": "20.1.1+bedrock-1.19.70",
|
"version": "20.1.2+bedrock-1.19.70",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||||
"reference": "455dbad93d29b4489b60910a41e38b8007b26563"
|
"reference": "2787c531039b3d92fa3ec92f28b95158dc24b915"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/455dbad93d29b4489b60910a41e38b8007b26563",
|
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/2787c531039b3d92fa3ec92f28b95158dc24b915",
|
||||||
"reference": "455dbad93d29b4489b60910a41e38b8007b26563",
|
"reference": "2787c531039b3d92fa3ec92f28b95158dc24b915",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -369,9 +369,9 @@
|
|||||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/20.1.1+bedrock-1.19.70"
|
"source": "https://github.com/pmmp/BedrockProtocol/tree/20.1.2+bedrock-1.19.70"
|
||||||
},
|
},
|
||||||
"time": "2023-03-29T22:38:17+00:00"
|
"time": "2023-04-10T11:40:32+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/binaryutils",
|
"name": "pocketmine/binaryutils",
|
||||||
@ -512,23 +512,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/color",
|
"name": "pocketmine/color",
|
||||||
"version": "0.3.0",
|
"version": "0.3.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/Color.git",
|
"url": "https://github.com/pmmp/Color.git",
|
||||||
"reference": "8cb346d0a21ad3287cc8d7175e4b643416607249"
|
"reference": "a0421f1e9e0b0c619300fb92d593283378f6a5e1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/Color/zipball/8cb346d0a21ad3287cc8d7175e4b643416607249",
|
"url": "https://api.github.com/repos/pmmp/Color/zipball/a0421f1e9e0b0c619300fb92d593283378f6a5e1",
|
||||||
"reference": "8cb346d0a21ad3287cc8d7175e4b643416607249",
|
"reference": "a0421f1e9e0b0c619300fb92d593283378f6a5e1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.0"
|
"php": "^8.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "1.9.4",
|
"phpstan/phpstan": "1.10.3",
|
||||||
"phpstan/phpstan-strict-rules": "^1.2.0"
|
"phpstan/phpstan-strict-rules": "^1.2.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -544,9 +544,9 @@
|
|||||||
"description": "Color handling library used by PocketMine-MP and related projects",
|
"description": "Color handling library used by PocketMine-MP and related projects",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/Color/issues",
|
"issues": "https://github.com/pmmp/Color/issues",
|
||||||
"source": "https://github.com/pmmp/Color/tree/0.3.0"
|
"source": "https://github.com/pmmp/Color/tree/0.3.1"
|
||||||
},
|
},
|
||||||
"time": "2022-12-18T19:49:21+00:00"
|
"time": "2023-04-10T11:38:05+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/errorhandler",
|
"name": "pocketmine/errorhandler",
|
||||||
@ -738,16 +738,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/nbt",
|
"name": "pocketmine/nbt",
|
||||||
"version": "0.3.3",
|
"version": "0.3.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/NBT.git",
|
"url": "https://github.com/pmmp/NBT.git",
|
||||||
"reference": "f4321be50df1a18b9f4e94d428a2e68a6e2ac2b4"
|
"reference": "62c02464c6708b2467c1e1a2af01af09d5114eda"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/f4321be50df1a18b9f4e94d428a2e68a6e2ac2b4",
|
"url": "https://api.github.com/repos/pmmp/NBT/zipball/62c02464c6708b2467c1e1a2af01af09d5114eda",
|
||||||
"reference": "f4321be50df1a18b9f4e94d428a2e68a6e2ac2b4",
|
"reference": "62c02464c6708b2467c1e1a2af01af09d5114eda",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -757,7 +757,7 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/extension-installer": "^1.0",
|
"phpstan/extension-installer": "^1.0",
|
||||||
"phpstan/phpstan": "1.7.7",
|
"phpstan/phpstan": "1.10.3",
|
||||||
"phpstan/phpstan-strict-rules": "^1.0",
|
"phpstan/phpstan-strict-rules": "^1.0",
|
||||||
"phpunit/phpunit": "^9.5"
|
"phpunit/phpunit": "^9.5"
|
||||||
},
|
},
|
||||||
@ -774,9 +774,9 @@
|
|||||||
"description": "PHP library for working with Named Binary Tags",
|
"description": "PHP library for working with Named Binary Tags",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/NBT/issues",
|
"issues": "https://github.com/pmmp/NBT/issues",
|
||||||
"source": "https://github.com/pmmp/NBT/tree/0.3.3"
|
"source": "https://github.com/pmmp/NBT/tree/0.3.4"
|
||||||
},
|
},
|
||||||
"time": "2022-07-06T14:13:26+00:00"
|
"time": "2023-04-10T11:31:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/raklib",
|
"name": "pocketmine/raklib",
|
||||||
|
@ -163,6 +163,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());
|
||||||
Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_pasteError());
|
Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_pasteError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
|||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||||
use pocketmine\player\Player;
|
use pocketmine\player\Player;
|
||||||
|
use function max;
|
||||||
use function sqrt;
|
use function sqrt;
|
||||||
|
|
||||||
class ExperienceOrb extends Entity{
|
class ExperienceOrb extends Entity{
|
||||||
@ -48,6 +49,10 @@ class ExperienceOrb extends Entity{
|
|||||||
/** Split sizes used for dropping experience orbs. */
|
/** Split sizes used for dropping experience orbs. */
|
||||||
public const ORB_SPLIT_SIZES = [2477, 1237, 617, 307, 149, 73, 37, 17, 7, 3, 1]; //This is indexed biggest to smallest so that we can return as soon as we found the biggest value.
|
public const ORB_SPLIT_SIZES = [2477, 1237, 617, 307, 149, 73, 37, 17, 7, 3, 1]; //This is indexed biggest to smallest so that we can return as soon as we found the biggest value.
|
||||||
|
|
||||||
|
public const DEFAULT_DESPAWN_DELAY = 6000;
|
||||||
|
public const NEVER_DESPAWN = -1;
|
||||||
|
public const MAX_DESPAWN_DELAY = 32767 + self::DEFAULT_DESPAWN_DELAY; //max value storable by mojang NBT :(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the largest size of normal XP orb that will be spawned for the specified amount of XP. Used to split XP
|
* Returns the largest size of normal XP orb that will be spawned for the specified amount of XP. Used to split XP
|
||||||
* up into multiple orbs when an amount of XP is dropped.
|
* up into multiple orbs when an amount of XP is dropped.
|
||||||
@ -79,6 +84,7 @@ class ExperienceOrb extends Entity{
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated */
|
||||||
protected int $age = 0;
|
protected int $age = 0;
|
||||||
|
|
||||||
/** Ticker used for determining interval in which to look for new target players. */
|
/** Ticker used for determining interval in which to look for new target players. */
|
||||||
@ -89,6 +95,8 @@ class ExperienceOrb extends Entity{
|
|||||||
|
|
||||||
protected int $xpValue;
|
protected int $xpValue;
|
||||||
|
|
||||||
|
private int $despawnDelay = self::DEFAULT_DESPAWN_DELAY;
|
||||||
|
|
||||||
public function __construct(Location $location, int $xpValue, ?CompoundTag $nbt = null){
|
public function __construct(Location $location, int $xpValue, ?CompoundTag $nbt = null){
|
||||||
$this->xpValue = $xpValue;
|
$this->xpValue = $xpValue;
|
||||||
parent::__construct($location, $nbt);
|
parent::__construct($location, $nbt);
|
||||||
@ -104,12 +112,22 @@ class ExperienceOrb extends Entity{
|
|||||||
parent::initEntity($nbt);
|
parent::initEntity($nbt);
|
||||||
|
|
||||||
$this->age = $nbt->getShort(self::TAG_AGE, 0);
|
$this->age = $nbt->getShort(self::TAG_AGE, 0);
|
||||||
|
if($this->age === -32768){
|
||||||
|
$this->despawnDelay = self::NEVER_DESPAWN;
|
||||||
|
}else{
|
||||||
|
$this->despawnDelay = max(0, self::DEFAULT_DESPAWN_DELAY - $this->age);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveNBT() : CompoundTag{
|
public function saveNBT() : CompoundTag{
|
||||||
$nbt = parent::saveNBT();
|
$nbt = parent::saveNBT();
|
||||||
|
|
||||||
$nbt->setShort(self::TAG_AGE, $this->age);
|
if($this->despawnDelay === self::NEVER_DESPAWN){
|
||||||
|
$age = -32768;
|
||||||
|
}else{
|
||||||
|
$age = self::DEFAULT_DESPAWN_DELAY - $this->despawnDelay;
|
||||||
|
}
|
||||||
|
$nbt->setShort(self::TAG_AGE, $age);
|
||||||
|
|
||||||
$nbt->setShort(self::TAG_VALUE_PC, $this->getXpValue());
|
$nbt->setShort(self::TAG_VALUE_PC, $this->getXpValue());
|
||||||
$nbt->setInt(self::TAG_VALUE_PE, $this->getXpValue());
|
$nbt->setInt(self::TAG_VALUE_PE, $this->getXpValue());
|
||||||
@ -117,6 +135,15 @@ class ExperienceOrb extends Entity{
|
|||||||
return $nbt;
|
return $nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDespawnDelay() : int{ return $this->despawnDelay; }
|
||||||
|
|
||||||
|
public function setDespawnDelay(int $despawnDelay) : void{
|
||||||
|
if(($despawnDelay < 0 || $despawnDelay > self::MAX_DESPAWN_DELAY) && $despawnDelay !== self::NEVER_DESPAWN){
|
||||||
|
throw new \InvalidArgumentException("Despawn ticker must be in range 0 ... " . self::MAX_DESPAWN_DELAY . " or " . self::NEVER_DESPAWN . ", got $despawnDelay");
|
||||||
|
}
|
||||||
|
$this->despawnDelay = $despawnDelay;
|
||||||
|
}
|
||||||
|
|
||||||
public function getXpValue() : int{
|
public function getXpValue() : int{
|
||||||
return $this->xpValue;
|
return $this->xpValue;
|
||||||
}
|
}
|
||||||
@ -154,7 +181,8 @@ class ExperienceOrb extends Entity{
|
|||||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
$hasUpdate = parent::entityBaseTick($tickDiff);
|
||||||
|
|
||||||
$this->age += $tickDiff;
|
$this->age += $tickDiff;
|
||||||
if($this->age > 6000){
|
$this->despawnDelay -= $tickDiff;
|
||||||
|
if($this->despawnDelay <= 0){
|
||||||
$this->flagForDespawn();
|
$this->flagForDespawn();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -58,16 +58,9 @@ abstract class Event{
|
|||||||
|
|
||||||
++self::$eventCallDepth;
|
++self::$eventCallDepth;
|
||||||
try{
|
try{
|
||||||
foreach(EventPriority::ALL as $priority){
|
foreach($handlerList->getListenerList() as $registration){
|
||||||
$currentList = $handlerList;
|
|
||||||
while($currentList !== null){
|
|
||||||
foreach($currentList->getListenersByPriority($priority) as $registration){
|
|
||||||
$registration->callEvent($this);
|
$registration->callEvent($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
$currentList = $currentList->getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}finally{
|
}finally{
|
||||||
--self::$eventCallDepth;
|
--self::$eventCallDepth;
|
||||||
$timings->stopTiming();
|
$timings->stopTiming();
|
||||||
|
@ -32,6 +32,8 @@ use function mb_strtoupper;
|
|||||||
* LOWEST -> LOW -> NORMAL -> HIGH -> HIGHEST -> MONITOR
|
* LOWEST -> LOW -> NORMAL -> HIGH -> HIGHEST -> MONITOR
|
||||||
*
|
*
|
||||||
* MONITOR events should not change the event outcome or contents
|
* MONITOR events should not change the event outcome or contents
|
||||||
|
*
|
||||||
|
* WARNING: If these values are changed, handler sorting in HandlerList::getListenerList() may need to be updated.
|
||||||
*/
|
*/
|
||||||
final class EventPriority{
|
final class EventPriority{
|
||||||
|
|
||||||
|
@ -24,13 +24,20 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\event;
|
namespace pocketmine\event;
|
||||||
|
|
||||||
use pocketmine\plugin\Plugin;
|
use pocketmine\plugin\Plugin;
|
||||||
use function array_fill_keys;
|
use function array_merge;
|
||||||
|
use function krsort;
|
||||||
use function spl_object_id;
|
use function spl_object_id;
|
||||||
|
use const SORT_NUMERIC;
|
||||||
|
|
||||||
class HandlerList{
|
class HandlerList{
|
||||||
/** @var RegisteredListener[][] */
|
/** @var RegisteredListener[][] */
|
||||||
private array $handlerSlots = [];
|
private array $handlerSlots = [];
|
||||||
|
|
||||||
|
private RegisteredListenerCache $handlerCache;
|
||||||
|
|
||||||
|
/** @var RegisteredListenerCache[] */
|
||||||
|
private array $affectedHandlerCaches = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-template TEvent of Event
|
* @phpstan-template TEvent of Event
|
||||||
* @phpstan-param class-string<TEvent> $class
|
* @phpstan-param class-string<TEvent> $class
|
||||||
@ -39,7 +46,10 @@ class HandlerList{
|
|||||||
private string $class,
|
private string $class,
|
||||||
private ?HandlerList $parentList
|
private ?HandlerList $parentList
|
||||||
){
|
){
|
||||||
$this->handlerSlots = array_fill_keys(EventPriority::ALL, []);
|
$this->handlerCache = new RegisteredListenerCache();
|
||||||
|
for($list = $this; $list !== null; $list = $list->parentList){
|
||||||
|
$list->affectedHandlerCaches[spl_object_id($this->handlerCache)] = $this->handlerCache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +60,7 @@ class HandlerList{
|
|||||||
throw new \InvalidArgumentException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}");
|
throw new \InvalidArgumentException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}");
|
||||||
}
|
}
|
||||||
$this->handlerSlots[$listener->getPriority()][spl_object_id($listener)] = $listener;
|
$this->handlerSlots[$listener->getPriority()][spl_object_id($listener)] = $listener;
|
||||||
|
$this->invalidateAffectedCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,6 +70,7 @@ class HandlerList{
|
|||||||
foreach($listeners as $listener){
|
foreach($listeners as $listener){
|
||||||
$this->register($listener);
|
$this->register($listener);
|
||||||
}
|
}
|
||||||
|
$this->invalidateAffectedCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unregister(RegisteredListener|Plugin|Listener $object) : void{
|
public function unregister(RegisteredListener|Plugin|Listener $object) : void{
|
||||||
@ -73,14 +85,14 @@ class HandlerList{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(isset($this->handlerSlots[$object->getPriority()][spl_object_id($object)])){
|
|
||||||
unset($this->handlerSlots[$object->getPriority()][spl_object_id($object)]);
|
unset($this->handlerSlots[$object->getPriority()][spl_object_id($object)]);
|
||||||
}
|
}
|
||||||
}
|
$this->invalidateAffectedCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clear() : void{
|
public function clear() : void{
|
||||||
$this->handlerSlots = array_fill_keys(EventPriority::ALL, []);
|
$this->handlerSlots = [];
|
||||||
|
$this->invalidateAffectedCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,4 +105,40 @@ class HandlerList{
|
|||||||
public function getParent() : ?HandlerList{
|
public function getParent() : ?HandlerList{
|
||||||
return $this->parentList;
|
return $this->parentList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates all known caches which might be affected by this list's contents.
|
||||||
|
*/
|
||||||
|
private function invalidateAffectedCaches() : void{
|
||||||
|
foreach($this->affectedHandlerCaches as $cache){
|
||||||
|
$cache->list = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return RegisteredListener[]
|
||||||
|
* @phpstan-return list<RegisteredListener>
|
||||||
|
*/
|
||||||
|
public function getListenerList() : array{
|
||||||
|
if($this->handlerCache->list !== null){
|
||||||
|
return $this->handlerCache->list;
|
||||||
|
}
|
||||||
|
|
||||||
|
$handlerLists = [];
|
||||||
|
for($currentList = $this; $currentList !== null; $currentList = $currentList->parentList){
|
||||||
|
$handlerLists[] = $currentList;
|
||||||
|
}
|
||||||
|
|
||||||
|
$listenersByPriority = [];
|
||||||
|
foreach($handlerLists as $currentList){
|
||||||
|
foreach($currentList->handlerSlots as $priority => $listeners){
|
||||||
|
$listenersByPriority[$priority] = array_merge($listenersByPriority[$priority] ?? [], $listeners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: why on earth do the priorities have higher values for lower priority?
|
||||||
|
krsort($listenersByPriority, SORT_NUMERIC);
|
||||||
|
|
||||||
|
return $this->handlerCache->list = array_merge(...$listenersByPriority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
35
src/event/RegisteredListenerCache.php
Normal file
35
src/event/RegisteredListenerCache.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\event;
|
||||||
|
|
||||||
|
final class RegisteredListenerCache{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all handlers that will be called for a particular event, ordered by execution order.
|
||||||
|
*
|
||||||
|
* @var RegisteredListener[]
|
||||||
|
* @phpstan-var list<RegisteredListener>
|
||||||
|
*/
|
||||||
|
public ?array $list = null;
|
||||||
|
}
|
@ -114,11 +114,8 @@ use function base64_encode;
|
|||||||
use function bin2hex;
|
use function bin2hex;
|
||||||
use function count;
|
use function count;
|
||||||
use function get_class;
|
use function get_class;
|
||||||
use function hrtime;
|
|
||||||
use function in_array;
|
use function in_array;
|
||||||
use function intdiv;
|
|
||||||
use function json_encode;
|
use function json_encode;
|
||||||
use function min;
|
|
||||||
use function random_bytes;
|
use function random_bytes;
|
||||||
use function strcasecmp;
|
use function strcasecmp;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
@ -129,19 +126,14 @@ use function ucfirst;
|
|||||||
use const JSON_THROW_ON_ERROR;
|
use const JSON_THROW_ON_ERROR;
|
||||||
|
|
||||||
class NetworkSession{
|
class NetworkSession{
|
||||||
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions may arrive separately
|
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions arrive separately
|
||||||
private const INCOMING_PACKET_BATCH_MAX_BUDGET = 100 * self::INCOMING_PACKET_BATCH_PER_TICK; //enough to account for a 5-second lag spike
|
private const INCOMING_PACKET_BATCH_BUFFER_TICKS = 100; //enough to account for a 5-second lag spike
|
||||||
|
|
||||||
/**
|
private const INCOMING_GAME_PACKETS_PER_TICK = 2;
|
||||||
* At most this many more packets can be received. If this reaches zero, any additional packets received will cause
|
private const INCOMING_GAME_PACKETS_BUFFER_TICKS = 100;
|
||||||
* the player to be kicked from the server.
|
|
||||||
* This number is increased every tick up to a maximum limit.
|
private PacketRateLimiter $packetBatchLimiter;
|
||||||
*
|
private PacketRateLimiter $gamePacketLimiter;
|
||||||
* @see self::INCOMING_PACKET_BATCH_PER_TICK
|
|
||||||
* @see self::INCOMING_PACKET_BATCH_MAX_BUDGET
|
|
||||||
*/
|
|
||||||
private int $incomingPacketBatchBudget = self::INCOMING_PACKET_BATCH_MAX_BUDGET;
|
|
||||||
private int $lastPacketBudgetUpdateTimeNs;
|
|
||||||
|
|
||||||
private \PrefixedLogger $logger;
|
private \PrefixedLogger $logger;
|
||||||
private ?Player $player = null;
|
private ?Player $player = null;
|
||||||
@ -197,7 +189,8 @@ class NetworkSession{
|
|||||||
$this->disposeHooks = new ObjectSet();
|
$this->disposeHooks = new ObjectSet();
|
||||||
|
|
||||||
$this->connectTime = time();
|
$this->connectTime = time();
|
||||||
$this->lastPacketBudgetUpdateTimeNs = hrtime(true);
|
$this->packetBatchLimiter = new PacketRateLimiter("Packet Batches", self::INCOMING_PACKET_BATCH_PER_TICK, self::INCOMING_PACKET_BATCH_BUFFER_TICKS);
|
||||||
|
$this->gamePacketLimiter = new PacketRateLimiter("Game Packets", self::INCOMING_GAME_PACKETS_PER_TICK, self::INCOMING_GAME_PACKETS_BUFFER_TICKS);
|
||||||
|
|
||||||
$this->setHandler(new SessionStartPacketHandler(
|
$this->setHandler(new SessionStartPacketHandler(
|
||||||
$this,
|
$this,
|
||||||
@ -341,13 +334,7 @@ class NetworkSession{
|
|||||||
|
|
||||||
Timings::$playerNetworkReceive->startTiming();
|
Timings::$playerNetworkReceive->startTiming();
|
||||||
try{
|
try{
|
||||||
if($this->incomingPacketBatchBudget <= 0){
|
$this->packetBatchLimiter->decrement();
|
||||||
$this->updatePacketBudget();
|
|
||||||
if($this->incomingPacketBatchBudget <= 0){
|
|
||||||
throw new PacketHandlingException("Receiving packets too fast");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->incomingPacketBatchBudget--;
|
|
||||||
|
|
||||||
if($this->cipher !== null){
|
if($this->cipher !== null){
|
||||||
Timings::$playerNetworkReceiveDecrypt->startTiming();
|
Timings::$playerNetworkReceiveDecrypt->startTiming();
|
||||||
@ -379,6 +366,7 @@ class NetworkSession{
|
|||||||
$stream = new BinaryStream($decompressed);
|
$stream = new BinaryStream($decompressed);
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach(PacketBatch::decodeRaw($stream) as $buffer){
|
foreach(PacketBatch::decodeRaw($stream) as $buffer){
|
||||||
|
$this->gamePacketLimiter->decrement();
|
||||||
if(++$count > 100){
|
if(++$count > 100){
|
||||||
throw new PacketHandlingException("Too many packets in batch");
|
throw new PacketHandlingException("Too many packets in batch");
|
||||||
}
|
}
|
||||||
@ -1150,23 +1138,6 @@ class NetworkSession{
|
|||||||
$this->sendDataPacket(ToastRequestPacket::create($title, $body));
|
$this->sendDataPacket(ToastRequestPacket::create($title, $body));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updatePacketBudget() : void{
|
|
||||||
$nowNs = hrtime(true);
|
|
||||||
$timeSinceLastUpdateNs = $nowNs - $this->lastPacketBudgetUpdateTimeNs;
|
|
||||||
if($timeSinceLastUpdateNs > 50_000_000){
|
|
||||||
$ticksSinceLastUpdate = intdiv($timeSinceLastUpdateNs, 50_000_000);
|
|
||||||
/*
|
|
||||||
* If the server takes an abnormally long time to process a tick, add the budget for time difference to
|
|
||||||
* compensate. This extra budget may be very large, but it will disappear the next time a normal update
|
|
||||||
* occurs. This ensures that backlogs during a large lag spike don't cause everyone to get kicked.
|
|
||||||
* As long as all the backlogged packets are processed before the next tick, everything should be OK for
|
|
||||||
* clients behaving normally.
|
|
||||||
*/
|
|
||||||
$this->incomingPacketBatchBudget = min($this->incomingPacketBatchBudget, self::INCOMING_PACKET_BATCH_MAX_BUDGET) + (self::INCOMING_PACKET_BATCH_PER_TICK * 2 * $ticksSinceLastUpdate);
|
|
||||||
$this->lastPacketBudgetUpdateTimeNs = $nowNs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tick() : void{
|
public function tick() : void{
|
||||||
if(!$this->isConnected()){
|
if(!$this->isConnected()){
|
||||||
$this->dispose();
|
$this->dispose();
|
||||||
|
81
src/network/mcpe/PacketRateLimiter.php
Normal file
81
src/network/mcpe/PacketRateLimiter.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\network\mcpe;
|
||||||
|
|
||||||
|
use pocketmine\network\PacketHandlingException;
|
||||||
|
use function hrtime;
|
||||||
|
use function intdiv;
|
||||||
|
use function min;
|
||||||
|
|
||||||
|
final class PacketRateLimiter{
|
||||||
|
/**
|
||||||
|
* At most this many more packets can be received. If this reaches zero, any additional packets received will cause
|
||||||
|
* the player to be kicked from the server.
|
||||||
|
* This number is increased every tick up to a maximum limit, and decreased by one every time a packet is received.
|
||||||
|
*/
|
||||||
|
private int $budget;
|
||||||
|
private int $lastUpdateTimeNs;
|
||||||
|
private int $maxBudget;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private string $name,
|
||||||
|
private int $averagePerTick,
|
||||||
|
int $maxBufferTicks,
|
||||||
|
private int $updateFrequencyNs = 50_000_000,
|
||||||
|
){
|
||||||
|
$this->maxBudget = $this->averagePerTick * $maxBufferTicks;
|
||||||
|
$this->budget = $this->maxBudget;
|
||||||
|
$this->lastUpdateTimeNs = hrtime(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws PacketHandlingException if the rate limit has been exceeded
|
||||||
|
*/
|
||||||
|
public function decrement(int $amount = 1) : void{
|
||||||
|
if($this->budget <= 0){
|
||||||
|
$this->update();
|
||||||
|
if($this->budget <= 0){
|
||||||
|
throw new PacketHandlingException("Exceeded rate limit for \"$this->name\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->budget -= $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update() : void{
|
||||||
|
$nowNs = hrtime(true);
|
||||||
|
$timeSinceLastUpdateNs = $nowNs - $this->lastUpdateTimeNs;
|
||||||
|
if($timeSinceLastUpdateNs > $this->updateFrequencyNs){
|
||||||
|
$ticksSinceLastUpdate = intdiv($timeSinceLastUpdateNs, $this->updateFrequencyNs);
|
||||||
|
/*
|
||||||
|
* If the server takes an abnormally long time to process a tick, add the budget for time difference to
|
||||||
|
* compensate. This extra budget may be very large, but it will disappear the next time a normal update
|
||||||
|
* occurs. This ensures that backlogs during a large lag spike don't cause everyone to get kicked.
|
||||||
|
* As long as all the backlogged packets are processed before the next tick, everything should be OK for
|
||||||
|
* clients behaving normally.
|
||||||
|
*/
|
||||||
|
$this->budget = min($this->budget, $this->maxBudget) + ($this->averagePerTick * 2 * $ticksSinceLastUpdate);
|
||||||
|
$this->lastUpdateTimeNs = $nowNs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -211,7 +211,7 @@ class InGamePacketHandler extends PacketHandler{
|
|||||||
if($newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
|
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);
|
$this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos);
|
||||||
//Still getting movements from before teleport, ignore them
|
//Still getting movements from before teleport, ignore them
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
|
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
|
||||||
|
@ -44,6 +44,7 @@ use pocketmine\network\mcpe\protocol\types\PlayerMovementType;
|
|||||||
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
|
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
|
||||||
use pocketmine\player\Player;
|
use pocketmine\player\Player;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
|
use pocketmine\timings\Timings;
|
||||||
use pocketmine\VersionInfo;
|
use pocketmine\VersionInfo;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
@ -60,6 +61,8 @@ class PreSpawnPacketHandler extends PacketHandler{
|
|||||||
){}
|
){}
|
||||||
|
|
||||||
public function setUp() : void{
|
public function setUp() : void{
|
||||||
|
Timings::$playerNetworkSendPreSpawnGameData->startTiming();
|
||||||
|
try{
|
||||||
$location = $this->player->getLocation();
|
$location = $this->player->getLocation();
|
||||||
$world = $location->getWorld();
|
$world = $location->getWorld();
|
||||||
|
|
||||||
@ -143,6 +146,9 @@ class PreSpawnPacketHandler extends PacketHandler{
|
|||||||
|
|
||||||
$this->session->getLogger()->debug("Sending player list");
|
$this->session->getLogger()->debug("Sending player list");
|
||||||
$this->session->syncPlayerList($this->server->getOnlinePlayers());
|
$this->session->syncPlayerList($this->server->getOnlinePlayers());
|
||||||
|
}finally{
|
||||||
|
Timings::$playerNetworkSendPreSpawnGameData->stopTiming();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestChunkRadius(RequestChunkRadiusPacket $packet) : bool{
|
public function handleRequestChunkRadius(RequestChunkRadiusPacket $packet) : bool{
|
||||||
|
@ -1233,7 +1233,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
|
|
||||||
$revert = false;
|
$revert = false;
|
||||||
|
|
||||||
if($distanceSquared > 100){
|
if($distanceSquared > 225){ //15 blocks
|
||||||
//TODO: this is probably too big if we process every movement
|
//TODO: this is probably too big if we process every movement
|
||||||
/* !!! BEWARE YE WHO ENTER HERE !!!
|
/* !!! BEWARE YE WHO ENTER HERE !!!
|
||||||
*
|
*
|
||||||
@ -1245,7 +1245,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
|||||||
* If you must tamper with this code, be aware that this can cause very nasty results. Do not waste our time
|
* If you must tamper with this code, be aware that this can cause very nasty results. Do not waste our time
|
||||||
* asking for help if you suffer the consequences of messing with this.
|
* asking for help if you suffer the consequences of messing with this.
|
||||||
*/
|
*/
|
||||||
$this->logger->debug("Moved too fast, reverting movement");
|
$this->logger->debug("Moved too fast (" . sqrt($distanceSquared) . " blocks in 1 movement), reverting movement");
|
||||||
$this->logger->debug("Old position: " . $oldPos->asVector3() . ", new position: " . $newPos);
|
$this->logger->debug("Old position: " . $oldPos->asVector3() . ", new position: " . $newPos);
|
||||||
$revert = true;
|
$revert = true;
|
||||||
}elseif(!$this->getWorld()->isInLoadedTerrain($newPos)){
|
}elseif(!$this->getWorld()->isInLoadedTerrain($newPos)){
|
||||||
|
@ -34,7 +34,13 @@ use function get_class;
|
|||||||
use function str_starts_with;
|
use function str_starts_with;
|
||||||
|
|
||||||
abstract class Timings{
|
abstract class Timings{
|
||||||
|
/**
|
||||||
|
* @deprecated This was used by the old timings viewer to make a timer appear in the Breakdown section of a timings
|
||||||
|
* report. Provide a group to your timer's constructor instead.
|
||||||
|
* @see Timings::GROUP_BREAKDOWN
|
||||||
|
*/
|
||||||
public const INCLUDED_BY_OTHER_TIMINGS_PREFIX = "** ";
|
public const INCLUDED_BY_OTHER_TIMINGS_PREFIX = "** ";
|
||||||
|
public const GROUP_BREAKDOWN = "Minecraft - Breakdown";
|
||||||
|
|
||||||
private static bool $initialized = false;
|
private static bool $initialized = false;
|
||||||
|
|
||||||
@ -50,6 +56,7 @@ abstract class Timings{
|
|||||||
public static TimingsHandler $playerNetworkSendCompressSessionBuffer;
|
public static TimingsHandler $playerNetworkSendCompressSessionBuffer;
|
||||||
public static TimingsHandler $playerNetworkSendEncrypt;
|
public static TimingsHandler $playerNetworkSendEncrypt;
|
||||||
public static TimingsHandler $playerNetworkSendInventorySync;
|
public static TimingsHandler $playerNetworkSendInventorySync;
|
||||||
|
public static TimingsHandler $playerNetworkSendPreSpawnGameData;
|
||||||
public static TimingsHandler $playerNetworkReceive;
|
public static TimingsHandler $playerNetworkReceive;
|
||||||
public static TimingsHandler $playerNetworkReceiveDecompress;
|
public static TimingsHandler $playerNetworkReceiveDecompress;
|
||||||
public static TimingsHandler $playerNetworkReceiveDecrypt;
|
public static TimingsHandler $playerNetworkReceiveDecrypt;
|
||||||
@ -125,8 +132,8 @@ abstract class Timings{
|
|||||||
self::$initialized = true;
|
self::$initialized = true;
|
||||||
|
|
||||||
self::$fullTick = new TimingsHandler("Full Server Tick");
|
self::$fullTick = new TimingsHandler("Full Server Tick");
|
||||||
self::$serverTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Server Tick Update Cycle", self::$fullTick);
|
self::$serverTick = new TimingsHandler("Server Tick Update Cycle", self::$fullTick, group: self::GROUP_BREAKDOWN);
|
||||||
self::$serverInterrupts = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Server Mid-Tick Processing", self::$fullTick);
|
self::$serverInterrupts = new TimingsHandler("Server Mid-Tick Processing", self::$fullTick, group: self::GROUP_BREAKDOWN);
|
||||||
self::$memoryManager = new TimingsHandler("Memory Manager");
|
self::$memoryManager = new TimingsHandler("Memory Manager");
|
||||||
self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager);
|
self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager);
|
||||||
self::$titleTick = new TimingsHandler("Console Title Tick");
|
self::$titleTick = new TimingsHandler("Console Title Tick");
|
||||||
@ -134,21 +141,22 @@ abstract class Timings{
|
|||||||
self::$connection = new TimingsHandler("Connection Handler");
|
self::$connection = new TimingsHandler("Connection Handler");
|
||||||
|
|
||||||
self::$playerNetworkSend = new TimingsHandler("Player Network Send", self::$connection);
|
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::$playerNetworkSendCompress = new TimingsHandler("Player Network Send - Compression", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||||
self::$playerNetworkSendCompressBroadcast = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress);
|
self::$playerNetworkSendCompressBroadcast = new TimingsHandler("Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN);
|
||||||
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress);
|
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler("Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN);
|
||||||
self::$playerNetworkSendEncrypt = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Encryption", self::$playerNetworkSend);
|
self::$playerNetworkSendEncrypt = new TimingsHandler("Player Network Send - Encryption", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||||
self::$playerNetworkSendInventorySync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Inventory Sync", self::$playerNetworkSend);
|
self::$playerNetworkSendInventorySync = new TimingsHandler("Player Network Send - Inventory Sync", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||||
|
self::$playerNetworkSendPreSpawnGameData = new TimingsHandler("Player Network Send - Pre-Spawn Game Data", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive", self::$connection);
|
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::$playerNetworkReceiveDecompress = new TimingsHandler("Player Network Receive - Decompression", self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
|
||||||
self::$playerNetworkReceiveDecrypt = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Receive - Decryption", self::$playerNetworkReceive);
|
self::$playerNetworkReceiveDecrypt = new TimingsHandler("Player Network Receive - Decryption", self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$broadcastPackets = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Broadcast Packets", self::$playerNetworkSend);
|
self::$broadcastPackets = new TimingsHandler("Broadcast Packets", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$playerMove = new TimingsHandler("Player Movement");
|
self::$playerMove = new TimingsHandler("Player Movement");
|
||||||
self::$playerChunkOrder = new TimingsHandler("Player Order Chunks");
|
self::$playerChunkOrder = new TimingsHandler("Player Order Chunks");
|
||||||
self::$playerChunkSend = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Chunks", self::$playerNetworkSend);
|
self::$playerChunkSend = new TimingsHandler("Player Network Send - Chunks", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||||
self::$scheduler = new TimingsHandler("Scheduler");
|
self::$scheduler = new TimingsHandler("Scheduler");
|
||||||
self::$serverCommand = new TimingsHandler("Server Command");
|
self::$serverCommand = new TimingsHandler("Server Command");
|
||||||
self::$worldLoad = new TimingsHandler("World Load");
|
self::$worldLoad = new TimingsHandler("World Load");
|
||||||
@ -156,37 +164,37 @@ abstract class Timings{
|
|||||||
self::$population = new TimingsHandler("World Population");
|
self::$population = new TimingsHandler("World Population");
|
||||||
self::$generationCallback = new TimingsHandler("World Generation Callback");
|
self::$generationCallback = new TimingsHandler("World Generation Callback");
|
||||||
self::$permissibleCalculation = new TimingsHandler("Permissible Calculation");
|
self::$permissibleCalculation = new TimingsHandler("Permissible Calculation");
|
||||||
self::$permissibleCalculationDiff = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Permissible Calculation - Diff", self::$permissibleCalculation);
|
self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
||||||
self::$permissibleCalculationCallback = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Permissible Calculation - Callbacks", self::$permissibleCalculation);
|
self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load");
|
self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load");
|
||||||
self::$syncPlayerDataSave = new TimingsHandler("Player Data Save");
|
self::$syncPlayerDataSave = new TimingsHandler("Player Data Save");
|
||||||
|
|
||||||
self::$entityMove = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Movement");
|
self::$entityMove = new TimingsHandler("Entity Movement", group: self::GROUP_BREAKDOWN);
|
||||||
self::$entityMoveCollision = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Movement - Collision Checks", self::$entityMove);
|
self::$entityMoveCollision = new TimingsHandler("Entity Movement - Collision Checks", self::$entityMove, group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$projectileMove = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Projectile Movement", self::$entityMove);
|
self::$projectileMove = new TimingsHandler("Projectile Movement", self::$entityMove, group: self::GROUP_BREAKDOWN);
|
||||||
self::$projectileMoveRayTrace = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Projectile Movement - Ray Tracing", self::$projectileMove);
|
self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove, group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$playerCheckNearEntities = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "checkNearEntities");
|
self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities", group: self::GROUP_BREAKDOWN);
|
||||||
self::$tickEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Tick");
|
self::$tickEntity = new TimingsHandler("Entity Tick", group: self::GROUP_BREAKDOWN);
|
||||||
self::$tickTileEntity = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Block Entity Tick");
|
self::$tickTileEntity = new TimingsHandler("Block Entity Tick", group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$entityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick");
|
self::$entityBaseTick = new TimingsHandler("Entity Base Tick", group: self::GROUP_BREAKDOWN);
|
||||||
self::$livingEntityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick - Living");
|
self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living", group: self::GROUP_BREAKDOWN);
|
||||||
self::$itemEntityBaseTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Base Tick - ItemEntity");
|
self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity", group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$schedulerSync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Sync Tasks");
|
self::$schedulerSync = new TimingsHandler("Scheduler - Sync Tasks", group: self::GROUP_BREAKDOWN);
|
||||||
self::$schedulerAsync = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Scheduler - Async Tasks");
|
self::$schedulerAsync = new TimingsHandler("Scheduler - Async Tasks", group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
self::$playerCommand = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Command");
|
self::$playerCommand = new TimingsHandler("Player Command", group: self::GROUP_BREAKDOWN);
|
||||||
self::$craftingDataCacheRebuild = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Build CraftingDataPacket Cache");
|
self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache", group: self::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getScheduledTaskTimings(TaskHandler $task, int $period) : TimingsHandler{
|
public static function getScheduledTaskTimings(TaskHandler $task, int $period) : TimingsHandler{
|
||||||
self::init();
|
self::init();
|
||||||
$name = "Task: " . $task->getOwnerName() . " Runnable: " . $task->getTaskName();
|
$name = "Task: " . $task->getTaskName();
|
||||||
|
|
||||||
if($period > 0){
|
if($period > 0){
|
||||||
$name .= "(interval:" . $period . ")";
|
$name .= "(interval:" . $period . ")";
|
||||||
@ -195,7 +203,7 @@ abstract class Timings{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!isset(self::$pluginTaskTimingMap[$name])){
|
if(!isset(self::$pluginTaskTimingMap[$name])){
|
||||||
self::$pluginTaskTimingMap[$name] = new TimingsHandler($name, self::$schedulerSync);
|
self::$pluginTaskTimingMap[$name] = new TimingsHandler($name, self::$schedulerSync, $task->getOwnerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$pluginTaskTimingMap[$name];
|
return self::$pluginTaskTimingMap[$name];
|
||||||
@ -211,7 +219,7 @@ abstract class Timings{
|
|||||||
if($entity instanceof Player && $reflect->getName() !== Player::class){
|
if($entity instanceof Player && $reflect->getName() !== Player::class){
|
||||||
$entityType = "Player (" . $reflect->getName() . ")";
|
$entityType = "Player (" . $reflect->getName() . ")";
|
||||||
}
|
}
|
||||||
self::$entityTypeTimingMap[$entityType] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Entity Tick - " . $entityType, self::$tickEntity);
|
self::$entityTypeTimingMap[$entityType] = new TimingsHandler("Entity Tick - " . $entityType, self::$tickEntity, group: self::GROUP_BREAKDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$entityTypeTimingMap[$entityType];
|
return self::$entityTypeTimingMap[$entityType];
|
||||||
@ -221,7 +229,7 @@ abstract class Timings{
|
|||||||
self::init();
|
self::init();
|
||||||
$tileType = (new \ReflectionClass($tile))->getShortName();
|
$tileType = (new \ReflectionClass($tile))->getShortName();
|
||||||
if(!isset(self::$tileEntityTypeTimingMap[$tileType])){
|
if(!isset(self::$tileEntityTypeTimingMap[$tileType])){
|
||||||
self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Block Entity Tick - " . $tileType, self::$tickTileEntity);
|
self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler("Block Entity Tick - " . $tileType, self::$tickTileEntity, group: self::GROUP_BREAKDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$tileEntityTypeTimingMap[$tileType];
|
return self::$tileEntityTypeTimingMap[$tileType];
|
||||||
@ -231,7 +239,7 @@ abstract class Timings{
|
|||||||
self::init();
|
self::init();
|
||||||
$pid = $pk->pid();
|
$pid = $pk->pid();
|
||||||
if(!isset(self::$packetReceiveTimingMap[$pid])){
|
if(!isset(self::$packetReceiveTimingMap[$pid])){
|
||||||
self::$packetReceiveTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Receive - " . $pk->getName(), self::$playerNetworkReceive);
|
self::$packetReceiveTimingMap[$pid] = new TimingsHandler("Receive - " . $pk->getName(), self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$packetReceiveTimingMap[$pid];
|
return self::$packetReceiveTimingMap[$pid];
|
||||||
@ -240,24 +248,27 @@ abstract class Timings{
|
|||||||
public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||||
$pid = $pk->pid();
|
$pid = $pk->pid();
|
||||||
return self::$packetDecodeTimingMap[$pid] ??= new TimingsHandler(
|
return self::$packetDecodeTimingMap[$pid] ??= new TimingsHandler(
|
||||||
self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Decode - " . $pk->getName(),
|
"Decode - " . $pk->getName(),
|
||||||
self::getReceiveDataPacketTimings($pk)
|
self::getReceiveDataPacketTimings($pk),
|
||||||
|
group: self::GROUP_BREAKDOWN
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||||
$pid = $pk->pid();
|
$pid = $pk->pid();
|
||||||
return self::$packetHandleTimingMap[$pid] ??= new TimingsHandler(
|
return self::$packetHandleTimingMap[$pid] ??= new TimingsHandler(
|
||||||
self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Handler - " . $pk->getName(),
|
"Handler - " . $pk->getName(),
|
||||||
self::getReceiveDataPacketTimings($pk)
|
self::getReceiveDataPacketTimings($pk),
|
||||||
|
group: self::GROUP_BREAKDOWN
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
||||||
$pid = $pk->pid();
|
$pid = $pk->pid();
|
||||||
return self::$packetEncodeTimingMap[$pid] ??= new TimingsHandler(
|
return self::$packetEncodeTimingMap[$pid] ??= new TimingsHandler(
|
||||||
self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Encode - " . $pk->getName(),
|
"Encode - " . $pk->getName(),
|
||||||
self::getSendDataPacketTimings($pk)
|
self::getSendDataPacketTimings($pk),
|
||||||
|
group: self::GROUP_BREAKDOWN
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +276,7 @@ abstract class Timings{
|
|||||||
self::init();
|
self::init();
|
||||||
$pid = $pk->pid();
|
$pid = $pk->pid();
|
||||||
if(!isset(self::$packetSendTimingMap[$pid])){
|
if(!isset(self::$packetSendTimingMap[$pid])){
|
||||||
self::$packetSendTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Send - " . $pk->getName(), self::$playerNetworkSend);
|
self::$packetSendTimingMap[$pid] = new TimingsHandler("Send - " . $pk->getName(), self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$packetSendTimingMap[$pid];
|
return self::$packetSendTimingMap[$pid];
|
||||||
@ -274,7 +285,7 @@ abstract class Timings{
|
|||||||
public static function getCommandDispatchTimings(string $commandName) : TimingsHandler{
|
public static function getCommandDispatchTimings(string $commandName) : TimingsHandler{
|
||||||
self::init();
|
self::init();
|
||||||
|
|
||||||
return self::$commandTimingMap[$commandName] ??= new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Command - " . $commandName);
|
return self::$commandTimingMap[$commandName] ??= new TimingsHandler("Command - " . $commandName, group: self::GROUP_BREAKDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getEventTimings(Event $event) : TimingsHandler{
|
public static function getEventTimings(Event $event) : TimingsHandler{
|
||||||
|
@ -32,6 +32,8 @@ use function implode;
|
|||||||
use function spl_object_id;
|
use function spl_object_id;
|
||||||
|
|
||||||
class TimingsHandler{
|
class TimingsHandler{
|
||||||
|
private const FORMAT_VERSION = 1;
|
||||||
|
|
||||||
private static bool $enabled = false;
|
private static bool $enabled = false;
|
||||||
private static int $timingStart = 0;
|
private static int $timingStart = 0;
|
||||||
|
|
||||||
@ -58,7 +60,9 @@ class TimingsHandler{
|
|||||||
"Violations: " . $timings->getViolations(),
|
"Violations: " . $timings->getViolations(),
|
||||||
"RecordId: " . $timings->getId(),
|
"RecordId: " . $timings->getId(),
|
||||||
"ParentRecordId: " . ($timings->getParentId() ?? "none"),
|
"ParentRecordId: " . ($timings->getParentId() ?? "none"),
|
||||||
"TimerId: " . $timings->getTimerId()
|
"TimerId: " . $timings->getTimerId(),
|
||||||
|
"Ticks: " . $timings->getTicksActive(),
|
||||||
|
"Peak: " . $timings->getPeakTime(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$result = [];
|
$result = [];
|
||||||
@ -86,6 +90,7 @@ class TimingsHandler{
|
|||||||
|
|
||||||
$result[] = "# Entities " . $entities;
|
$result[] = "# Entities " . $entities;
|
||||||
$result[] = "# LivingEntities " . $livingEntities;
|
$result[] = "# LivingEntities " . $livingEntities;
|
||||||
|
$result[] = "# FormatVersion " . self::FORMAT_VERSION;
|
||||||
|
|
||||||
$sampleTime = hrtime(true) - self::$timingStart;
|
$sampleTime = hrtime(true) - self::$timingStart;
|
||||||
$result[] = "Sample time $sampleTime (" . ($sampleTime / 1000000000) . "s)";
|
$result[] = "Sample time $sampleTime (" . ($sampleTime / 1000000000) . "s)";
|
||||||
|
@ -59,11 +59,17 @@ final class TimingsRecord{
|
|||||||
public static function tick(bool $measure = true) : void{
|
public static function tick(bool $measure = true) : void{
|
||||||
if($measure){
|
if($measure){
|
||||||
foreach(self::$records as $record){
|
foreach(self::$records as $record){
|
||||||
|
if($record->curCount > 0){
|
||||||
if($record->curTickTotal > Server::TARGET_NANOSECONDS_PER_TICK){
|
if($record->curTickTotal > Server::TARGET_NANOSECONDS_PER_TICK){
|
||||||
$record->violations += (int) floor($record->curTickTotal / Server::TARGET_NANOSECONDS_PER_TICK);
|
$record->violations += (int) floor($record->curTickTotal / Server::TARGET_NANOSECONDS_PER_TICK);
|
||||||
}
|
}
|
||||||
|
if($record->curTickTotal > $record->peakTime){
|
||||||
|
$record->peakTime = $record->curTickTotal;
|
||||||
|
}
|
||||||
$record->curTickTotal = 0;
|
$record->curTickTotal = 0;
|
||||||
$record->curCount = 0;
|
$record->curCount = 0;
|
||||||
|
$record->ticksActive++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
foreach(self::$records as $record){
|
foreach(self::$records as $record){
|
||||||
@ -82,6 +88,8 @@ final class TimingsRecord{
|
|||||||
private int $totalTime = 0;
|
private int $totalTime = 0;
|
||||||
private int $curTickTotal = 0;
|
private int $curTickTotal = 0;
|
||||||
private int $violations = 0;
|
private int $violations = 0;
|
||||||
|
private int $ticksActive = 0;
|
||||||
|
private int $peakTime = 0;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
//I'm not the biggest fan of this cycle, but it seems to be the most effective way to avoid leaking anything.
|
//I'm not the biggest fan of this cycle, but it seems to be the most effective way to avoid leaking anything.
|
||||||
@ -113,6 +121,10 @@ final class TimingsRecord{
|
|||||||
|
|
||||||
public function getViolations() : int{ return $this->violations; }
|
public function getViolations() : int{ return $this->violations; }
|
||||||
|
|
||||||
|
public function getTicksActive() : int{ return $this->ticksActive; }
|
||||||
|
|
||||||
|
public function getPeakTime() : float{ return $this->peakTime; }
|
||||||
|
|
||||||
public function startTiming(int $now) : void{
|
public function startTiming(int $now) : void{
|
||||||
$this->start = $now;
|
$this->start = $now;
|
||||||
self::$currentRecord = $this;
|
self::$currentRecord = $this;
|
||||||
|
@ -53,27 +53,27 @@ class WorldTimings{
|
|||||||
public function __construct(World $world){
|
public function __construct(World $world){
|
||||||
$name = $world->getFolderName() . " - ";
|
$name = $world->getFolderName() . " - ";
|
||||||
|
|
||||||
$this->setBlock = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "setBlock");
|
$this->setBlock = new TimingsHandler($name . "setBlock", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->doBlockLightUpdates = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Block Light Updates");
|
$this->doBlockLightUpdates = new TimingsHandler($name . "Block Light Updates", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->doBlockSkyLightUpdates = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Sky Light Updates");
|
$this->doBlockSkyLightUpdates = new TimingsHandler($name . "Sky Light Updates", group: Timings::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
$this->doChunkUnload = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Unload Chunks");
|
$this->doChunkUnload = new TimingsHandler($name . "Unload Chunks", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->scheduledBlockUpdates = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Scheduled Block Updates");
|
$this->scheduledBlockUpdates = new TimingsHandler($name . "Scheduled Block Updates", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->randomChunkUpdates = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Random Chunk Updates");
|
$this->randomChunkUpdates = new TimingsHandler($name . "Random Chunk Updates", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->randomChunkUpdatesChunkSelection = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Random Chunk Updates - Chunk Selection");
|
$this->randomChunkUpdatesChunkSelection = new TimingsHandler($name . "Random Chunk Updates - Chunk Selection", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->doChunkGC = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Garbage Collection");
|
$this->doChunkGC = new TimingsHandler($name . "Garbage Collection", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->entityTick = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Tick Entities");
|
$this->entityTick = new TimingsHandler($name . "Tick Entities", group: Timings::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
Timings::init(); //make sure the timers we want are available
|
Timings::init(); //make sure the timers we want are available
|
||||||
$this->syncChunkSend = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Player Send Chunks", Timings::$playerChunkSend);
|
$this->syncChunkSend = new TimingsHandler($name . "Player Send Chunks", Timings::$playerChunkSend, group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->syncChunkSendPrepare = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Player Send Chunk Prepare", Timings::$playerChunkSend);
|
$this->syncChunkSendPrepare = new TimingsHandler($name . "Player Send Chunk Prepare", Timings::$playerChunkSend, group: Timings::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
$this->syncChunkLoad = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load", Timings::$worldLoad);
|
$this->syncChunkLoad = new TimingsHandler($name . "Chunk Load", Timings::$worldLoad, group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->syncChunkLoadData = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Data");
|
$this->syncChunkLoadData = new TimingsHandler($name . "Chunk Load - Data", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->syncChunkLoadFixInvalidBlocks = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Fix Invalid Blocks");
|
$this->syncChunkLoadFixInvalidBlocks = new TimingsHandler($name . "Chunk Load - Fix Invalid Blocks", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->syncChunkLoadEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Entities");
|
$this->syncChunkLoadEntities = new TimingsHandler($name . "Chunk Load - Entities", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->syncChunkLoadTileEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - TileEntities");
|
$this->syncChunkLoadTileEntities = new TimingsHandler($name . "Chunk Load - TileEntities", group: Timings::GROUP_BREAKDOWN);
|
||||||
$this->syncChunkSave = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Save", Timings::$worldSave);
|
$this->syncChunkSave = new TimingsHandler($name . "Chunk Save", Timings::$worldSave, group: Timings::GROUP_BREAKDOWN);
|
||||||
|
|
||||||
$this->doTick = new TimingsHandler($name . "World Tick");
|
$this->doTick = new TimingsHandler($name . "World Tick");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user