Firehose auto-tick-rate anti-feature, closes #2665

This commit is contained in:
Dylan K. Taylor 2019-03-03 13:24:53 +00:00
parent d9880de2ef
commit 6bd43a8215
4 changed files with 4 additions and 65 deletions

View File

@ -108,12 +108,11 @@ class StatusCommand extends VanillaCommand{
foreach($server->getLevelManager()->getLevels() as $level){ foreach($server->getLevelManager()->getLevels() as $level){
$levelName = $level->getFolderName() !== $level->getDisplayName() ? " (" . $level->getDisplayName() . ")" : ""; $levelName = $level->getFolderName() !== $level->getDisplayName() ? " (" . $level->getDisplayName() . ")" : "";
$timeColor = ($level->getTickRate() > 1 or $level->getTickRateTime() > 40) ? TextFormat::RED : TextFormat::YELLOW; $timeColor = $level->getTickRateTime() > 40 ? TextFormat::RED : TextFormat::YELLOW;
$tickRate = $level->getTickRate() > 1 ? " (tick rate " . $level->getTickRate() . ")" : "";
$sender->sendMessage(TextFormat::GOLD . "World \"{$level->getFolderName()}\"$levelName: " . $sender->sendMessage(TextFormat::GOLD . "World \"{$level->getFolderName()}\"$levelName: " .
TextFormat::RED . number_format(count($level->getChunks())) . TextFormat::GREEN . " chunks, " . TextFormat::RED . number_format(count($level->getChunks())) . TextFormat::GREEN . " chunks, " .
TextFormat::RED . number_format(count($level->getEntities())) . TextFormat::GREEN . " entities. " . TextFormat::RED . number_format(count($level->getEntities())) . TextFormat::GREEN . " entities. " .
"Time $timeColor" . round($level->getTickRateTime(), 2) . "ms" . $tickRate "Time $timeColor" . round($level->getTickRateTime(), 2) . "ms"
); );
} }

View File

@ -1422,7 +1422,8 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
assert(abs($dx) <= 20 and abs($dy) <= 20 and abs($dz) <= 20, "Movement distance is excessive: dx=$dx, dy=$dy, dz=$dz"); assert(abs($dx) <= 20 and abs($dy) <= 20 and abs($dz) <= 20, "Movement distance is excessive: dx=$dx, dy=$dy, dz=$dz");
$list = $this->level->getCollisionBoxes($this, $this->level->getTickRate() > 1 ? $this->boundingBox->offsetCopy($dx, $dy, $dz) : $this->boundingBox->addCoord($dx, $dy, $dz), false); //TODO: bad hack here will cause unexpected behaviour under heavy lag
$list = $this->level->getCollisionBoxes($this, $this->level->getTickRateTime() > 50 ? $this->boundingBox->offsetCopy($dx, $dy, $dz) : $this->boundingBox->addCoord($dx, $dy, $dz), false);
foreach($list as $bb){ foreach($list as $bb){
$dy = $bb->calculateYOffset($this->boundingBox, $dy); $dy = $bb->calculateYOffset($this->boundingBox, $dy);

View File

@ -256,12 +256,8 @@ class Level implements ChunkManager, Metadatable{
/** @var LevelTimings */ /** @var LevelTimings */
public $timings; public $timings;
/** @var int */
private $tickRate;
/** @var int */ /** @var int */
public $tickRateTime = 0; public $tickRateTime = 0;
/** @var int */
public $tickRateCounter = 0;
/** @var bool */ /** @var bool */
private $doingTick = false; private $doingTick = false;
@ -401,21 +397,12 @@ class Level implements ChunkManager, Metadatable{
$this->timings = new LevelTimings($this); $this->timings = new LevelTimings($this);
$this->temporalPosition = new Position(0, 0, 0, $this); $this->temporalPosition = new Position(0, 0, 0, $this);
$this->temporalVector = new Vector3(0, 0, 0); $this->temporalVector = new Vector3(0, 0, 0);
$this->tickRate = 1;
}
public function getTickRate() : int{
return $this->tickRate;
} }
public function getTickRateTime() : float{ public function getTickRateTime() : float{
return $this->tickRateTime; return $this->tickRateTime;
} }
public function setTickRate(int $tickRate){
$this->tickRate = $tickRate;
}
public function registerGeneratorToWorker(int $worker) : void{ public function registerGeneratorToWorker(int $worker) : void{
$this->generatorRegisteredWorkers[$worker] = true; $this->generatorRegisteredWorkers[$worker] = true;
$this->server->getAsyncPool()->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getLevelData()->getGeneratorOptions()), $worker); $this->server->getAsyncPool()->submitTaskToWorker(new GeneratorRegisterTask($this, $this->generator, $this->provider->getLevelData()->getGeneratorOptions()), $worker);

View File

@ -40,11 +40,8 @@ use function array_shift;
use function asort; use function asort;
use function assert; use function assert;
use function count; use function count;
use function floor;
use function implode; use function implode;
use function max;
use function microtime; use function microtime;
use function min;
use function random_int; use function random_int;
use function round; use function round;
use function sprintf; use function sprintf;
@ -61,31 +58,17 @@ class LevelManager{
/** @var Server */ /** @var Server */
private $server; private $server;
/** @var bool */
private $autoTickRate = true;
/** @var int */
private $autoTickRateLimit = 20;
/** @var bool */
private $alwaysTickPlayers = false;
/** @var int */
private $baseTickRate = 1;
/** @var bool */ /** @var bool */
private $autoSave = true; private $autoSave = true;
/** @var int */ /** @var int */
private $autoSaveTicks = 6000; private $autoSaveTicks = 6000;
/** @var int */ /** @var int */
private $autoSaveTicker = 0; private $autoSaveTicker = 0;
public function __construct(Server $server){ public function __construct(Server $server){
$this->server = $server; $this->server = $server;
$this->autoTickRate = (bool) $this->server->getProperty("level-settings.auto-tick-rate", $this->autoTickRate);
$this->autoTickRateLimit = (int) $this->server->getProperty("level-settings.auto-tick-rate-limit", $this->autoTickRateLimit);
$this->alwaysTickPlayers = (bool) $this->server->getProperty("level-settings.always-tick-players", $this->alwaysTickPlayers);
$this->baseTickRate = (int) $this->server->getProperty("level-settings.base-tick-rate", $this->baseTickRate);
$this->autoSave = $this->server->getConfigBool("auto-save", $this->autoSave); $this->autoSave = $this->server->getConfigBool("auto-save", $this->autoSave);
$this->autoSaveTicks = (int) $this->server->getProperty("ticks-per.autosave", 6000); $this->autoSaveTicks = (int) $this->server->getProperty("ticks-per.autosave", 6000);
} }
@ -239,7 +222,6 @@ class LevelManager{
} }
$this->levels[$level->getId()] = $level; $this->levels[$level->getId()] = $level;
$level->setTickRate($this->baseTickRate);
$level->setAutoSave($this->autoSave); $level->setAutoSave($this->autoSave);
(new LevelLoadEvent($level))->call(); (new LevelLoadEvent($level))->call();
@ -278,7 +260,6 @@ class LevelManager{
$level = new Level($this->server, $name, new $providerClass($path)); $level = new Level($this->server, $name, new $providerClass($path));
$this->levels[$level->getId()] = $level; $this->levels[$level->getId()] = $level;
$level->setTickRate($this->baseTickRate);
$level->setAutoSave($this->autoSave); $level->setAutoSave($this->autoSave);
(new LevelInitEvent($level))->call(); (new LevelInitEvent($level))->call();
@ -360,40 +341,11 @@ class LevelManager{
// Level unloaded during the tick of a level earlier in this loop, perhaps by plugin // Level unloaded during the tick of a level earlier in this loop, perhaps by plugin
continue; continue;
} }
if($level->getTickRate() > $this->baseTickRate and --$level->tickRateCounter > 0){
if($this->alwaysTickPlayers){
foreach($level->getPlayers() as $p){
if($p->spawned){
$p->onUpdate($currentTick);
}
}
}
continue;
}
$levelTime = microtime(true); $levelTime = microtime(true);
$level->doTick($currentTick); $level->doTick($currentTick);
$tickMs = (microtime(true) - $levelTime) * 1000; $tickMs = (microtime(true) - $levelTime) * 1000;
$level->tickRateTime = $tickMs; $level->tickRateTime = $tickMs;
if($this->autoTickRate){
if($tickMs < 50 and $level->getTickRate() > $this->baseTickRate){
$level->setTickRate($r = $level->getTickRate() - 1);
if($r > $this->baseTickRate){
$level->tickRateCounter = $level->getTickRate();
}
$this->server->getLogger()->debug("Raising world \"{$level->getDisplayName()}\" tick rate to {$level->getTickRate()} ticks");
}elseif($tickMs >= 50){
if($level->getTickRate() === $this->baseTickRate){
$level->setTickRate(max($this->baseTickRate + 1, min($this->autoTickRateLimit, (int) floor($tickMs / 50))));
$this->server->getLogger()->debug(sprintf("World \"%s\" took %gms, setting tick rate to %d ticks", $level->getDisplayName(), (int) round($tickMs, 2), $level->getTickRate()));
}elseif(($tickMs / $level->getTickRate()) >= 50 and $level->getTickRate() < $this->autoTickRateLimit){
$level->setTickRate($level->getTickRate() + 1);
$this->server->getLogger()->debug(sprintf("World \"%s\" took %gms, setting tick rate to %d ticks", $level->getDisplayName(), (int) round($tickMs, 2), $level->getTickRate()));
}
$level->tickRateCounter = $level->getTickRate();
}
}
} }
if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){ if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){