From 5e2a21fc267ee28b615e420ba5c60a547651329d Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sun, 12 Apr 2015 14:13:36 +0200 Subject: [PATCH] Added level-settings.auto-tick-rate property, added Level tick rate --- src/pocketmine/Server.php | 61 ++++++++++--------------- src/pocketmine/level/Level.php | 54 +++++++++++++--------- src/pocketmine/resources/pocketmine.yml | 2 + 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 557ad0709..d2748a2f7 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -196,6 +196,8 @@ class Server{ private $networkCompressionAsync = true; private $networkCompressionLevel = 7; + private $autoTickRate = true; + /** @var BaseLang */ private $baseLang; @@ -224,8 +226,6 @@ class Server{ /** @var Level[] */ private $levels = []; - private $offendingLevels = []; - private $offendingTicks = []; /** @var Level */ private $levelDefault = null; @@ -1530,6 +1530,8 @@ class Server{ $this->networkCompressionLevel = $this->getProperty("network.compression-level", 7); $this->networkCompressionAsync = $this->getProperty("network.async-compression", true); + $this->autoTickRate = $this->getProperty("level-settings.auto-tick-rate", true); + $this->scheduler = new ServerScheduler(); if($this->getConfigBoolean("enable-rcon", false) === true){ @@ -2154,27 +2156,34 @@ class Server{ } private function checkTickUpdates($currentTick){ - - $tickLimit = 50 / count($this->levels); - $levelTimes = []; - - $startTime = microtime(true); //Do level ticks foreach($this->getLevels() as $level){ - if(isset($this->offendingLevels[$level->getId()]) and $this->offendingTicks[$level->getId()]-- > 0){ + if($level->getTickRate() > 1 and --$level->tickRateCounter > 0){ continue; } try{ $levelTime = microtime(true); $level->doTick($currentTick); - $levelMs = (microtime(true) - $levelTime) * 1000; - $levelTimes[$level->getId()] = $levelMs; - if(isset($this->offendingLevels[$level->getId()])){ - if($levelMs < $tickLimit and --$this->offendingLevels[$level->getId()] <= 0){ - unset($this->offendingLevels[$level->getId()]); - unset($this->offendingTicks[$level->getId()]); - }else{ - $this->offendingTicks[$level->getId()] = $this->offendingLevels[$level->getId()]; + $tickMs = (microtime(true) - $levelTime) * 1000; + + if($this->autoTickRate){ + if($tickMs < 50 and $level->getTickRate() > 1){ + if($level->getTickRate() > 1){ + $level->setTickRate($r = $level->getTickRate() - 1); + if($r > 1){ + $level->tickRateCounter = $level->getTickRate(); + } + $this->getLogger()->debug("Raising level \"".$level->getName()."\" tick rate to ".$level->getTickRate()." ticks"); + } + }elseif($tickMs >= 50){ + if($level->getTickRate() === 1){ + $level->setTickRate(max(2, min(10, floor($tickMs / 50)))); + $this->getLogger()->debug("Set level \"".$level->getName()."\" tick rate to ".$level->getTickRate()." ticks"); + }elseif(($tickMs / $level->getTickRate()) >= 50 and $level->getTickRate() < 10){ //Limit? + $level->setTickRate($level->getTickRate() + 1); + $this->getLogger()->debug("Set level \"".$level->getName()."\" tick rate to ".$level->getTickRate()." ticks"); + } + $level->tickRateCounter = $level->getTickRate(); } } }catch(\Exception $e){ @@ -2184,26 +2193,6 @@ class Server{ } } } - - $totalTime = (microtime(true) - $startTime) * 1000; - - if($totalTime > 50){ - arsort($levelTimes); - foreach($levelTimes as $levelId => $t){ - $totalTime -= $t; - if(!isset($this->offendingLevels[$levelId])){ - $this->offendingLevels[$levelId] = max(1, min(10, floor($t / 50))); - }elseif($this->offendingLevels[$levelId] < 10){ //Limit? - ++$this->offendingLevels[$levelId]; - } - $this->offendingTicks[$levelId] = $this->offendingLevels[$levelId]; - - if($totalTime <= 50){ - break; - } - } - } - } public function doAutoSave(){ diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 769a169ba..2bced9e27 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -125,37 +125,37 @@ class Level implements ChunkManager, Metadatable{ const TIME_FULL = 24000; /** @var Tile[] */ - protected $tiles = []; + private $tiles = []; /** @var Player[] */ - protected $players = []; + private $players = []; /** @var Entity[] */ - protected $entities = []; + private $entities = []; /** @var Entity[] */ public $updateEntities = []; /** @var Tile[] */ public $updateTiles = []; - protected $blockCache = []; + private $blockCache = []; /** @var Server */ - protected $server; + private $server; /** @var int */ - protected $levelId; + private $levelId; /** @var LevelProvider */ - protected $provider; + private $provider; /** @var Player[][] */ - protected $usedChunks = []; + private $usedChunks = []; /** @var FullChunk[]|Chunk[] */ - protected $unloadQueue; + private $unloadQueue; - protected $time; + private $time; public $stopTime; private $folderName; @@ -164,7 +164,7 @@ class Level implements ChunkManager, Metadatable{ private $chunks = []; /** @var Vector3[][] */ - protected $changedBlocks = []; + private $changedBlocks = []; /** @var ReversePriorityQueue */ private $updateQueue; @@ -196,11 +196,11 @@ class Level implements ChunkManager, Metadatable{ /** @var \SplFixedArray */ private $blockStates; - protected $chunkTickRadius; - protected $chunkTickList = []; - protected $chunksPerTick; - protected $clearChunksOnTick; - protected $randomTickBlocks = [ + private $chunkTickRadius; + private $chunkTickList = []; + private $chunksPerTick; + private $clearChunksOnTick; + private $randomTickBlocks = [ Block::GRASS => Grass::class, Block::SAPLING => Sapling::class, Block::LEAVES => Leaves::class, @@ -227,10 +227,13 @@ class Level implements ChunkManager, Metadatable{ /** @var LevelTimings */ public $timings; + private $tickRate; + public $tickRateCounter = 0; + /** @var Generator */ - protected $generator; + private $generator; /** @var Generator */ - protected $generatorInstance; + private $generatorInstance; /** * Returns the chunk unique hash/key @@ -317,6 +320,15 @@ class Level implements ChunkManager, Metadatable{ $this->timings = new LevelTimings($this); $this->temporalPosition = new Position(0, 0, 0, $this); $this->temporalVector = new Vector3(0, 0, 0); + $this->tickRate = 1; + } + + public function getTickRate(){ + return $this->tickRate; + } + + public function setTickRate($tickRate){ + $this->tickRate = (int) $tickRate; } public function initLevel(){ @@ -1935,7 +1947,7 @@ class Level implements ChunkManager, Metadatable{ $this->chunkSendQueue[$index][spl_object_hash($player)] = $player; } - protected function processChunkRequest(){ + private function processChunkRequest(){ if(count($this->chunkSendQueue) > 0){ $this->timings->syncChunkSendTimer->startTiming(); @@ -2088,7 +2100,7 @@ class Level implements ChunkManager, Metadatable{ return true; } - protected function queueUnloadChunk($x, $z){ + private function queueUnloadChunk($x, $z){ $this->unloadQueue[$index = Level::chunkHash($x, $z)] = microtime(true); unset($this->chunkTickList[$index]); } @@ -2384,7 +2396,7 @@ class Level implements ChunkManager, Metadatable{ $this->timings->doChunkGC->stopTiming(); } - protected function unloadChunks(){ + private function unloadChunks(){ if(count($this->unloadQueue) > 0){ $X = null; $Z = null; diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 2ba7e66ca..b7a45f81b 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -44,6 +44,8 @@ level-settings: #If true, converts from a format that is not the default to the default format on load #NOTE: This is currently not implemented convert-format: false + #Automatically change levels tick rate to maintain 20 ticks per second + auto-tick-rate: true chunk-sending: #Amount of chunks sent to players per tick