Merge branch 'next-minor' into next-major

This commit is contained in:
Dylan K. Taylor 2023-01-13 17:29:25 +00:00
commit 8909aa6a18
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
9 changed files with 74 additions and 35 deletions

View File

@ -43,7 +43,7 @@
"pocketmine/classloader": "^0.2.0", "pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.3.0", "pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.6.0", "pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.16.0", "pocketmine/locale-data": "~2.17.0",
"pocketmine/log": "^0.4.0", "pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0", "pocketmine/math": "^0.4.0",

14
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "ecbdb7bda8ed93cb0499bfe486a68ff6", "content-hash": "5c869a38ea239fff76262c1648cef623",
"packages": [ "packages": [
{ {
"name": "adhocore/json-comment", "name": "adhocore/json-comment",
@ -591,16 +591,16 @@
}, },
{ {
"name": "pocketmine/locale-data", "name": "pocketmine/locale-data",
"version": "2.16.0", "version": "2.17.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/Language.git", "url": "https://github.com/pmmp/Language.git",
"reference": "b3bf9029c112414fdb7cd9de778df191565d3038" "reference": "a2c7071117c98ccc0e333994271cab1072eb3c06"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/b3bf9029c112414fdb7cd9de778df191565d3038", "url": "https://api.github.com/repos/pmmp/Language/zipball/a2c7071117c98ccc0e333994271cab1072eb3c06",
"reference": "b3bf9029c112414fdb7cd9de778df191565d3038", "reference": "a2c7071117c98ccc0e333994271cab1072eb3c06",
"shasum": "" "shasum": ""
}, },
"type": "library", "type": "library",
@ -608,9 +608,9 @@
"description": "Language resources used by PocketMine-MP", "description": "Language resources used by PocketMine-MP",
"support": { "support": {
"issues": "https://github.com/pmmp/Language/issues", "issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.16.0" "source": "https://github.com/pmmp/Language/tree/2.17.0"
}, },
"time": "2023-01-04T20:27:52+00:00" "time": "2023-01-13T17:22:45+00:00"
}, },
{ {
"name": "pocketmine/log", "name": "pocketmine/log",

View File

@ -69,6 +69,10 @@ use const JSON_UNESCAPED_SLASHES;
use const SORT_NUMERIC; use const SORT_NUMERIC;
class MemoryManager{ class MemoryManager{
private const DEFAULT_CHECK_RATE = Server::TARGET_TICKS_PER_SECOND;
private const DEFAULT_CONTINUOUS_TRIGGER_RATE = Server::TARGET_TICKS_PER_SECOND * 2;
private const DEEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
private int $memoryLimit; private int $memoryLimit;
private int $globalMemoryLimit; private int $globalMemoryLimit;
private int $checkRate; private int $checkRate;
@ -131,11 +135,11 @@ class MemoryManager{
} }
$this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024; $this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024;
$this->checkRate = $config->getPropertyInt("memory.check-rate", 20); $this->checkRate = $config->getPropertyInt("memory.check-rate", self::DEFAULT_CHECK_RATE);
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true); $this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", 30); $this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", 36000); $this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEEFAULT_TICKS_PER_GC);
$this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true); $this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true);
$this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true); $this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true);

View File

