diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 1142b3172..c0de17903 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -345,7 +345,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade } public function isBanned(){ - return $this->server->getNameBans()->isBanned(strtolower($this->getName())); + return $this->server->getNameBans()->isBanned($this->iusername); } public function setBanned($value){ @@ -358,14 +358,14 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade } public function isWhitelisted(){ - return $this->server->isWhitelisted(strtolower($this->getName())); + return $this->server->isWhitelisted($this->iusername); } public function setWhitelisted($value){ if($value === true){ - $this->server->addWhitelist(strtolower($this->getName())); + $this->server->addWhitelist($this->iusername); }else{ - $this->server->removeWhitelist(strtolower($this->getName())); + $this->server->removeWhitelist($this->iusername); } } @@ -1731,18 +1731,18 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade protected function processLogin(){ - if(!$this->server->isWhitelisted(strtolower($this->getName()))){ + if(!$this->server->isWhitelisted($this->iusername)){ $this->close($this->getLeaveMessage(), "Server is white-listed"); return; - }elseif($this->server->getNameBans()->isBanned(strtolower($this->getName())) or $this->server->getIPBans()->isBanned($this->getAddress())){ + }elseif($this->server->getNameBans()->isBanned($this->iusername) or $this->server->getIPBans()->isBanned($this->getAddress())){ $this->close($this->getLeaveMessage(), "You are banned"); return; } foreach($this->server->getOnlinePlayers() as $p){ - if($p !== $this and strtolower($p->getName()) === strtolower($this->getName())){ + if($p !== $this and $p->iusername === $this->iusername){ if($p->kick("logged in from another location") === false){ $this->close($this->getLeaveMessage(), "Logged in from another location"); diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 6c3724637..5699e1722 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -128,7 +128,6 @@ namespace pocketmine { set_time_limit(0); //Who set it to 30 seconds?!?! - gc_enable(); error_reporting(-1); ini_set("allow_url_fopen", 1); ini_set("display_errors", 1); diff --git a/src/pocketmine/block/Lava.php b/src/pocketmine/block/Lava.php index d90f34ad3..d0d07042b 100644 --- a/src/pocketmine/block/Lava.php +++ b/src/pocketmine/block/Lava.php @@ -64,7 +64,7 @@ class Lava extends Liquid{ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ $ret = $this->getLevel()->setBlock($this, $this, true, false); - $this->getLevel()->scheduleUpdate($this, $this->tickRate()); + $this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate()); return $ret; } diff --git a/src/pocketmine/block/Liquid.php b/src/pocketmine/block/Liquid.php index 8c0f333b8..79e6730cd 100644 --- a/src/pocketmine/block/Liquid.php +++ b/src/pocketmine/block/Liquid.php @@ -189,7 +189,7 @@ abstract class Liquid extends Transparent{ public function onUpdate($type){ if($type === Level::BLOCK_UPDATE_NORMAL){ $this->checkForHarden(); - $this->getLevel()->scheduleUpdate($this, $this->tickRate()); + $this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate()); }elseif($type === Level::BLOCK_UPDATE_SCHEDULED){ if($this->temporalVector === null){ $this->temporalVector = new Vector3(0, 0, 0); @@ -242,7 +242,7 @@ abstract class Liquid extends Transparent{ $this->getLevel()->setBlock($this, new Air(), true); }else{ $this->getLevel()->setBlock($this, Block::get($this->id, $decay), true); - $this->getLevel()->scheduleUpdate($this, $this->tickRate()); + $this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate()); } }elseif($flag){ //$this->getLevel()->scheduleUpdate($this, $this->tickRate()); @@ -262,10 +262,10 @@ abstract class Liquid extends Transparent{ if($decay >= 8){ $this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay), true); - $this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate()); + $this->getLevel()->scheduleDelayedBlockUpdate($bottomBlock, $this->tickRate()); }else{ $this->getLevel()->setBlock($bottomBlock, Block::get($this->id, $decay + 8), true); - $this->getLevel()->scheduleUpdate($bottomBlock, $this->tickRate()); + $this->getLevel()->scheduleDelayedBlockUpdate($bottomBlock, $this->tickRate()); } }elseif($decay >= 0 and ($decay === 0 or !$bottomBlock->canBeFlowedInto())){ $flags = $this->getOptimalFlowDirections(); @@ -310,7 +310,7 @@ abstract class Liquid extends Transparent{ } $this->getLevel()->setBlock($block, Block::get($this->getId(), $newFlowDecay), true); - $this->getLevel()->scheduleUpdate($block, $this->tickRate()); + $this->getLevel()->scheduleDelayedBlockUpdate($block, $this->tickRate()); } } diff --git a/src/pocketmine/block/Water.php b/src/pocketmine/block/Water.php index 4e7da94a5..d71e4791a 100644 --- a/src/pocketmine/block/Water.php +++ b/src/pocketmine/block/Water.php @@ -48,7 +48,7 @@ class Water extends Liquid{ public function place(Item $item, Block $block, Block $target, $face, $fx, $fy, $fz, Player $player = null){ $ret = $this->getLevel()->setBlock($this, $this, true, false); - $this->getLevel()->scheduleUpdate($this, $this->tickRate()); + $this->getLevel()->scheduleDelayedBlockUpdate($this, $this->tickRate()); return $ret; } diff --git a/src/pocketmine/event/Event.php b/src/pocketmine/event/Event.php index b9fe376db..2b54763d0 100644 --- a/src/pocketmine/event/Event.php +++ b/src/pocketmine/event/Event.php @@ -30,8 +30,6 @@ abstract class Event{ * Any callable event must declare the static variable * * public static $handlerList = null; - * public static $eventPool = []; - * public static $nextEvent = 0; * * Not doing so will deny the proper event initialization */ @@ -85,4 +83,4 @@ abstract class Event{ return static::$handlerList; } -} \ No newline at end of file +} diff --git a/src/pocketmine/level/Explosion.php b/src/pocketmine/level/Explosion.php index 5ece506e2..0fe5b3e6b 100644 --- a/src/pocketmine/level/Explosion.php +++ b/src/pocketmine/level/Explosion.php @@ -201,7 +201,7 @@ class Explosion{ $pos = new Vector3($block->x, $block->y, $block->z); - for($side = 0; $side < 5; $side++){ + for($side = 0; $side <= 5; $side++){ $sideBlock = $pos->getSide($side); if(!isset($this->affectedBlocks[$index = Level::blockHash($sideBlock->x, $sideBlock->y, $sideBlock->z)]) and !isset($updateBlocks[$index])){ $this->level->getServer()->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->level->getBlock($sideBlock))); diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 25acf601d..8e480d712 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -190,8 +190,11 @@ class Level implements ChunkManager, Metadatable{ private $changedBlocks = []; /** @var ReversePriorityQueue */ - private $updateQueue; - private $updateQueueIndex = []; + private $scheduledBlockUpdateQueue; + private $scheduledBlockUpdateQueueIndex = []; + + /** @var \SplQueue */ + private $neighbourBlockUpdateQueue = []; /** @var Player[][] */ private $chunkSendQueue = []; @@ -333,8 +336,11 @@ class Level implements ChunkManager, Metadatable{ $this->generator = Generator::getGenerator($this->provider->getGenerator()); $this->folderName = $name; - $this->updateQueue = new ReversePriorityQueue(); - $this->updateQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + $this->scheduledBlockUpdateQueue = new ReversePriorityQueue(); + $this->scheduledBlockUpdateQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + + $this->neighbourBlockUpdateQueue = new \SplQueue(); + $this->time = (int) $this->provider->getTime(); $this->chunkTickRadius = min($this->server->getViewDistance(), max(1, (int) $this->server->getProperty("chunk-ticking.tick-radius", 4))); @@ -662,11 +668,24 @@ class Level implements ChunkManager, Metadatable{ //Do block updates $this->timings->doTickPending->startTiming(); - while($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick){ - $block = $this->getBlock($this->updateQueue->extract()["data"]); - unset($this->updateQueueIndex[Level::blockHash($block->x, $block->y, $block->z)]); + + //Delayed updates + while($this->scheduledBlockUpdateQueue->count() > 0 and $this->scheduledBlockUpdateQueue->current()["priority"] <= $currentTick){ + $block = $this->getBlock($this->scheduledBlockUpdateQueue->extract()["data"]); + unset($this->scheduledBlockUpdateQueueIndex[Level::blockHash($block->x, $block->y, $block->z)]); $block->onUpdate(self::BLOCK_UPDATE_SCHEDULED); } + + //Normal updates + while($this->neighbourBlockUpdateQueue->count() > 0){ + $index = $this->neighbourBlockUpdateQueue->dequeue(); + Level::getBlockXYZ($index, $x, $y, $z); + $this->server->getPluginManager()->callEvent($ev = new BlockUpdateEvent($this->getBlock($this->temporalVector->setComponents($x, $y, $z)))); + if(!$ev->isCancelled()){ + $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); + } + } + $this->timings->doTickPending->stopTiming(); $this->timings->entityTick->startTiming(); @@ -1017,15 +1036,45 @@ class Level implements ChunkManager, Metadatable{ } /** + * @deprecated This method will be removed in the future due to misleading/ambiguous name. Use {@link Level#scheduleDelayedBlockUpdate} instead. + * * @param Vector3 $pos * @param int $delay */ public function scheduleUpdate(Vector3 $pos, int $delay){ - if(isset($this->updateQueueIndex[$index = Level::blockHash($pos->x, $pos->y, $pos->z)]) and $this->updateQueueIndex[$index] <= $delay){ + $this->scheduleDelayedBlockUpdate($pos, $delay); + } + + /** + * Schedules a block update to be executed after the specified number of ticks. + * Blocks will be updated with the scheduled update type. + * + * @param Vector3 $pos + * @param int $delay + */ + public function scheduleDelayedBlockUpdate(Vector3 $pos, int $delay){ + if(isset($this->scheduledBlockUpdateQueueIndex[$index = Level::blockHash($pos->x, $pos->y, $pos->z)]) and $this->scheduledBlockUpdateQueueIndex[$index] <= $delay){ return; } - $this->updateQueueIndex[$index] = $delay; - $this->updateQueue->insert(new Vector3((int) $pos->x, (int) $pos->y, (int) $pos->z), (int) $delay + $this->server->getTick()); + $this->scheduledBlockUpdateQueueIndex[$index] = $delay; + $this->scheduledBlockUpdateQueue->insert(new Vector3((int) $pos->x, (int) $pos->y, (int) $pos->z), (int) $delay + $this->server->getTick()); + } + + /** + * Schedules the blocks around the specified position to be updated at the end of this tick. + * Blocks will be updated with the normal update type. + * + * @param Vector3 $pos + */ + public function scheduleNeighbourBlockUpdates(Vector3 $pos){ + $pos = $pos->floor(); + + $this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x + 1, $pos->y, $pos->z)); + $this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x - 1, $pos->y, $pos->z)); + $this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y + 1, $pos->z)); + $this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y - 1, $pos->z)); + $this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y, $pos->z + 1)); + $this->neighbourBlockUpdateQueue->enqueue(Level::blockHash($pos->x, $pos->y, $pos->z - 1)); } /** @@ -1439,9 +1488,8 @@ class Level implements ChunkManager, Metadatable{ $entity->scheduleUpdate(); } $ev->getBlock()->onUpdate(self::BLOCK_UPDATE_NORMAL); + $this->scheduleNeighbourBlockUpdates($pos); } - - $this->updateAround($pos); } $this->timings->setBlock->stopTiming(); diff --git a/src/pocketmine/utils/Config.php b/src/pocketmine/utils/Config.php index 24547d989..9b9a2211f 100644 --- a/src/pocketmine/utils/Config.php +++ b/src/pocketmine/utils/Config.php @@ -50,6 +50,8 @@ class Config{ private $correct = false; /** @var int */ private $type = Config::DETECT; + /** @var int */ + private $jsonOptions = JSON_PRETTY_PRINT | JSON_BIGINT_AS_STRING; public static $formats = [ "properties" => Config::PROPERTIES, @@ -187,7 +189,7 @@ class Config{ $content = $this->writeProperties(); break; case Config::JSON: - $content = json_encode($this->config, JSON_PRETTY_PRINT | JSON_BIGINT_AS_STRING); + $content = json_encode($this->config, $this->jsonOptions); break; case Config::YAML: $content = yaml_emit($this->config, YAML_UTF8_ENCODING); @@ -219,6 +221,68 @@ class Config{ } } + /** + * Sets the options for the JSON encoding when saving + * + * @param int $options + * @return Config $this + * @throws \RuntimeException if the Config is not in JSON + * @see json_encode + */ + public function setJsonOptions(int $options) : Config{ + if($this->type !== Config::JSON){ + throw new \RuntimeException("Attempt to set JSON options for non-JSON config"); + } + $this->jsonOptions = $options; + return $this; + } + + /** + * Enables the given option in addition to the currently set JSON options + * + * @param int $option + * @return Config $this + * @throws \RuntimeException if the Config is not in JSON + * @see json_encode + */ + public function enableJsonOption(int $option) : Config{ + if($this->type !== Config::JSON){ + throw new \RuntimeException("Attempt to enable JSON option for non-JSON config"); + } + $this->jsonOptions |= $option; + return $this; + } + + /** + * Disables the given option for the JSON encoding when saving + * + * @param int $option + * @return Config $this + * @throws \RuntimeException if the Config is not in JSON + * @see json_encode + */ + public function disableJsonOption(int $option) : Config{ + if($this->type !== Config::JSON){ + throw new \RuntimeException("Attempt to disable JSON option for non-JSON config"); + } + $this->jsonOptions &= ~$option; + return $this; + } + + /** + * Returns the options for the JSON encoding when saving + * + * @return int + * @throws \RuntimeException if the Config is not in JSON + * @see json_encode + */ + public function getJsonOptions() : int{ + if($this->type !== Config::JSON){ + throw new \RuntimeException("Attempt to get JSON options for non-JSON config"); + } + return $this->jsonOptions; + } + /** * @param $k *