mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-03 18:42:37 +00:00
Merge branch 'minor-next' into stable
This commit is contained in:
commit
69b668355f
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
php-version: 8.1
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
php-version: 8.1
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
|
12
.github/workflows/main.yml
vendored
12
.github/workflows/main.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.28, 8.1.18, 8.2.5]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- name: Build and prepare PHP cache
|
||||
@ -32,7 +32,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.28, 8.1.18, 8.2.5]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -71,7 +71,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.28, 8.1.18, 8.2.5]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -110,7 +110,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.28, 8.1.18, 8.2.5]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -151,7 +151,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.28, 8.1.18, 8.2.5]
|
||||
php: [8.1.19, 8.2.6]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -205,7 +205,7 @@ jobs:
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
php-version: 8.1
|
||||
tools: php-cs-fixer:3.16
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
1
.github/workflows/update-php-versions.php
vendored
1
.github/workflows/update-php-versions.php
vendored
@ -22,7 +22,6 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
const VERSIONS = [
|
||||
"8.0",
|
||||
"8.1",
|
||||
"8.2"
|
||||
];
|
||||
|
10
BUILDING.md
10
BUILDING.md
@ -2,13 +2,13 @@
|
||||
## Pre-requisites
|
||||
- A bash shell (git bash is sufficient for Windows)
|
||||
- [`git`](https://git-scm.com) available in your shell
|
||||
- PHP 8.0 or newer available in your shell
|
||||
- PHP 8.1 or newer available in your shell
|
||||
- [`composer`](https://getcomposer.org) available in your shell
|
||||
|
||||
## Custom PHP binaries
|
||||
Because PocketMine-MP requires several non-standard PHP extensions and configuration, PMMP provides scripts to build custom binaries for running PocketMine-MP, as well as prebuilt binaries.
|
||||
|
||||
- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-8.0-Aggregate)
|
||||
- [Prebuilt binaries](https://github.com/pmmp/PHP-Binaries/releases)
|
||||
- [Compile scripts](https://github.com/pmmp/php-build-scripts) are provided as a submodule in the path `build/php`
|
||||
|
||||
If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`.
|
||||
@ -29,11 +29,5 @@ Run `composer make-server` using your preferred PHP binary. It'll drop a `Pocket
|
||||
|
||||
You can also use the `--out` option to change the output filename.
|
||||
|
||||
There is a bug in PHP that might cause an error which looks like this:
|
||||
```
|
||||
Fatal error: Uncaught BadMethodCallException: unable to create temporary file in PocketMine-MP/build/server-phar.php:119
|
||||
```
|
||||
You can work around it by setting `ulimit -n` to some bigger number, e.g. `8192`, or by updating your PHP version to at least 8.0.3.
|
||||
|
||||
## Running PocketMine-MP from source code
|
||||
Run `src/PocketMine.php` using your preferred PHP binary.
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9d8807be825b3fafd420534f2c29351c1bda6398
|
||||
Subproject commit f860ade30acc074a98bbf5ff286f35b5eda10c86
|
@ -5,7 +5,7 @@
|
||||
"homepage": "https://pmmp.io",
|
||||
"license": "LGPL-3.0",
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"php": "^8.1",
|
||||
"php-64bit": "*",
|
||||
"ext-chunkutils2": "^0.3.1",
|
||||
"ext-crypto": "^0.3.1",
|
||||
@ -77,7 +77,7 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.0.0"
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
|
126
composer.lock
generated
126
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "a5ffe862f4e6376eaf78593a4bb8aeb6",
|
||||
"content-hash": "ecb1e46a4410fdc7efb7e3dac60b5322",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -903,21 +903,20 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
"version": "1.3.0",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/collection.git",
|
||||
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4"
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4",
|
||||
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"symfony/polyfill-php81": "^1.23"
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
@ -977,7 +976,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/collection/issues",
|
||||
"source": "https://github.com/ramsey/collection/tree/1.3.0"
|
||||
"source": "https://github.com/ramsey/collection/tree/2.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -989,7 +988,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-27T19:12:24+00:00"
|
||||
"time": "2022-12-31T21:50:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
@ -1395,85 +1394,6 @@
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php81.git",
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php81\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.11.0",
|
||||
@ -1587,30 +1507,30 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.5.0",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
|
||||
"reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
|
||||
"reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9 || ^11",
|
||||
"doctrine/coding-standard": "^11",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpbench/phpbench": "^0.16 || ^1",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-phpunit": "^1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.30 || ^5.4"
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/phpstan": "^1.9.4",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpunit/phpunit": "^9.5.27",
|
||||
"vimeo/psalm": "^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -1637,7 +1557,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
|
||||
"source": "https://github.com/doctrine/instantiator/tree/2.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1653,7 +1573,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-30T00:15:36+00:00"
|
||||
"time": "2022-12-30T00:23:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
@ -3486,7 +3406,7 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.0",
|
||||
"php": "^8.1",
|
||||
"php-64bit": "*",
|
||||
"ext-chunkutils2": "^0.3.1",
|
||||
"ext-crypto": "^0.3.1",
|
||||
@ -3515,7 +3435,7 @@
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "8.0.0"
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
||||
|
@ -85,8 +85,11 @@ network:
|
||||
batch-threshold: 256
|
||||
#Compression level used when sending batched packets. Higher = more CPU, less bandwidth usage
|
||||
compression-level: 6
|
||||
#Use AsyncTasks for compression. Adds half/one tick delay, less CPU load on main thread
|
||||
#Use AsyncTasks for compression during the main game session. Increases latency, but may reduce main thread load
|
||||
async-compression: false
|
||||
#Threshold for async compression, in bytes. Only packets larger than this will be compressed asynchronously
|
||||
#Due to large overhead of AsyncTask, async compression isn't worth it except for large packets
|
||||
async-compression-threshold: 10000
|
||||
#Experimental. Use UPnP to automatically port forward
|
||||
upnp-forwarding: false
|
||||
#Maximum size in bytes of packets sent over the network (default 1492 bytes). Packets larger than this will be
|
||||
|
@ -50,7 +50,7 @@ namespace pocketmine {
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
const MIN_PHP_VERSION = "8.0.0";
|
||||
const MIN_PHP_VERSION = "8.1.0";
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
@ -265,9 +265,6 @@ JIT_WARNING
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if(extension_loaded('parallel')){
|
||||
\parallel\bootstrap(\pocketmine\COMPOSER_AUTOLOADER_PATH);
|
||||
}
|
||||
|
||||
ErrorToExceptionHandler::set();
|
||||
|
||||
|
@ -208,6 +208,8 @@ class Server{
|
||||
private const TICKS_PER_TPS_OVERLOAD_WARNING = 5 * self::TARGET_TICKS_PER_SECOND;
|
||||
private const TICKS_PER_STATS_REPORT = 300 * self::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private const DEFAULT_ASYNC_COMPRESSION_THRESHOLD = 10_000;
|
||||
|
||||
private static ?Server $instance = null;
|
||||
|
||||
private TimeTrackingSleeperHandler $tickSleeper;
|
||||
@ -266,6 +268,7 @@ class Server{
|
||||
|
||||
private Network $network;
|
||||
private bool $networkCompressionAsync = true;
|
||||
private int $networkCompressionAsyncThreshold = self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD;
|
||||
|
||||
private Language $language;
|
||||
private bool $forceLanguage = false;
|
||||
@ -908,6 +911,10 @@ class Server{
|
||||
ZlibCompressor::setInstance(new ZlibCompressor($netCompressionLevel, $netCompressionThreshold, ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE));
|
||||
|
||||
$this->networkCompressionAsync = $this->configGroup->getPropertyBool("network.async-compression", true);
|
||||
$this->networkCompressionAsyncThreshold = max(
|
||||
$this->configGroup->getPropertyInt("network.async-compression-threshold", self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD),
|
||||
$netCompressionThreshold ?? self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD
|
||||
);
|
||||
|
||||
EncryptionContext::$ENABLED = $this->configGroup->getPropertyBool("network.enable-encryption", true);
|
||||
|
||||
@ -1375,7 +1382,7 @@ class Server{
|
||||
}
|
||||
|
||||
$promise = new CompressBatchPromise();
|
||||
if(!$sync){
|
||||
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||
$this->asyncPool->submitTask($task);
|
||||
}else{
|
||||
|
@ -85,6 +85,20 @@ class DoubleChestInventory extends BaseInventory implements BlockInventory, Inve
|
||||
$this->right->setContents($rightContents);
|
||||
}
|
||||
|
||||
protected function getMatchingItemCount(int $slot, Item $test, bool $checkDamage, bool $checkTags) : int{
|
||||
$leftSize = $this->left->getSize();
|
||||
return $slot < $leftSize ?
|
||||
$this->left->getMatchingItemCount($slot, $test, $checkDamage, $checkTags) :
|
||||
$this->right->getMatchingItemCount($slot - $leftSize, $test, $checkDamage, $checkTags);
|
||||
}
|
||||
|
||||
public function isSlotEmpty(int $index) : bool{
|
||||
$leftSize = $this->left->getSize();
|
||||
return $index < $leftSize ?
|
||||
$this->left->isSlotEmpty($index) :
|
||||
$this->right->isSlotEmpty($index - $leftSize);
|
||||
}
|
||||
|
||||
protected function getOpenSound() : Sound{ return new ChestOpenSound(); }
|
||||
|
||||
protected function getCloseSound() : Sound{ return new ChestCloseSound(); }
|
||||
|
@ -110,7 +110,8 @@ class StatusCommand extends VanillaCommand{
|
||||
$worldName = $world->getFolderName() !== $world->getDisplayName() ? " (" . $world->getDisplayName() . ")" : "";
|
||||
$timeColor = $world->getTickRateTime() > 40 ? TextFormat::RED : TextFormat::YELLOW;
|
||||
$sender->sendMessage(TextFormat::GOLD . "World \"{$world->getFolderName()}\"$worldName: " .
|
||||
TextFormat::RED . number_format(count($world->getLoadedChunks())) . TextFormat::GREEN . " chunks, " .
|
||||
TextFormat::RED . number_format(count($world->getLoadedChunks())) . TextFormat::GREEN . " loaded chunks, " .
|
||||
TextFormat::RED . number_format(count($world->getTickingChunks())) . TextFormat::GREEN . " ticking chunks, " .
|
||||
TextFormat::RED . number_format(count($world->getEntities())) . TextFormat::GREEN . " entities. " .
|
||||
"Time $timeColor" . round($world->getTickRateTime(), 2) . "ms"
|
||||
);
|
||||
|
@ -92,7 +92,6 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
private const TAG_XP_PROGRESS = "XpP"; //TAG_Float
|
||||
private const TAG_LIFETIME_XP_TOTAL = "XpTotal"; //TAG_Int
|
||||
private const TAG_XP_SEED = "XpSeed"; //TAG_Int
|
||||
private const TAG_NAME_TAG = "NameTag"; //TAG_String
|
||||
private const TAG_SKIN = "Skin"; //TAG_Compound
|
||||
private const TAG_SKIN_NAME = "Name"; //TAG_String
|
||||
private const TAG_SKIN_DATA = "Data"; //TAG_ByteArray
|
||||
@ -245,10 +244,6 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
* For Human entities which are not players, sets their properties such as nametag, skin and UUID from NBT.
|
||||
*/
|
||||
protected function initHumanData(CompoundTag $nbt) : void{
|
||||
if(($nameTagTag = $nbt->getTag(self::TAG_NAME_TAG)) instanceof StringTag){
|
||||
$this->setNameTag($nameTagTag->getValue());
|
||||
}
|
||||
|
||||
//TODO: use of NIL UUID for namespace is a hack; we should provide a proper UUID for the namespace
|
||||
$this->uuid = Uuid::uuid3(Uuid::NIL, ((string) $this->getId()) . $this->skin->getSkinData() . $this->getNameTag());
|
||||
}
|
||||
|
@ -108,13 +108,23 @@ abstract class BaseInventory implements Inventory{
|
||||
$this->onContentChange($oldContents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for utility functions which search the inventory.
|
||||
* TODO: make this abstract instead of providing a slow default implementation (BC break)
|
||||
*/
|
||||
protected function getMatchingItemCount(int $slot, Item $test, bool $checkDamage, bool $checkTags) : int{
|
||||
$item = $this->getItem($slot);
|
||||
return $item->equals($test, $checkDamage, $checkTags) ? $item->getCount() : 0;
|
||||
}
|
||||
|
||||
public function contains(Item $item) : bool{
|
||||
$count = max(1, $item->getCount());
|
||||
$checkDamage = !$item->hasAnyDamageValue();
|
||||
$checkTags = $item->hasNamedTag();
|
||||
foreach($this->getContents() as $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags)){
|
||||
$count -= $i->getCount();
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; $i++){
|
||||
$slotCount = $this->getMatchingItemCount($i, $item, $checkDamage, $checkTags);
|
||||
if($slotCount > 0){
|
||||
$count -= $slotCount;
|
||||
if($count <= 0){
|
||||
return true;
|
||||
}
|
||||
@ -128,9 +138,9 @@ abstract class BaseInventory implements Inventory{
|
||||
$slots = [];
|
||||
$checkDamage = !$item->hasAnyDamageValue();
|
||||
$checkTags = $item->hasNamedTag();
|
||||
foreach($this->getContents() as $index => $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags)){
|
||||
$slots[$index] = $i;
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; $i++){
|
||||
if($this->getMatchingItemCount($i, $item, $checkDamage, $checkTags) > 0){
|
||||
$slots[$i] = $this->getItem($i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,18 +152,9 @@ abstract class BaseInventory implements Inventory{
|
||||
$checkDamage = $exact || !$item->hasAnyDamageValue();
|
||||
$checkTags = $exact || $item->hasNamedTag();
|
||||
|
||||
foreach($this->getContents() as $index => $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags) && ($i->getCount() === $count || (!$exact && $i->getCount() > $count))){
|
||||
return $index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function firstEmpty() : int{
|
||||
foreach($this->getContents(true) as $i => $slot){
|
||||
if($slot->isNull()){
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; $i++){
|
||||
$slotCount = $this->getMatchingItemCount($i, $item, $checkDamage, $checkTags);
|
||||
if($slotCount > 0 && ($slotCount === $count || (!$exact && $slotCount > $count))){
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
@ -161,6 +162,20 @@ abstract class BaseInventory implements Inventory{
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function firstEmpty() : int{
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; $i++){
|
||||
if($this->isSlotEmpty($i)){
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: make this abstract and force implementations to implement it properly (BC break)
|
||||
* This default implementation works, but is slow.
|
||||
*/
|
||||
public function isSlotEmpty(int $index) : bool{
|
||||
return $this->getItem($index)->isNull();
|
||||
}
|
||||
@ -171,14 +186,16 @@ abstract class BaseInventory implements Inventory{
|
||||
|
||||
public function getAddableItemQuantity(Item $item) : int{
|
||||
$count = $item->getCount();
|
||||
$maxStackSize = min($this->getMaxStackSize(), $item->getMaxStackSize());
|
||||
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
$slot = $this->getItem($i);
|
||||
if($item->canStackWith($slot)){
|
||||
if(($diff = min($slot->getMaxStackSize(), $item->getMaxStackSize()) - $slot->getCount()) > 0){
|
||||
if($this->isSlotEmpty($i)){
|
||||
$count -= $maxStackSize;
|
||||
}else{
|
||||
$slotCount = $this->getMatchingItemCount($i, $item, true, true);
|
||||
if($slotCount > 0 && ($diff = $maxStackSize - $slotCount) > 0){
|
||||
$count -= $diff;
|
||||
}
|
||||
}elseif($slot->isNull()){
|
||||
$count -= min($this->getMaxStackSize(), $item->getMaxStackSize());
|
||||
}
|
||||
|
||||
if($count <= 0){
|
||||
@ -212,23 +229,29 @@ abstract class BaseInventory implements Inventory{
|
||||
return $returnSlots;
|
||||
}
|
||||
|
||||
private function internalAddItem(Item $slot) : Item{
|
||||
private function internalAddItem(Item $newItem) : Item{
|
||||
$emptySlots = [];
|
||||
|
||||
$maxStackSize = min($this->getMaxStackSize(), $newItem->getMaxStackSize());
|
||||
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
$item = $this->getItem($i);
|
||||
if($item->isNull()){
|
||||
if($this->isSlotEmpty($i)){
|
||||
$emptySlots[] = $i;
|
||||
continue;
|
||||
}
|
||||
$slotCount = $this->getMatchingItemCount($i, $newItem, true, true);
|
||||
if($slotCount === 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
if($slot->canStackWith($item) && $item->getCount() < $item->getMaxStackSize()){
|
||||
$amount = min($item->getMaxStackSize() - $item->getCount(), $slot->getCount(), $this->getMaxStackSize());
|
||||
if($slotCount < $maxStackSize){
|
||||
$amount = min($maxStackSize - $slotCount, $newItem->getCount());
|
||||
if($amount > 0){
|
||||
$slot->setCount($slot->getCount() - $amount);
|
||||
$item->setCount($item->getCount() + $amount);
|
||||
$this->setItem($i, $item);
|
||||
if($slot->getCount() <= 0){
|
||||
$newItem->setCount($newItem->getCount() - $amount);
|
||||
$slotItem = $this->getItem($i);
|
||||
$slotItem->setCount($slotItem->getCount() + $amount);
|
||||
$this->setItem($i, $slotItem);
|
||||
if($newItem->getCount() <= 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -237,65 +260,67 @@ abstract class BaseInventory implements Inventory{
|
||||
|
||||
if(count($emptySlots) > 0){
|
||||
foreach($emptySlots as $slotIndex){
|
||||
$amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize());
|
||||
$slot->setCount($slot->getCount() - $amount);
|
||||
$item = clone $slot;
|
||||
$item->setCount($amount);
|
||||
$this->setItem($slotIndex, $item);
|
||||
if($slot->getCount() <= 0){
|
||||
$amount = min($maxStackSize, $newItem->getCount());
|
||||
$newItem->setCount($newItem->getCount() - $amount);
|
||||
$slotItem = clone $newItem;
|
||||
$slotItem->setCount($amount);
|
||||
$this->setItem($slotIndex, $slotItem);
|
||||
if($newItem->getCount() <= 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $slot;
|
||||
return $newItem;
|
||||
}
|
||||
|
||||
public function remove(Item $item) : void{
|
||||
$checkDamage = !$item->hasAnyDamageValue();
|
||||
$checkTags = $item->hasNamedTag();
|
||||
|
||||
foreach($this->getContents() as $index => $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags)){
|
||||
$this->clear($index);
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; $i++){
|
||||
if($this->getMatchingItemCount($i, $item, $checkDamage, $checkTags) > 0){
|
||||
$this->clear($i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeItem(Item ...$slots) : array{
|
||||
/** @var Item[] $itemSlots */
|
||||
/** @var Item[] $searchItems */
|
||||
/** @var Item[] $slots */
|
||||
$itemSlots = [];
|
||||
$searchItems = [];
|
||||
foreach($slots as $slot){
|
||||
if(!$slot->isNull()){
|
||||
$itemSlots[] = clone $slot;
|
||||
$searchItems[] = clone $slot;
|
||||
}
|
||||
}
|
||||
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
$item = $this->getItem($i);
|
||||
if($item->isNull()){
|
||||
if($this->isSlotEmpty($i)){
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($itemSlots as $index => $slot){
|
||||
if($slot->equals($item, !$slot->hasAnyDamageValue(), $slot->hasNamedTag())){
|
||||
$amount = min($item->getCount(), $slot->getCount());
|
||||
$slot->setCount($slot->getCount() - $amount);
|
||||
$item->setCount($item->getCount() - $amount);
|
||||
$this->setItem($i, $item);
|
||||
if($slot->getCount() <= 0){
|
||||
unset($itemSlots[$index]);
|
||||
foreach($searchItems as $index => $search){
|
||||
$slotCount = $this->getMatchingItemCount($i, $search, !$search->hasAnyDamageValue(), $search->hasNamedTag());
|
||||
if($slotCount > 0){
|
||||
$amount = min($slotCount, $search->getCount());
|
||||
$search->setCount($search->getCount() - $amount);
|
||||
|
||||
$slotItem = $this->getItem($i);
|
||||
$slotItem->setCount($slotItem->getCount() - $amount);
|
||||
$this->setItem($i, $slotItem);
|
||||
if($search->getCount() <= 0){
|
||||
unset($searchItems[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(count($itemSlots) === 0){
|
||||
if(count($searchItems) === 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $itemSlots;
|
||||
return $searchItems;
|
||||
}
|
||||
|
||||
public function clear(int $index) : void{
|
||||
|
@ -85,6 +85,10 @@ class DelegateInventory extends BaseInventory{
|
||||
$this->backingInventory->setContents($items);
|
||||
}
|
||||
|
||||
public function isSlotEmpty(int $index) : bool{
|
||||
return $this->backingInventory->isSlotEmpty($index);
|
||||
}
|
||||
|
||||
protected function onSlotChange(int $index, Item $before) : void{
|
||||
if($this->backingInventoryChanging){
|
||||
parent::onSlotChange($index, $before);
|
||||
|
@ -83,4 +83,13 @@ class SimpleInventory extends BaseInventory{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getMatchingItemCount(int $slot, Item $test, bool $checkDamage, bool $checkTags) : int{
|
||||
$slotItem = $this->slots[$slot];
|
||||
return $slotItem !== null && $slotItem->equals($test, $checkDamage, $checkTags) ? $slotItem->getCount() : 0;
|
||||
}
|
||||
|
||||
public function isSlotEmpty(int $index) : bool{
|
||||
return $this->slots[$index] === null || $this->slots[$index]->isNull();
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,6 @@ use pocketmine\utils\BinaryDataException;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\utils\ObjectSet;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\Position;
|
||||
use function array_map;
|
||||
use function array_values;
|
||||
@ -1000,8 +999,6 @@ class NetworkSession{
|
||||
* @phpstan-param \Closure() : void $onCompletion
|
||||
*/
|
||||
public function startUsingChunk(int $chunkX, int $chunkZ, \Closure $onCompletion) : void{
|
||||
Utils::validateCallableSignature(function() : void{}, $onCompletion);
|
||||
|
||||
$world = $this->player->getLocation()->getWorld();
|
||||
ChunkCache::getInstance($world, $this->compressor)->request($chunkX, $chunkZ)->onResolve(
|
||||
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\compression;
|
||||
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_push;
|
||||
|
||||
class CompressBatchPromise{
|
||||
@ -42,9 +41,6 @@ class CompressBatchPromise{
|
||||
*/
|
||||
public function onResolve(\Closure ...$callbacks) : void{
|
||||
$this->checkCancelled();
|
||||
foreach($callbacks as $callback){
|
||||
Utils::validateCallableSignature(function(CompressBatchPromise $promise) : void{}, $callback);
|
||||
}
|
||||
if($this->result !== null){
|
||||
foreach($callbacks as $callback){
|
||||
$callback($this);
|
||||
|
@ -48,8 +48,8 @@ final class RuntimeBlockMapping{
|
||||
private array $legacyToRuntimeMap = [];
|
||||
/** @var int[] */
|
||||
private array $runtimeToLegacyMap = [];
|
||||
/** @var CompoundTag[] */
|
||||
private array $bedrockKnownStates;
|
||||
/** @var CompoundTag[]|null */
|
||||
private ?array $bedrockKnownStates = null;
|
||||
|
||||
private static function make() : self{
|
||||
return new self(
|
||||
@ -85,25 +85,13 @@ final class RuntimeBlockMapping{
|
||||
return $newTag;
|
||||
}
|
||||
|
||||
public function __construct(string $canonicalBlockStatesFile, string $r12ToCurrentBlockMapFile){
|
||||
$stream = new BinaryStream(Filesystem::fileGetContents($canonicalBlockStatesFile));
|
||||
$list = [];
|
||||
$nbtReader = new NetworkNbtSerializer();
|
||||
public function __construct(
|
||||
private string $canonicalBlockStatesFile,
|
||||
string $r12ToCurrentBlockMapFile
|
||||
){
|
||||
//do not cache this - we only need it to set up mappings under normal circumstances
|
||||
$bedrockKnownStates = $this->loadBedrockKnownStates();
|
||||
|
||||
$keyIndex = [];
|
||||
$valueIndex = [];
|
||||
while(!$stream->feof()){
|
||||
$offset = $stream->getOffset();
|
||||
$blockState = $nbtReader->read($stream->getBuffer(), $offset)->mustGetCompoundTag();
|
||||
$stream->setOffset($offset);
|
||||
$list[] = self::deduplicateCompound($blockState, $keyIndex, $valueIndex);
|
||||
}
|
||||
$this->bedrockKnownStates = $list;
|
||||
|
||||
$this->setupLegacyMappings($r12ToCurrentBlockMapFile);
|
||||
}
|
||||
|
||||
private function setupLegacyMappings(string $r12ToCurrentBlockMapFile) : void{
|
||||
$legacyIdMap = LegacyBlockIdToStringIdMap::getInstance();
|
||||
/** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */
|
||||
$legacyStateMap = [];
|
||||
@ -123,7 +111,7 @@ final class RuntimeBlockMapping{
|
||||
* @var int[][] $idToStatesMap string id -> int[] list of candidate state indices
|
||||
*/
|
||||
$idToStatesMap = [];
|
||||
foreach($this->bedrockKnownStates as $k => $state){
|
||||
foreach($bedrockKnownStates as $k => $state){
|
||||
$idToStatesMap[$state->getString("name")][] = $k;
|
||||
}
|
||||
foreach($legacyStateMap as $pair){
|
||||
@ -142,7 +130,7 @@ final class RuntimeBlockMapping{
|
||||
throw new \RuntimeException("Mapped new state does not appear in network table");
|
||||
}
|
||||
foreach($idToStatesMap[$mappedName] as $k){
|
||||
$networkState = $this->bedrockKnownStates[$k];
|
||||
$networkState = $bedrockKnownStates[$k];
|
||||
if($mappedState->equals($networkState)){
|
||||
$this->registerMapping($k, $id, $data);
|
||||
continue 2;
|
||||
@ -152,6 +140,25 @@ final class RuntimeBlockMapping{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CompoundTag[]
|
||||
*/
|
||||
private function loadBedrockKnownStates() : array{
|
||||
$stream = new BinaryStream(Filesystem::fileGetContents($this->canonicalBlockStatesFile));
|
||||
$list = [];
|
||||
$nbtReader = new NetworkNbtSerializer();
|
||||
|
||||
$keyIndex = [];
|
||||
$valueIndex = [];
|
||||
while(!$stream->feof()){
|
||||
$offset = $stream->getOffset();
|
||||
$blockState = $nbtReader->read($stream->getBuffer(), $offset)->mustGetCompoundTag();
|
||||
$stream->setOffset($offset);
|
||||
$list[] = self::deduplicateCompound($blockState, $keyIndex, $valueIndex);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function toRuntimeId(int $internalStateId) : int{
|
||||
return $this->legacyToRuntimeMap[$internalStateId] ?? $this->legacyToRuntimeMap[BlockLegacyIds::INFO_UPDATE << Block::INTERNAL_METADATA_BITS];
|
||||
}
|
||||
@ -166,9 +173,14 @@ final class RuntimeBlockMapping{
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: This method may load the palette from disk, which is a slow operation.
|
||||
* Afterwards, it will cache the palette in memory, which requires (in some cases) tens of MB of memory.
|
||||
* Avoid using this where possible.
|
||||
*
|
||||
* @deprecated
|
||||
* @return CompoundTag[]
|
||||
*/
|
||||
public function getBedrockKnownStates() : array{
|
||||
return $this->bedrockKnownStates;
|
||||
return $this->bedrockKnownStates ??= $this->loadBedrockKnownStates();
|
||||
}
|
||||
}
|
||||
|
@ -1191,7 +1191,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
* TODO: make this a dynamic ability instead of being hardcoded
|
||||
*/
|
||||
public function hasFiniteResources() : bool{
|
||||
return $this->gamemode->equals(GameMode::SURVIVAL()) || $this->gamemode->equals(GameMode::ADVENTURE());
|
||||
return !$this->gamemode->equals(GameMode::CREATIVE());
|
||||
}
|
||||
|
||||
public function isFireProof() : bool{
|
||||
@ -1657,7 +1657,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
|
||||
$ev = new PlayerBlockPickEvent($this, $block, $item);
|
||||
$existingSlot = $this->inventory->first($item);
|
||||
if($existingSlot === -1 && ($this->hasFiniteResources() || $this->isSpectator())){
|
||||
if($existingSlot === -1 && $this->hasFiniteResources()){
|
||||
$ev->cancel();
|
||||
}
|
||||
$ev->call();
|
||||
|
@ -247,7 +247,6 @@ class AsyncPool{
|
||||
while(!$queue->isEmpty()){
|
||||
/** @var AsyncTask $task */
|
||||
$task = $queue->bottom();
|
||||
$task->checkProgressUpdates();
|
||||
if($task->isFinished()){ //make sure the task actually executed before trying to collect
|
||||
$queue->dequeue();
|
||||
|
||||
@ -268,6 +267,7 @@ class AsyncPool{
|
||||
$task->onCompletion();
|
||||
}
|
||||
}else{
|
||||
$task->checkProgressUpdates();
|
||||
$more = true;
|
||||
break; //current task is still running, skip to next worker
|
||||
}
|
||||
|
@ -87,14 +87,6 @@ abstract class Timings{
|
||||
/** @var TimingsHandler */
|
||||
public static $serverCommand;
|
||||
/** @var TimingsHandler */
|
||||
public static $worldLoad;
|
||||
/** @var TimingsHandler */
|
||||
public static $worldSave;
|
||||
/** @var TimingsHandler */
|
||||
public static $population;
|
||||
/** @var TimingsHandler */
|
||||
public static $generationCallback;
|
||||
/** @var TimingsHandler */
|
||||
public static $permissibleCalculation;
|
||||
/** @var TimingsHandler */
|
||||
public static $permissibleCalculationDiff;
|
||||
@ -111,10 +103,6 @@ abstract class Timings{
|
||||
|
||||
/** @var TimingsHandler */
|
||||
public static $playerCheckNearEntities;
|
||||
/** @var TimingsHandler */
|
||||
public static $tickEntity;
|
||||
/** @var TimingsHandler */
|
||||
public static $tickTileEntity;
|
||||
|
||||
/** @var TimingsHandler */
|
||||
public static $entityBaseTick;
|
||||
@ -203,10 +191,6 @@ abstract class Timings{
|
||||
self::$playerChunkSend = new TimingsHandler("Player Network Send - Chunks", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||
self::$scheduler = new TimingsHandler("Scheduler");
|
||||
self::$serverCommand = new TimingsHandler("Server Command");
|
||||
self::$worldLoad = new TimingsHandler("World Load");
|
||||
self::$worldSave = new TimingsHandler("World Save");
|
||||
self::$population = new TimingsHandler("World Population");
|
||||
self::$generationCallback = new TimingsHandler("World Generation Callback");
|
||||
self::$permissibleCalculation = new TimingsHandler("Permissible Calculation");
|
||||
self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
||||
self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
||||
@ -221,9 +205,6 @@ abstract class Timings{
|
||||
self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove, group: self::GROUP_BREAKDOWN);
|
||||
|
||||
self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities", group: self::GROUP_BREAKDOWN);
|
||||
self::$tickEntity = new TimingsHandler("Entity Tick", group: self::GROUP_BREAKDOWN);
|
||||
self::$tickTileEntity = new TimingsHandler("Block Entity Tick", group: self::GROUP_BREAKDOWN);
|
||||
|
||||
self::$entityBaseTick = new TimingsHandler("Entity Base Tick", group: self::GROUP_BREAKDOWN);
|
||||
self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living", group: self::GROUP_BREAKDOWN);
|
||||
self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity", group: self::GROUP_BREAKDOWN);
|
||||
@ -272,7 +253,7 @@ abstract class Timings{
|
||||
}else{
|
||||
$displayName = self::shortenCoreClassName($entity::class, "pocketmine\\entity\\");
|
||||
}
|
||||
self::$entityTypeTimingMap[$entity::class] = new TimingsHandler("Entity Tick - " . $displayName, self::$tickEntity, group: self::GROUP_BREAKDOWN);
|
||||
self::$entityTypeTimingMap[$entity::class] = new TimingsHandler("Entity Tick - " . $displayName, group: self::GROUP_BREAKDOWN);
|
||||
}
|
||||
|
||||
return self::$entityTypeTimingMap[$entity::class];
|
||||
@ -282,7 +263,6 @@ abstract class Timings{
|
||||
if(!isset(self::$tileEntityTypeTimingMap[$tile::class])){
|
||||
self::$tileEntityTypeTimingMap[$tile::class] = new TimingsHandler(
|
||||
"Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\"),
|
||||
self::$tickTileEntity,
|
||||
group: self::GROUP_BREAKDOWN
|
||||
);
|
||||
}
|
||||
|
@ -23,10 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\timings;
|
||||
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Utils;
|
||||
use function count;
|
||||
use function hrtime;
|
||||
use function implode;
|
||||
use function spl_object_id;
|
||||
@ -77,19 +75,6 @@ class TimingsHandler{
|
||||
$result[] = "# Version " . Server::getInstance()->getVersion();
|
||||
$result[] = "# " . Server::getInstance()->getName() . " " . Server::getInstance()->getPocketMineVersion();
|
||||
|
||||
$entities = 0;
|
||||
$livingEntities = 0;
|
||||
foreach(Server::getInstance()->getWorldManager()->getWorlds() as $world){
|
||||
$entities += count($world->getEntities());
|
||||
foreach($world->getEntities() as $e){
|
||||
if($e instanceof Living){
|
||||
++$livingEntities;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = "# Entities " . $entities;
|
||||
$result[] = "# LivingEntities " . $livingEntities;
|
||||
$result[] = "# FormatVersion " . self::FORMAT_VERSION;
|
||||
|
||||
$sampleTime = hrtime(true) - self::$timingStart;
|
||||
|
@ -1,37 +0,0 @@
|
||||
<?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\world;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class TickingChunkEntry{
|
||||
/**
|
||||
* @var ChunkTicker[] spl_object_id => ChunkTicker
|
||||
* @phpstan-var array<int, ChunkTicker>
|
||||
*/
|
||||
public array $tickers = [];
|
||||
|
||||
public bool $ready = false;
|
||||
}
|
@ -77,7 +77,6 @@ use pocketmine\promise\PromiseResolver;
|
||||
use pocketmine\scheduler\AsyncPool;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\ServerConfigGroup;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\utils\ReversePriorityQueue;
|
||||
@ -104,6 +103,7 @@ use pocketmine\world\utils\SubChunkExplorer;
|
||||
use function abs;
|
||||
use function array_filter;
|
||||
use function array_key_exists;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function array_sum;
|
||||
@ -223,10 +223,25 @@ class World implements ChunkManager{
|
||||
private array $tickingLoaderCounter = [];
|
||||
|
||||
/**
|
||||
* @var TickingChunkEntry[] chunkHash => TickingChunkEntry
|
||||
* @phpstan-var array<ChunkPosHash, TickingChunkEntry>
|
||||
* @var ChunkTicker[][] chunkHash => [spl_object_id => ChunkTicker]
|
||||
* @phpstan-var array<ChunkPosHash, array<int, ChunkTicker>>
|
||||
*/
|
||||
private array $tickingChunks = [];
|
||||
private array $registeredTickingChunks = [];
|
||||
|
||||
/**
|
||||
* Set of chunks which are definitely ready for ticking.
|
||||
*
|
||||
* @var int[]
|
||||
* @phpstan-var array<ChunkPosHash, ChunkPosHash>
|
||||
*/
|
||||
private array $validTickingChunks = [];
|
||||
|
||||
/**
|
||||
* Set of chunks which might be ready for ticking. These will be checked at the next tick.
|
||||
* @var int[]
|
||||
* @phpstan-var array<ChunkPosHash, ChunkPosHash>
|
||||
*/
|
||||
private array $recheckTickingChunks = [];
|
||||
|
||||
/**
|
||||
* @var ChunkLoader[][] chunkHash => [spl_object_id => ChunkLoader]
|
||||
@ -983,7 +998,6 @@ class World implements ChunkManager{
|
||||
|
||||
$this->timings->entityTick->startTiming();
|
||||
//Update entities that need update
|
||||
Timings::$tickEntity->startTiming();
|
||||
foreach($this->updateEntities as $id => $entity){
|
||||
if($entity->isClosed() || $entity->isFlaggedForDespawn() || !$entity->onUpdate($currentTick)){
|
||||
unset($this->updateEntities[$id]);
|
||||
@ -992,7 +1006,6 @@ class World implements ChunkManager{
|
||||
$entity->close();
|
||||
}
|
||||
}
|
||||
Timings::$tickEntity->stopTiming();
|
||||
$this->timings->entityTick->stopTiming();
|
||||
|
||||
$this->timings->randomChunkUpdates->startTiming();
|
||||
@ -1155,17 +1168,25 @@ class World implements ChunkManager{
|
||||
$this->chunkTickRadius = $radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of chunk position hashes (as returned by World::chunkHash()) which are currently valid for
|
||||
* ticking.
|
||||
*
|
||||
* @return int[]
|
||||
* @phpstan-return list<ChunkPosHash>
|
||||
*/
|
||||
public function getTickingChunks() : array{
|
||||
return array_keys($this->validTickingChunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the World to tick the specified chunk, for as long as this chunk ticker (or any other chunk ticker) is
|
||||
* registered to it.
|
||||
*/
|
||||
public function registerTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void{
|
||||
$chunkPosHash = World::chunkHash($chunkX, $chunkZ);
|
||||
$entry = $this->tickingChunks[$chunkPosHash] ?? null;
|
||||
if($entry === null){
|
||||
$entry = $this->tickingChunks[$chunkPosHash] = new TickingChunkEntry();
|
||||
}
|
||||
$entry->tickers[spl_object_id($ticker)] = $ticker;
|
||||
$this->registeredTickingChunks[$chunkPosHash][spl_object_id($ticker)] = $ticker;
|
||||
$this->recheckTickingChunks[$chunkPosHash] = $chunkPosHash;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1175,10 +1196,14 @@ class World implements ChunkManager{
|
||||
public function unregisterTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void{
|
||||
$chunkHash = World::chunkHash($chunkX, $chunkZ);
|
||||
$tickerId = spl_object_id($ticker);
|
||||
if(isset($this->tickingChunks[$chunkHash]->tickers[$tickerId])){
|
||||
unset($this->tickingChunks[$chunkHash]->tickers[$tickerId]);
|
||||
if(count($this->tickingChunks[$chunkHash]->tickers) === 0){
|
||||
unset($this->tickingChunks[$chunkHash]);
|
||||
if(isset($this->registeredTickingChunks[$chunkHash][$tickerId])){
|
||||
unset($this->registeredTickingChunks[$chunkHash][$tickerId]);
|
||||
if(count($this->registeredTickingChunks[$chunkHash]) === 0){
|
||||
unset(
|
||||
$this->registeredTickingChunks[$chunkHash],
|
||||
$this->recheckTickingChunks[$chunkHash],
|
||||
$this->validTickingChunks[$chunkHash]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1222,37 +1247,37 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
private function tickChunks() : void{
|
||||
if($this->chunkTickRadius <= 0 || (count($this->tickingChunks) === 0 && count($this->tickingLoaders) === 0)){
|
||||
if($this->chunkTickRadius <= 0 || (count($this->registeredTickingChunks) === 0 && count($this->tickingLoaders) === 0)){
|
||||
return;
|
||||
}
|
||||
|
||||
$this->timings->randomChunkUpdatesChunkSelection->startTiming();
|
||||
if(count($this->recheckTickingChunks) > 0 || count($this->tickingLoaders) > 0){
|
||||
$this->timings->randomChunkUpdatesChunkSelection->startTiming();
|
||||
|
||||
/** @var bool[] $chunkTickList chunkhash => dummy */
|
||||
$chunkTickList = [];
|
||||
$chunkTickableCache = [];
|
||||
|
||||
$chunkTickableCache = [];
|
||||
|
||||
foreach($this->tickingChunks as $hash => $entry){
|
||||
if(!$entry->ready){
|
||||
foreach($this->recheckTickingChunks as $hash => $_){
|
||||
World::getXZ($hash, $chunkX, $chunkZ);
|
||||
if($this->isChunkTickable($chunkX, $chunkZ, $chunkTickableCache)){
|
||||
$entry->ready = true;
|
||||
}else{
|
||||
//the chunk has been flagged as temporarily not tickable, so we don't want to tick it this time
|
||||
continue;
|
||||
$this->validTickingChunks[$hash] = $hash;
|
||||
}
|
||||
}
|
||||
$chunkTickList[$hash] = true;
|
||||
}
|
||||
$this->recheckTickingChunks = [];
|
||||
|
||||
//TODO: REMOVE THIS
|
||||
//backwards compatibility for TickingChunkLoader, although I'm not sure this is really necessary in practice
|
||||
if(count($this->tickingLoaders) !== 0){
|
||||
$this->selectTickableChunksLegacy($chunkTickList, $chunkTickableCache);
|
||||
}
|
||||
//TODO: REMOVE THIS - we need a local var to add extra chunks to if we have legacy ticking loaders
|
||||
//this is copy-on-write, so it won't have any performance impact if there are no legacy ticking loaders
|
||||
$chunkTickList = $this->validTickingChunks;
|
||||
|
||||
$this->timings->randomChunkUpdatesChunkSelection->stopTiming();
|
||||
//TODO: REMOVE THIS
|
||||
//backwards compatibility for TickingChunkLoader, although I'm not sure this is really necessary in practice
|
||||
if(count($this->tickingLoaders) !== 0){
|
||||
$this->selectTickableChunksLegacy($chunkTickList, $chunkTickableCache);
|
||||
}
|
||||
|
||||
$this->timings->randomChunkUpdatesChunkSelection->stopTiming();
|
||||
}else{
|
||||
$chunkTickList = $this->validTickingChunks;
|
||||
}
|
||||
|
||||
foreach($chunkTickList as $index => $_){
|
||||
World::getXZ($index, $chunkX, $chunkZ);
|
||||
@ -1303,16 +1328,23 @@ class World implements ChunkManager{
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the 3x3 chunks around the specified chunk as not ready to be ticked. This is used to prevent chunk ticking
|
||||
* while a chunk is being populated, light-populated, or unloaded.
|
||||
* Each chunk will be rechecked every tick until it is ready to be ticked again.
|
||||
* Marks the 3x3 square of chunks centered on the specified chunk for chunk ticking eligibility recheck.
|
||||
*
|
||||
* This should be used whenever the chunk's eligibility to be ticked is changed. This includes:
|
||||
* - Loading/unloading the chunk (the chunk may be registered for ticking before it is loaded)
|
||||
* - Locking/unlocking the chunk (e.g. world population)
|
||||
* - Light populated state change (i.e. scheduled for light population, or light population completed)
|
||||
* - Arbitrary chunk replacement (i.e. setChunk() or similar)
|
||||
*/
|
||||
private function markTickingChunkUnavailable(int $chunkX, int $chunkZ) : void{
|
||||
private function markTickingChunkForRecheck(int $chunkX, int $chunkZ) : void{
|
||||
for($cx = -1; $cx <= 1; ++$cx){
|
||||
for($cz = -1; $cz <= 1; ++$cz){
|
||||
$chunkHash = World::chunkHash($chunkX + $cx, $chunkZ + $cz);
|
||||
if(isset($this->tickingChunks[$chunkHash])){
|
||||
$this->tickingChunks[$chunkHash]->ready = false;
|
||||
unset($this->validTickingChunks[$chunkHash]);
|
||||
if(isset($this->registeredTickingChunks[$chunkHash])){
|
||||
$this->recheckTickingChunks[$chunkHash] = $chunkHash;
|
||||
}else{
|
||||
unset($this->recheckTickingChunks[$chunkHash]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1323,7 +1355,7 @@ class World implements ChunkManager{
|
||||
$lightPopulatedState = $this->chunks[$chunkHash]->isLightPopulated();
|
||||
if($lightPopulatedState === false){
|
||||
$this->chunks[$chunkHash]->setLightPopulated(null);
|
||||
$this->markTickingChunkUnavailable($chunkX, $chunkZ);
|
||||
$this->markTickingChunkForRecheck($chunkX, $chunkZ);
|
||||
|
||||
$this->workerPool->submitTask(new LightPopulationTask(
|
||||
$this->chunks[$chunkHash],
|
||||
@ -1347,6 +1379,7 @@ class World implements ChunkManager{
|
||||
$chunk->getSubChunk($y)->setBlockSkyLightArray($lightArray);
|
||||
}
|
||||
$chunk->setLightPopulated(true);
|
||||
$this->markTickingChunkForRecheck($chunkX, $chunkZ);
|
||||
}
|
||||
));
|
||||
}
|
||||
@ -1403,10 +1436,15 @@ class World implements ChunkManager{
|
||||
|
||||
(new WorldSaveEvent($this))->call();
|
||||
|
||||
$timings = $this->timings->syncDataSave;
|
||||
$timings->startTiming();
|
||||
|
||||
$this->provider->getWorldData()->setTime($this->time);
|
||||
$this->saveChunks();
|
||||
$this->provider->getWorldData()->save();
|
||||
|
||||
$timings->stopTiming();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2391,7 +2429,7 @@ class World implements ChunkManager{
|
||||
throw new \InvalidArgumentException("Chunk $chunkX $chunkZ is already locked");
|
||||
}
|
||||
$this->chunkLock[$chunkHash] = $lockId;
|
||||
$this->markTickingChunkUnavailable($chunkX, $chunkZ);
|
||||
$this->markTickingChunkForRecheck($chunkX, $chunkZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2406,6 +2444,7 @@ class World implements ChunkManager{
|
||||
$chunkHash = World::chunkHash($chunkX, $chunkZ);
|
||||
if(isset($this->chunkLock[$chunkHash]) && ($lockId === null || $this->chunkLock[$chunkHash] === $lockId)){
|
||||
unset($this->chunkLock[$chunkHash]);
|
||||
$this->markTickingChunkForRecheck($chunkX, $chunkZ);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -2457,7 +2496,7 @@ class World implements ChunkManager{
|
||||
unset($this->blockCache[$chunkHash]);
|
||||
unset($this->changedBlocks[$chunkHash]);
|
||||
$chunk->setTerrainDirty();
|
||||
$this->markTickingChunkUnavailable($chunkX, $chunkZ); //this replacement chunk may not meet the conditions for ticking
|
||||
$this->markTickingChunkForRecheck($chunkX, $chunkZ); //this replacement chunk may not meet the conditions for ticking
|
||||
|
||||
if(!$this->isChunkInUse($chunkX, $chunkZ)){
|
||||
$this->unloadChunkRequest($chunkX, $chunkZ);
|
||||
@ -2739,6 +2778,7 @@ class World implements ChunkManager{
|
||||
foreach($this->getChunkListeners($x, $z) as $listener){
|
||||
$listener->onChunkLoaded($x, $z, $this->chunks[$chunkHash]);
|
||||
}
|
||||
$this->markTickingChunkForRecheck($x, $z); //tickers may have been registered before the chunk was loaded
|
||||
|
||||
$this->timings->syncChunkLoad->stopTiming();
|
||||
|
||||
@ -2900,8 +2940,8 @@ class World implements ChunkManager{
|
||||
unset($this->chunks[$chunkHash]);
|
||||
unset($this->blockCache[$chunkHash]);
|
||||
unset($this->changedBlocks[$chunkHash]);
|
||||
unset($this->tickingChunks[$chunkHash]);
|
||||
$this->markTickingChunkUnavailable($x, $z);
|
||||
unset($this->registeredTickingChunks[$chunkHash]);
|
||||
$this->markTickingChunkForRecheck($x, $z);
|
||||
|
||||
if(array_key_exists($chunkHash, $this->chunkPopulationRequestMap)){
|
||||
$this->logger->debug("Rejecting population promise for chunk $x $z");
|
||||
@ -3210,7 +3250,8 @@ class World implements ChunkManager{
|
||||
private function internalOrderChunkPopulation(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader, ?PromiseResolver $resolver) : Promise{
|
||||
$chunkHash = World::chunkHash($chunkX, $chunkZ);
|
||||
|
||||
Timings::$population->startTiming();
|
||||
$timings = $this->timings->chunkPopulationOrder;
|
||||
$timings->startTiming();
|
||||
|
||||
try{
|
||||
for($xx = -1; $xx <= 1; ++$xx){
|
||||
@ -3267,7 +3308,7 @@ class World implements ChunkManager{
|
||||
|
||||
return $resolver->getPromise();
|
||||
}finally{
|
||||
Timings::$population->stopTiming();
|
||||
$timings->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3276,7 +3317,8 @@ class World implements ChunkManager{
|
||||
* @phpstan-param array<int, Chunk> $adjacentChunks
|
||||
*/
|
||||
private function generateChunkCallback(ChunkLockId $chunkLockId, int $x, int $z, Chunk $chunk, array $adjacentChunks, ChunkLoader $temporaryChunkLoader) : void{
|
||||
Timings::$generationCallback->startTiming();
|
||||
$timings = $this->timings->chunkPopulationCompletion;
|
||||
$timings->startTiming();
|
||||
|
||||
$dirtyChunks = 0;
|
||||
for($xx = -1; $xx <= 1; ++$xx){
|
||||
@ -3345,7 +3387,7 @@ class World implements ChunkManager{
|
||||
|
||||
$this->drainPopulationRequestQueue();
|
||||
}
|
||||
Timings::$generationCallback->stopTiming();
|
||||
$timings->stopTiming();
|
||||
}
|
||||
|
||||
public function doChunkGarbageCollection() : void{
|
||||
|
@ -30,7 +30,6 @@ use pocketmine\event\world\WorldUnloadEvent;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\player\ChunkSelector;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\format\io\exception\CorruptedWorldException;
|
||||
use pocketmine\world\format\io\exception\UnsupportedWorldFormatException;
|
||||
@ -391,7 +390,6 @@ class WorldManager{
|
||||
}
|
||||
|
||||
private function doAutoSave() : void{
|
||||
Timings::$worldSave->startTiming();
|
||||
foreach($this->worlds as $world){
|
||||
foreach($world->getPlayers() as $player){
|
||||
if($player->spawned){
|
||||
@ -400,6 +398,5 @@ class WorldManager{
|
||||
}
|
||||
$world->save(false);
|
||||
}
|
||||
Timings::$worldSave->stopTiming();
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ class WorldTimings{
|
||||
public TimingsHandler $randomChunkUpdatesChunkSelection;
|
||||
public TimingsHandler $doChunkGC;
|
||||
public TimingsHandler $entityTick;
|
||||
public TimingsHandler $tileTick;
|
||||
public TimingsHandler $doTick;
|
||||
|
||||
public TimingsHandler $syncChunkSend;
|
||||
@ -48,33 +49,54 @@ class WorldTimings{
|
||||
public TimingsHandler $syncChunkLoadFixInvalidBlocks;
|
||||
public TimingsHandler $syncChunkLoadEntities;
|
||||
public TimingsHandler $syncChunkLoadTileEntities;
|
||||
|
||||
public TimingsHandler $syncDataSave;
|
||||
public TimingsHandler $syncChunkSave;
|
||||
|
||||
public TimingsHandler $chunkPopulationOrder;
|
||||
public TimingsHandler $chunkPopulationCompletion;
|
||||
|
||||
/**
|
||||
* @var TimingsHandler[]
|
||||
* @phpstan-var array<string, TimingsHandler>
|
||||
*/
|
||||
private static array $aggregators = [];
|
||||
|
||||
private static function newTimer(string $worldName, string $timerName) : TimingsHandler{
|
||||
$aggregator = self::$aggregators[$timerName] ??= new TimingsHandler("Worlds - $timerName"); //displayed in Minecraft primary table
|
||||
|
||||
return new TimingsHandler("$worldName - $timerName", $aggregator, Timings::GROUP_BREAKDOWN);
|
||||
}
|
||||
|
||||
public function __construct(World $world){
|
||||
$name = $world->getFolderName() . " - ";
|
||||
$name = $world->getFolderName();
|
||||
|
||||
$this->setBlock = new TimingsHandler($name . "setBlock", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->doBlockLightUpdates = new TimingsHandler($name . "Block Light Updates", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->doBlockSkyLightUpdates = new TimingsHandler($name . "Sky Light Updates", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->setBlock = self::newTimer($name, "Set Blocks");
|
||||
$this->doBlockLightUpdates = self::newTimer($name, "Block Light Updates");
|
||||
$this->doBlockSkyLightUpdates = self::newTimer($name, "Sky Light Updates");
|
||||
|
||||
$this->doChunkUnload = new TimingsHandler($name . "Unload Chunks", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->scheduledBlockUpdates = new TimingsHandler($name . "Scheduled Block Updates", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->randomChunkUpdates = new TimingsHandler($name . "Random Chunk Updates", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->randomChunkUpdatesChunkSelection = new TimingsHandler($name . "Random Chunk Updates - Chunk Selection", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->doChunkGC = new TimingsHandler($name . "Garbage Collection", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->entityTick = new TimingsHandler($name . "Tick Entities", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->doChunkUnload = self::newTimer($name, "Unload Chunks");
|
||||
$this->scheduledBlockUpdates = self::newTimer($name, "Scheduled Block Updates");
|
||||
$this->randomChunkUpdates = self::newTimer($name, "Random Chunk Updates");
|
||||
$this->randomChunkUpdatesChunkSelection = self::newTimer($name, "Random Chunk Updates - Chunk Selection");
|
||||
$this->doChunkGC = self::newTimer($name, "Garbage Collection");
|
||||
$this->entityTick = self::newTimer($name, "Entity Tick");
|
||||
$this->tileTick = self::newTimer($name, "Block Entity Tick");
|
||||
$this->doTick = self::newTimer($name, "World Tick");
|
||||
|
||||
Timings::init(); //make sure the timers we want are available
|
||||
$this->syncChunkSend = new TimingsHandler($name . "Player Send Chunks", Timings::$playerChunkSend, group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkSendPrepare = new TimingsHandler($name . "Player Send Chunk Prepare", Timings::$playerChunkSend, group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkSend = self::newTimer($name, "Player Send Chunks");
|
||||
$this->syncChunkSendPrepare = self::newTimer($name, "Player Send Chunk Prepare");
|
||||
|
||||
$this->syncChunkLoad = new TimingsHandler($name . "Chunk Load", Timings::$worldLoad, group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkLoadData = new TimingsHandler($name . "Chunk Load - Data", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkLoadFixInvalidBlocks = new TimingsHandler($name . "Chunk Load - Fix Invalid Blocks", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkLoadEntities = new TimingsHandler($name . "Chunk Load - Entities", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkLoadTileEntities = new TimingsHandler($name . "Chunk Load - TileEntities", group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkSave = new TimingsHandler($name . "Chunk Save", Timings::$worldSave, group: Timings::GROUP_BREAKDOWN);
|
||||
$this->syncChunkLoad = self::newTimer($name, "Chunk Load");
|
||||
$this->syncChunkLoadData = self::newTimer($name, "Chunk Load - Data");
|
||||
$this->syncChunkLoadFixInvalidBlocks = self::newTimer($name, "Chunk Load - Fix Invalid Blocks");
|
||||
$this->syncChunkLoadEntities = self::newTimer($name, "Chunk Load - Entities");
|
||||
$this->syncChunkLoadTileEntities = self::newTimer($name, "Chunk Load - Block Entities");
|
||||
|
||||
$this->doTick = new TimingsHandler($name . "World Tick");
|
||||
$this->syncDataSave = self::newTimer($name, "Data Save");
|
||||
$this->syncChunkSave = self::newTimer($name, "Chunk Save");
|
||||
|
||||
$this->chunkPopulationOrder = self::newTimer($name, "Chunk Population - Order");
|
||||
$this->chunkPopulationCompletion = self::newTimer($name, "Chunk Population - Completion");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user