@ -117,6 +117,7 @@ use pocketmine\world\WorldCreationOptions;
use pocketmine\world\WorldManager; use pocketmine\world\WorldManager;
use Ramsey\Uuid\UuidInterface; use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Filesystem\Path; use Symfony\Component\Filesystem\Path;
use function array_fill;
use function array_sum; use function array_sum;
use function base64_encode; use function base64_encode;
use function cli_set_process_title; use function cli_set_process_title;
@ -181,6 +182,27 @@ class Server{
public const DEFAULT_PORT_IPV6 = 19133; public const DEFAULT_PORT_IPV6 = 19133;
public const DEFAULT_MAX_VIEW_DISTANCE = 16; public const DEFAULT_MAX_VIEW_DISTANCE = 16;
/**
* Worlds, network, commands and most other things are polled this many times per second on average.
* Between ticks, the server will sleep to ensure that the average tick rate is maintained.
* It may wake up between ticks if a Snooze notification source is triggered (e.g. to process network packets).
*/
public const TARGET_TICKS_PER_SECOND = 20;
/**
* The average time between ticks, in seconds.
*/
public const TARGET_SECONDS_PER_TICK = 1 / self::TARGET_TICKS_PER_SECOND;
public const TARGET_NANOSECONDS_PER_TICK = 1_000_000_000 / self::TARGET_TICKS_PER_SECOND;
/**
* The TPS threshold below which the server will generate log warnings.
*/
private const TPS_OVERLOAD_WARNING_THRESHOLD = self::TARGET_TICKS_PER_SECOND * 0.6;
private const TICKS_PER_WORLD_CACHE_CLEAR = 5 * self::TARGET_TICKS_PER_SECOND;
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 static ?Server $instance = null; private static ?Server $instance = null;
private SleeperHandler $tickSleeper; private SleeperHandler $tickSleeper;
@ -199,7 +221,7 @@ class Server{
private PluginManager $pluginManager; private PluginManager $pluginManager;
private float $profilingTickRate = 20; private float $profilingTickRate = self::TARGET_TICKS_PER_SECOND;
private UpdateChecker $updater; private UpdateChecker $updater;
@ -209,10 +231,10 @@ class Server{
private int $tickCounter = 0; private int $tickCounter = 0;
private float $nextTick = 0; private float $nextTick = 0;
/** @var float[] */ /** @var float[] */
private array $tickAverage = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]; private array $tickAverage;
/** @var float[] */ /** @var float[] */
private array $useAverage = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; private array $useAverage;
private float $currentTPS = 20; private float $currentTPS = self::TARGET_TICKS_PER_SECOND;
private float $currentUse = 0; private float $currentUse = 0;
private float $startTime; private float $startTime;
@ -748,6 +770,8 @@ class Server{
} }
self::$instance = $this; self::$instance = $this;
$this->startTime = microtime(true); $this->startTime = microtime(true);
$this->tickAverage = array_fill(0, self::TARGET_TICKS_PER_SECOND, self::TARGET_TICKS_PER_SECOND);
$this->useAverage = array_fill(0, self::TARGET_TICKS_PER_SECOND, 0);
$this->tickSleeper = new SleeperHandler(); $this->tickSleeper = new SleeperHandler();
@ -931,7 +955,7 @@ class Server{
Timings::init(); Timings::init();
TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false)); TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false));
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", 20); $this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", self::TARGET_TICKS_PER_SECOND);
DefaultPermissions::registerCorePermissions(); DefaultPermissions::registerCorePermissions();
@ -969,7 +993,7 @@ class Server{
$this->worldManager = new WorldManager($this, Path::join($this->dataPath, "worlds"), $providerManager); $this->worldManager = new WorldManager($this, Path::join($this->dataPath, "worlds"), $providerManager);
$this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave())); $this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave()));
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", 6000)); $this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", $this->worldManager->getAutoSaveInterval()));
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString("auto-updater.host", "update.pmmp.io")); $this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString("auto-updater.host", "update.pmmp.io"));
@ -1009,7 +1033,7 @@ class Server{
} }
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){ if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
$this->sendUsageTicker = 6000; $this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
$this->sendUsage(SendUsageTask::TYPE_OPEN); $this->sendUsage(SendUsageTask::TYPE_OPEN);
} }
@ -1792,11 +1816,11 @@ class Server{
$this->network->tick(); $this->network->tick();
Timings::$connection->stopTiming(); Timings::$connection->stopTiming();
if(($this->tickCounter % 20) === 0){ if(($this->tickCounter % self::TARGET_TICKS_PER_SECOND) === 0){
if($this->doTitleTick){ if($this->doTitleTick){
$this->titleTick(); $this->titleTick();
} }
$this->currentTPS = 20; $this->currentTPS = self::TARGET_TICKS_PER_SECOND;
$this->currentUse = 0; $this->currentUse = 0;
$queryRegenerateEvent = new QueryRegenerateEvent(new QueryInfo($this)); $queryRegenerateEvent = new QueryRegenerateEvent(new QueryInfo($this));
@ -1808,18 +1832,18 @@ class Server{
} }
if($this->sendUsageTicker > 0 && --$this->sendUsageTicker === 0){ if($this->sendUsageTicker > 0 && --$this->sendUsageTicker === 0){
$this->sendUsageTicker = 6000; $this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
$this->sendUsage(SendUsageTask::TYPE_STATUS); $this->sendUsage(SendUsageTask::TYPE_STATUS);
} }
if(($this->tickCounter % 100) === 0){ if(($this->tickCounter % self::TICKS_PER_WORLD_CACHE_CLEAR) === 0){
foreach($this->worldManager->getWorlds() as $world){ foreach($this->worldManager->getWorlds() as $world){
$world->clearCache(); $world->clearCache();
} }
}
if($this->getTicksPerSecondAverage() < 12){ if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload())); $this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
}
} }
$this->getMemoryManager()->check(); $this->getMemoryManager()->check();
@ -1836,19 +1860,19 @@ class Server{
Timings::$serverTick->stopTiming(); Timings::$serverTick->stopTiming();
$now = microtime(true); $now = microtime(true);
$this->currentTPS = min(20, 1 / max(0.001, $now - $tickTime)); $this->currentTPS = min(self::TARGET_TICKS_PER_SECOND, 1 / max(0.001, $now - $tickTime));
$this->currentUse = min(1, ($now - $tickTime) / 0.05); $this->currentUse = min(1, ($now - $tickTime) / self::TARGET_SECONDS_PER_TICK);
TimingsHandler::tick($this->currentTPS <= $this->profilingTickRate); TimingsHandler::tick($this->currentTPS <= $this->profilingTickRate);
$idx = $this->tickCounter % 20; $idx = $this->tickCounter % self::TARGET_TICKS_PER_SECOND;
$this->tickAverage[$idx] = $this->currentTPS; $this->tickAverage[$idx] = $this->currentTPS;
$this->useAverage[$idx] = $this->currentUse; $this->useAverage[$idx] = $this->currentUse;
if(($this->nextTick - $tickTime) < -1){ if(($this->nextTick - $tickTime) < -1){
$this->nextTick = $tickTime; $this->nextTick = $tickTime;
}else{ }else{
$this->nextTick += 0.05; $this->nextTick += self::TARGET_SECONDS_PER_TICK;
} }
} }
} }

View File

@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Jukebox as JukeboxTile; use pocketmine\block\tile\Jukebox as JukeboxTile;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\Record; use pocketmine\item\Record;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\sound\RecordSound; use pocketmine\world\sound\RecordSound;
@ -44,7 +45,7 @@ class Jukebox extends Opaque{
if($this->record !== null){ if($this->record !== null){
$this->ejectRecord(); $this->ejectRecord();
}elseif($item instanceof Record){ }elseif($item instanceof Record){
$player->sendJukeboxPopup("record.nowPlaying", [$player->getLanguage()->translate($item->getRecordType()->getTranslatableName())]); $player->sendJukeboxPopup(KnownTranslationKeys::RECORD_NOWPLAYING, [$player->getLanguage()->translate($item->getRecordType()->getTranslatableName())]);
$this->insertRecord($item->pop()); $this->insertRecord($item->pop());
} }
} }

View File

@ -2586,6 +2586,12 @@ final class KnownTranslationFactory{
return new Translatable(KnownTranslationKeys::QUERY_WARNING2, []); return new Translatable(KnownTranslationKeys::QUERY_WARNING2, []);
} }
public static function record_nowPlaying(Translatable|string $param0) : Translatable{
return new Translatable(KnownTranslationKeys::RECORD_NOWPLAYING, [
0 => $param0,
]);
}
public static function server_port() : Translatable{ public static function server_port() : Translatable{
return new Translatable(KnownTranslationKeys::SERVER_PORT, []); return new Translatable(KnownTranslationKeys::SERVER_PORT, []);
} }

View File

@ -549,6 +549,7 @@ final class KnownTranslationKeys{
public const QUERY_DISABLE = "query_disable"; public const QUERY_DISABLE = "query_disable";
public const QUERY_WARNING1 = "query_warning1"; public const QUERY_WARNING1 = "query_warning1";
public const QUERY_WARNING2 = "query_warning2"; public const QUERY_WARNING2 = "query_warning2";
public const RECORD_NOWPLAYING = "record.nowPlaying";
public const SERVER_PORT = "server_port"; public const SERVER_PORT = "server_port";
public const SERVER_PORT_V4 = "server_port_v4"; public const SERVER_PORT_V4 = "server_port_v4";
public const SERVER_PORT_V6 = "server_port_v6"; public const SERVER_PORT_V6 = "server_port_v6";

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\timings; namespace pocketmine\timings;
use pocketmine\Server;
use function round; use function round;
use function spl_object_id; use function spl_object_id;
@ -54,8 +55,8 @@ 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->curTickTotal > 50000000){ if($record->curTickTotal > Server::TARGET_NANOSECONDS_PER_TICK){
$record->violations += (int) round($record->curTickTotal / 50000000); $record->violations += (int) round($record->curTickTotal / Server::TARGET_NANOSECONDS_PER_TICK);
} }
$record->curTickTotal = 0; $record->curTickTotal = 0;
$record->curCount = 0; $record->curCount = 0;

View File

@ -55,12 +55,14 @@ use function strval;
use function trim; use function trim;
class WorldManager{ class WorldManager{
public const TICKS_PER_AUTOSAVE = 300 * Server::TARGET_TICKS_PER_SECOND;
/** @var World[] */ /** @var World[] */
private array $worlds = []; private array $worlds = [];
private ?World $defaultWorld = null; private ?World $defaultWorld = null;
private bool $autoSave = true; private bool $autoSave = true;
private int $autoSaveTicks = 6000; private int $autoSaveTicks = self::TICKS_PER_AUTOSAVE;
private int $autoSaveTicker = 0; private int $autoSaveTicker = 0;
public function __construct( public function __construct(
@ -348,8 +350,8 @@ class WorldManager{
$world->doTick($currentTick); $world->doTick($currentTick);
$tickMs = (microtime(true) - $worldTime) * 1000; $tickMs = (microtime(true) - $worldTime) * 1000;
$world->tickRateTime = $tickMs; $world->tickRateTime = $tickMs;
if($tickMs >= 50){ if($tickMs >= Server::TARGET_SECONDS_PER_TICK){
$world->getLogger()->debug(sprintf("Tick took too long: %gms (%g ticks)", $tickMs, round($tickMs / 50, 2))); $world->getLogger()->debug(sprintf("Tick took too long: %gms (%g ticks)", $tickMs, round($tickMs / Server::TARGET_SECONDS_PER_TICK, 2)));
} }
} }