getXZ() публичный статический Метод

public static getXZ ( $hash, &$x, &$z )
 public function onCompletion(Server $server)
 {
     $chunks = $this->getResult();
     $plugin = $server->getPluginManager()->getPlugin("MineReset");
     if ($plugin instanceof MineReset and $plugin->isEnabled()) {
         $level = $server->getLevel($this->levelId);
         if ($level != null) {
             foreach ($chunks as $hash => $chunk) {
                 Level::getXZ($hash, $x, $z);
                 $level->setChunk($x, $z, $chunk);
             }
         }
         $plugin->getRegionBlocker()->freeZone($this->regionId, $this->levelId);
     }
 }
Пример #2
0
 public function process()
 {
     if (count($this->requestQueue) > 0) {
         $count = 0;
         foreach ($this->requestQueue as $levelID => $chunks) {
             if ($count >= $this->maxCount) {
                 break;
             }
             if (count($chunks) === 0) {
                 unset($this->requestQueue[$levelID]);
             } else {
                 Level::getXZ($key = key($chunks), $chunkX, $chunkZ);
                 unset($this->requestQueue[$levelID][$key]);
                 $this->generateChunk($levelID, $chunkX, $chunkZ);
                 ++$count;
             }
         }
     }
 }
Пример #3
0
 /**
  * Changes the biome of a plot
  *
  * @api
  * @param Plot $plot
  * @param Biome $biome
  * @return bool
  */
 public function setPlotBiome(Plot $plot, Biome $biome)
 {
     $plotLevel = $this->getLevelSettings($plot->levelName);
     if ($plotLevel === null) {
         return false;
     }
     $level = $this->getServer()->getLevelByName($plot->levelName);
     $pos = $this->getPlotPosition($plot);
     $plotSize = $plotLevel->plotSize;
     $xMax = $pos->x + $plotSize;
     $zMax = $pos->z + $plotSize;
     $chunkIndexes = [];
     for ($x = $pos->x; $x < $xMax; $x++) {
         for ($z = $pos->z; $z < $zMax; $z++) {
             $index = Level::chunkHash($x >> 4, $z >> 4);
             if (!in_array($index, $chunkIndexes)) {
                 $chunkIndexes[] = $index;
             }
             $color = $biome->getColor();
             $R = $color >> 16;
             $G = $color >> 8 & 0xff;
             $B = $color & 0xff;
             $level->setBiomeColor($x, $z, $R, $G, $B);
         }
     }
     foreach ($chunkIndexes as $index) {
         Level::getXZ($index, $X, $Z);
         $chunk = $level->getChunk($X, $Z);
         foreach ($level->getChunkPlayers($X, $Z) as $player) {
             $player->onChunkChanged($chunk);
         }
     }
     $plot->biome = $biome->getName();
     $this->dataProvider->savePlot($plot);
     return true;
 }
Пример #4
0
 /**
  * @param GenerationThread $thread
  * @param \Logger          $logger
  * @param \ClassLoader     $loader
  */
 public function __construct(GenerationThread $thread, \Logger $logger, \ClassLoader $loader)
 {
     $this->thread = $thread;
     $this->logger = $logger;
     $this->loader = $loader;
     $chunkX = $chunkZ = null;
     while ($this->shutdown !== true) {
         try {
             if (count($this->requestQueue) > 0) {
                 foreach ($this->requestQueue as $levelID => $chunks) {
                     if (count($chunks) === 0) {
                         unset($this->requestQueue[$levelID]);
                     } else {
                         Level::getXZ($key = key($chunks), $chunkX, $chunkZ);
                         unset($this->requestQueue[$levelID][$key]);
                         $this->generateChunk($levelID, $chunkX, $chunkZ);
                     }
                 }
             } else {
                 $this->readPacket();
             }
         } catch (\Exception $e) {
             $this->logger->warning("[Generator Thread] Exception: " . $e->getMessage() . " on file \"" . $e->getFile() . "\" line " . $e->getLine());
         }
     }
 }
Пример #5
0
 private function unloadChunks()
 {
     if (count($this->unloadQueue) > 0) {
         $X = null;
         $Z = null;
         foreach ($this->unloadQueue as $index => $time) {
             Level::getXZ($index, $X, $Z);
             //If the chunk can't be unloaded, it stays on the queue
             if ($this->unloadChunk($X, $Z, true)) {
                 unset($this->unloadQueue[$index]);
             }
         }
     }
 }
Пример #6
0
 /**
  * Generates a new level if it does not exists
  *
  * @param string $name
  * @param int    $seed
  * @param string $generator Class name that extends pocketmine\level\generator\Generator
  * @param array  $options
  *
  * @return bool
  */
 public function generateLevel($name, $seed = null, $generator = null, $options = [])
 {
     if (trim($name) === "" or $this->isLevelGenerated($name)) {
         return false;
     }
     $seed = $seed === null ? Binary::readInt(@Utils::getRandomBytes(4, false)) : (int) $seed;
     if ($generator !== null and class_exists($generator) and is_subclass_of($generator, Generator::class)) {
         $generator = new $generator($options);
     } else {
         $options["preset"] = $this->getConfigString("generator-settings", "");
         $generator = Generator::getGenerator($this->getLevelType());
     }
     if (($provider = LevelProviderManager::getProviderByName($providerName = $this->getProperty("level-settings.default-format", "mcregion"))) === null) {
         $provider = LevelProviderManager::getProviderByName($providerName = "mcregion");
     }
     try {
         $path = $this->getDataPath() . "worlds/" . $name . "/";
         /** @var \pocketmine\level\format\LevelProvider $provider */
         $provider::generate($path, $name, $seed, $generator, $options);
         $level = new Level($this, $name, $path, $provider);
         $this->levels[$level->getId()] = $level;
         $level->initLevel();
     } catch (\Exception $e) {
         $this->logger->error("Could not generate level \"" . $name . "\": " . $e->getMessage());
         if ($this->logger instanceof MainLogger) {
             $this->logger->logException($e);
         }
         return false;
     }
     $this->getPluginManager()->callEvent(new LevelInitEvent($level));
     $this->getPluginManager()->callEvent(new LevelLoadEvent($level));
     $this->getLogger()->notice("Spawn terrain for level \"{$name}\" is being generated in the background");
     $radiusSquared = ($this->getViewDistance() + 1) / M_PI;
     $radius = ceil(sqrt($radiusSquared));
     $centerX = $level->getSpawnLocation()->getX() >> 4;
     $centerZ = $level->getSpawnLocation()->getZ() >> 4;
     $order = [];
     for ($X = -$radius; $X <= $radius; ++$X) {
         for ($Z = -$radius; $Z <= $radius; ++$Z) {
             $distance = $X ** 2 + $Z ** 2;
             if ($distance > $radiusSquared) {
                 continue;
             }
             $chunkX = $X + $centerX;
             $chunkZ = $Z + $centerZ;
             $index = Level::chunkHash($chunkX, $chunkZ);
             $order[$index] = $distance;
         }
     }
     asort($order);
     $chunkX = $chunkZ = null;
     foreach ($order as $index => $distance) {
         Level::getXZ($index, $chunkX, $chunkZ);
         $level->generateChunk($chunkX, $chunkZ);
     }
     return true;
 }
Пример #7
0
 /**
  * Generates a new level if it does not exists
  *
  * @param string $name
  * @param int    $seed
  * @param array  $options
  *
  * @return bool
  */
 public function generateLevel($name, $seed = null, $options = [])
 {
     if (trim($name) === "" or $this->isLevelGenerated($name)) {
         return false;
     }
     $seed = $seed === null ? PHP_INT_SIZE === 8 ? unpack("N", @Utils::getRandomBytes(4, false))[1] << 32 >> 32 : unpack("N", @Utils::getRandomBytes(4, false))[1] : (int) $seed;
     if (($provider = LevelProviderManager::getProviderByName($providerName = $this->getProperty("level-settings.default-format", "mcregion"))) === null) {
         $provider = LevelProviderManager::getProviderByName($providerName = "mcregion");
     }
     try {
         $path = $this->getDataPath() . "worlds/" . $name . "/";
         /** @var \pocketmine\level\format\LevelProvider $provider */
         $provider::generate($path, $name, $seed, $options);
         $level = new Level($this, $name, $path, $provider);
         $this->levels[$level->getId()] = $level;
         $level->initLevel();
     } catch (\Exception $e) {
         $this->logger->error("Could not generate level \"" . $name . "\": " . $e->getMessage());
         if ($this->logger instanceof MainLogger) {
             $this->logger->logException($e);
         }
         return false;
     }
     $this->getPluginManager()->callEvent(new LevelInitEvent($level));
     $this->getPluginManager()->callEvent(new LevelLoadEvent($level));
     $centerX = $level->getSpawnLocation()->getX() >> 4;
     $centerZ = $level->getSpawnLocation()->getZ() >> 4;
     $order = [];
     for ($X = -3; $X <= 3; ++$X) {
         for ($Z = -3; $Z <= 3; ++$Z) {
             $distance = $X ** 2 + $Z ** 2;
             $chunkX = $X + $centerX;
             $chunkZ = $Z + $centerZ;
             $index = Level::chunkHash($chunkX, $chunkZ);
             $order[$index] = $distance;
         }
     }
     asort($order);
     foreach ($order as $index => $distance) {
         Level::getXZ($index, $chunkX, $chunkZ);
         $level->generateChunk($chunkX, $chunkZ, true);
     }
     return true;
 }
Пример #8
0
 /**
  * Note for plugin developers: use kick() with the isAdmin
  * flag set to kick without the "Kicked by admin" part instead of this method.
  *
  * @param string $message Message to be broadcasted
  * @param string $reason  Reason showed in console
  * @param bool $notify
  */
 public final function close($message = "", $reason = "generic reason", $notify = true)
 {
     if ($this->connected and !$this->closed) {
         if ($notify and strlen((string) $reason) > 0) {
             $pk = new DisconnectPacket();
             $pk->message = $reason;
             $this->directDataPacket($pk);
         }
         $this->connected = false;
         if (strlen($this->getName()) > 0) {
             $this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message, true));
             if ($this->loggedIn === true and $ev->getAutoSave()) {
                 $this->save();
             }
         }
         foreach ($this->server->getOnlinePlayers() as $player) {
             if (!$player->canSee($this)) {
                 $player->showPlayer($this);
             }
         }
         $this->hiddenPlayers = [];
         foreach ($this->windowIndex as $window) {
             $this->removeWindow($window);
         }
         foreach ($this->usedChunks as $index => $d) {
             Level::getXZ($index, $chunkX, $chunkZ);
             $this->level->unregisterChunkLoader($this, $chunkX, $chunkZ);
             unset($this->usedChunks[$index]);
         }
         parent::close();
         $this->interface->close($this, $notify ? $reason : "");
         if ($this->loggedIn) {
             $this->server->removeOnlinePlayer($this);
         }
         $this->loggedIn = false;
         if (isset($ev) and $this->username != "" and $this->spawned !== false and $ev->getQuitMessage() != "") {
             $this->server->broadcastMessage($ev->getQuitMessage());
         }
         $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this);
         $this->spawned = false;
         $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logOut", [TextFormat::AQUA . $this->getName() . TextFormat::WHITE, $this->ip, $this->port, $this->getServer()->getLanguage()->translateString($reason)]));
         $this->windows = new \SplObjectStorage();
         $this->windowIndex = [];
         $this->usedChunks = [];
         $this->loadQueue = [];
         $this->hasSpawned = [];
         $this->spawnPosition = null;
         unset($this->buffer);
     }
     if ($this->perm !== null) {
         $this->perm->clearPermissions();
         $this->perm = null;
     }
     if ($this->inventory !== null) {
         $this->inventory = null;
         $this->currentTransaction = null;
     }
     $this->chunk = null;
     $this->server->removePlayer($this);
 }
Пример #9
0
 public function doChunkGarbageCollection()
 {
     $this->timings->doChunkGC->startTiming();
     $X = null;
     $Z = null;
     foreach ($this->chunks as $index => $chunk) {
         if (!isset($this->usedChunks[$index])) {
             Level::getXZ($index, $X, $Z);
             $this->unloadChunkRequest($X, $Z, true);
         }
     }
     if (count($this->unloadQueue) > 0) {
         foreach ($this->unloadQueue as $index => $time) {
             Level::getXZ($index, $X, $Z);
             if ($this->getAutoSave()) {
                 $this->provider->saveChunk($X, $Z);
             }
             //If the chunk can't be unloaded, it stays on the queue
             if ($this->unloadChunk($X, $Z, true)) {
                 unset($this->unloadQueue[$index]);
             }
         }
     }
     foreach ($this->usedChunks as $i => $c) {
         if (count($c) === 0) {
             Level::getXZ($i, $X, $Z);
             if (!$this->isSpawnChunk($X, $Z)) {
                 if ($this->getAutoSave()) {
                     $this->provider->saveChunk($X, $Z);
                 }
                 $this->unloadChunk($X, $Z, true);
             }
         }
     }
     $this->timings->doChunkGC->stopTiming();
 }
Пример #10
0
 protected function switchLevel(Level $targetLevel)
 {
     if ($this->isValid()) {
         $this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->level, $targetLevel));
         if ($ev->isCancelled()) {
             return false;
         }
         $this->level->removeEntity($this);
         if ($this->chunk !== null) {
             $this->chunk->removeEntity($this);
         }
         $this->despawnFromAll();
         if ($this instanceof Player) {
             foreach ($this->usedChunks as $index => $d) {
                 Level::getXZ($index, $X, $Z);
                 $this->unloadChunk($X, $Z);
             }
         }
     }
     $this->setLevel($targetLevel);
     $this->level->addEntity($this);
     if ($this instanceof Player) {
         $this->usedChunks = [];
         $pk = new SetTimePacket();
         $pk->time = $this->level->getTime();
         $pk->started = $this->level->stopTime == false;
         $this->dataPacket($pk->setChannel(Network::CHANNEL_WORLD_EVENTS));
     }
     $this->chunk = null;
     return true;
 }
Пример #11
0
 /**
  * Note for plugin developers: use kick() with the isAdmin
  * flag set to kick without the "Kicked by admin" part instead of this method.
  *
  * @param string $message Message to be broadcasted
  * @param string $reason Reason showed in console
  * @param bool   $notify
  */
 public final function close($message = "", $reason = "generic reason", $notify = true)
 {
     if ($this->connected and !$this->closed) {
         if ($notify and strlen((string) $reason) > 0) {
             $pk = new DisconnectPacket();
             $pk->message = $reason;
             $this->directDataPacket($pk);
         }
         //$this->setLinked();
         if ($this->fishingHook instanceof FishingHook) {
             $this->fishingHook->close();
             $this->fishingHook = null;
         }
         $this->removeEffect(Effect::HEALTH_BOOST);
         $this->connected = false;
         if (strlen($this->getName()) > 0) {
             $this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message, true));
             if ($this->loggedIn === true and $ev->getAutoSave()) {
                 $this->save();
             }
         }
         foreach ($this->server->getOnlinePlayers() as $player) {
             if (!$player->canSee($this)) {
                 $player->showPlayer($this);
             }
         }
         $this->hiddenPlayers = [];
         foreach ($this->windowIndex as $window) {
             $this->removeWindow($window);
         }
         foreach ($this->usedChunks as $index => $d) {
             Level::getXZ($index, $chunkX, $chunkZ);
             $this->level->unregisterChunkLoader($this, $chunkX, $chunkZ);
             unset($this->usedChunks[$index]);
         }
         parent::close();
         $this->interface->close($this, $notify ? $reason : "");
         if ($this->loggedIn) {
             $this->server->removeOnlinePlayer($this);
         }
         $this->loggedIn = false;
         if (isset($ev) and $this->username != "" and $this->spawned !== false and $ev->getQuitMessage() != "") {
             if ($this->server->playerMsgType === Server::PLAYER_MSG_TYPE_MESSAGE) {
                 $this->server->broadcastMessage($ev->getQuitMessage());
             } elseif ($this->server->playerMsgType === Server::PLAYER_MSG_TYPE_TIP) {
                 $this->server->broadcastTip(str_replace("@player", $this->getName(), $this->server->playerLogoutMsg));
             } elseif ($this->server->playerMsgType === Server::PLAYER_MSG_TYPE_POPUP) {
                 $this->server->broadcastPopup(str_replace("@player", $this->getName(), $this->server->playerLogoutMsg));
             }
         }
         $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this);
         $this->spawned = false;
         $this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logOut", [TextFormat::AQUA . $this->getName() . TextFormat::WHITE, $this->ip, $this->port, $this->getServer()->getLanguage()->translateString($reason)]));
         $this->windows = new \SplObjectStorage();
         $this->windowIndex = [];
         $this->usedChunks = [];
         $this->loadQueue = [];
         $this->hasSpawned = [];
         $this->spawnPosition = null;
         unset($this->buffer);
         if ($this->server->dserverConfig["enable"] and $this->server->dserverConfig["queryAutoUpdate"]) {
             $this->server->updateQuery();
         }
     }
     if ($this->perm !== null) {
         $this->perm->clearPermissions();
         $this->perm = null;
     }
     $this->inventory = null;
     $this->transactionQueue = null;
     $this->chunk = null;
     $this->server->removePlayer($this);
 }
Пример #12
0
 private function cleanupMemory(Player $player)
 {
     foreach ($player->usedChunks as $index => $c) {
         Level::getXZ($index, $chunkX, $chunkZ);
         foreach ($player->getLevel()->getChunkEntities($chunkX, $chunkZ) as $entity) {
             if ($entity !== $this) {
                 $entity->despawnFrom($player);
             }
         }
     }
 }
Пример #13
0
 protected function switchLevel(Level $targetLevel)
 {
     if ($this->isValid()) {
         $this->server->getPluginManager()->callEvent($ev = new EntityLevelChangeEvent($this, $this->getLevel(), $targetLevel));
         if ($ev->isCancelled()) {
             return false;
         }
         $this->getLevel()->removeEntity($this);
         $this->chunk->removeEntity($this);
         $this->despawnFromAll();
         if ($this instanceof Player) {
             foreach ($this->usedChunks as $index => $d) {
                 $X = null;
                 $Z = null;
                 Level::getXZ($index, $X, $Z);
                 foreach ($this->getLevel()->getChunkEntities($X, $Z) as $entity) {
                     $entity->despawnFrom($this);
                 }
             }
             $this->getLevel()->freeAllChunks($this);
         }
     }
     $this->setLevel($targetLevel, $this instanceof Player ? true : false);
     //Hard reference
     $this->getLevel()->addEntity($this);
     if ($this instanceof Player) {
         $this->usedChunks = [];
         $pk = new SetTimePacket();
         $pk->time = $this->getLevel()->getTime();
         $pk->started = $this->getLevel()->stopTime == false;
         $this->dataPacket($pk);
     }
     $this->chunk = null;
     return true;
 }
Пример #14
0
 protected function sendNextChunk()
 {
     if ($this->connected === false) {
         return;
     }
     Timings::$playerChunkSendTimer->startTiming();
     $count = 0;
     foreach ($this->loadQueue as $index => $distance) {
         if ($count >= $this->chunksPerTick) {
             break;
         }
         $X = null;
         $Z = null;
         Level::getXZ($index, $X, $Z);
         ++$count;
         $this->usedChunks[$index] = false;
         $this->level->registerChunkLoader($this, $X, $Z, false);
         if (!$this->level->populateChunk($X, $Z)) {
             if ($this->spawned and $this->teleportPosition === null) {
                 continue;
             } else {
                 break;
             }
         }
         unset($this->loadQueue[$index]);
         $chunk = new DesktopChunk($this, $X, $Z);
         $this->bigBrother_sendChunk($X, $Z, $chunk->getData());
         $chunk = null;
     }
     if ($this->chunkLoadCount >= 4 and $this->spawned === false and $this->teleportPosition === null) {
         $this->doFirstSpawn();
         $this->inventory->sendContents($this);
         $this->inventory->sendArmorContents($this);
     }
     Timings::$playerChunkSendTimer->stopTiming();
 }
Пример #15
0
 /**
  *
  * WARNING: Do not use this, it's only for internal use.
  * Changes to this function won't be recorded on the version.
  *
  * @return bool
  */
 public function orderChunks()
 {
     if ($this->connected === false) {
         return false;
     }
     $radiusSquared = $this->viewDistance / M_PI;
     $radius = ceil(sqrt($radiusSquared));
     $newOrder = [];
     $lastChunk = $this->usedChunks;
     $centerX = $this->x >> 4;
     $centerZ = $this->z >> 4;
     $generateQueue = new ReversePriorityQueue();
     for ($X = -$radius; $X <= $radius; ++$X) {
         for ($Z = -$radius; $Z <= $radius; ++$Z) {
             $distance = $X * $X + $Z * $Z;
             if ($distance > $radiusSquared) {
                 continue;
             }
             $chunkX = $X + $centerX;
             $chunkZ = $Z + $centerZ;
             $index = Level::chunkHash($chunkX, $chunkZ);
             if (!isset($this->usedChunks[$index])) {
                 if ($this->level->isChunkPopulated($chunkX, $chunkZ)) {
                     $newOrder[$index] = $distance;
                 } else {
                     $generateQueue->insert([$chunkX, $chunkZ], $distance);
                 }
             }
             unset($lastChunk[$index]);
         }
     }
     asort($newOrder);
     if (count($newOrder) > $this->viewDistance) {
         $count = 0;
         $this->loadQueue = [];
         foreach ($newOrder as $k => $distance) {
             $this->loadQueue[$k] = $distance;
             if (++$count > $this->viewDistance) {
                 break;
             }
         }
     } else {
         $this->loadQueue = $newOrder;
     }
     $i = 0;
     while (count($this->loadQueue) < 3 and $generateQueue->count() > 0 and $i < 16) {
         $d = $generateQueue->extract();
         $this->getLevel()->generateChunk($d[0], $d[1]);
         ++$i;
     }
     foreach ($lastChunk as $index => $Yndex) {
         $X = null;
         $Z = null;
         Level::getXZ($index, $X, $Z);
         foreach ($this->getLevel()->getChunkEntities($X, $Z) as $entity) {
             if ($entity !== $this) {
                 $entity->despawnFrom($this);
             }
         }
         unset($this->usedChunks[$index]);
     }
 }
Пример #16
0
 protected function orderChunks()
 {
     if ($this->connected === false) {
         return false;
     }
     $this->nextChunkOrderRun = 200;
     $radiusSquared = $this->viewDistance;
     $radius = ceil(sqrt($radiusSquared));
     $side = ceil($radius / 2);
     $newOrder = [];
     $lastChunk = $this->usedChunks;
     $currentQueue = [];
     $centerX = $this->x >> 4;
     $centerZ = $this->z >> 4;
     for ($X = -$side; $X <= $side; ++$X) {
         for ($Z = -$side; $Z <= $side; ++$Z) {
             $chunkX = $X + $centerX;
             $chunkZ = $Z + $centerZ;
             if (!isset($this->usedChunks[$index = Level::chunkHash($chunkX, $chunkZ)])) {
                 $newOrder[$index] = abs($X) + abs($Z);
             } else {
                 $currentQueue[$index] = abs($X) + abs($Z);
             }
         }
     }
     asort($newOrder);
     asort($currentQueue);
     $limit = $this->viewDistance;
     foreach ($currentQueue as $index => $distance) {
         if ($limit-- <= 0) {
             break;
         }
         unset($lastChunk[$index]);
     }
     foreach ($lastChunk as $index => $Yndex) {
         $X = null;
         $Z = null;
         Level::getXZ($index, $X, $Z);
         $this->unloadChunk($X, $Z);
     }
     $loadedChunks = count($this->usedChunks);
     if (count($newOrder) + $loadedChunks > $this->viewDistance) {
         $count = $loadedChunks;
         $this->loadQueue = [];
         foreach ($newOrder as $k => $distance) {
             if (++$count > $this->viewDistance) {
                 break;
             }
             $this->loadQueue[$k] = $distance;
         }
     } else {
         $this->loadQueue = $newOrder;
     }
     return true;
 }
Пример #17
0
 /**
  * Generates a new level if it does not exists
  *
  * @param string $name
  * @param int    $seed
  * @param string $generator Class name that extends pocketmine\level\generator\Noise
  * @param array  $options
  *
  * @return bool
  */
 public function generateLevel($name, $seed = null, $generator = null, $options = [])
 {
     if (trim($name) === "" or $this->isLevelGenerated($name)) {
         return false;
     }
     $seed = $seed === null ? Binary::readInt(@Utils::getRandomBytes(4, false)) : (int) $seed;
     if (!isset($options["preset"])) {
         $options["preset"] = $this->getConfigString("generator-settings", "");
     }
     if (!($generator !== null and class_exists($generator, true) and is_subclass_of($generator, Generator::class))) {
         $generator = Generator::getGenerator($this->getLevelType());
     }
     if (($provider = LevelProviderManager::getProviderByName($providerName = $this->getProperty("level-settings.default-format", "mcregion"))) === null) {
         $provider = LevelProviderManager::getProviderByName($providerName = "mcregion");
     }
     try {
         $path = $this->getDataPath() . "worlds/" . $name . "/";
         /** @var \pocketmine\level\format\LevelProvider $provider */
         $provider::generate($path, $name, $seed, $generator, $options);
         $level = new Level($this, $name, $path, $provider);
         $this->levels[$level->getId()] = $level;
         $level->initLevel();
         $level->setTickRate($this->baseTickRate);
     } catch (\Exception $e) {
         $this->logger->error($this->getLanguage()->translateString("pocketmine.level.generateError", [$name, $e->getMessage()]));
         if ($this->logger instanceof MainLogger) {
             $this->logger->logException($e);
         }
         return false;
     }
     $this->getPluginManager()->callEvent(new LevelInitEvent($level));
     $this->getPluginManager()->callEvent(new LevelLoadEvent($level));
     $this->getLogger()->notice($this->getLanguage()->translateString("pocketmine.level.backgroundGeneration", [$name]));
     $centerX = $level->getSpawnLocation()->getX() >> 4;
     $centerZ = $level->getSpawnLocation()->getZ() >> 4;
     $order = [];
     for ($X = -3; $X <= 3; ++$X) {
         for ($Z = -3; $Z <= 3; ++$Z) {
             $distance = $X ** 2 + $Z ** 2;
             $chunkX = $X + $centerX;
             $chunkZ = $Z + $centerZ;
             $index = Level::chunkHash($chunkX, $chunkZ);
             $order[$index] = $distance;
         }
     }
     asort($order);
     foreach ($order as $index => $distance) {
         Level::getXZ($index, $chunkX, $chunkZ);
         $level->populateChunk($chunkX, $chunkZ, true);
     }
     return true;
 }
Пример #18
0
 /**
  * @param string $message Message to be broadcasted
  * @param string $reason  Reason showed in console
  */
 public function close($message = "", $reason = "generic reason")
 {
     foreach ($this->tasks as $task) {
         $task->cancel();
     }
     $this->tasks = [];
     if ($this->connected and !$this->closed) {
         $this->connected = false;
         if ($this->username != "") {
             $this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message));
             if ($this->server->getAutoSave() and $this->loggedIn === true) {
                 $this->save();
             }
         }
         foreach ($this->windowIndex as $window) {
             $this->removeWindow($window);
         }
         $this->interface->close($this, $reason);
         $chunkX = $chunkZ = null;
         foreach ($this->usedChunks as $index => $d) {
             Level::getXZ($index, $chunkX, $chunkZ);
             $this->level->freeChunk($chunkX, $chunkZ, $this);
             unset($this->usedChunks[$index]);
         }
         parent::close();
         $this->loggedIn = false;
         if (isset($ev) and $this->username != "" and $this->spawned !== false and $ev->getQuitMessage() != "") {
             $this->server->broadcastMessage($ev->getQuitMessage());
         }
         $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this);
         $this->spawned = false;
         $this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "[/" . $this->ip . ":" . $this->port . "] logged out due to " . str_replace(["\n", "\r"], [" ", ""], $reason));
         $this->windows = new \SplObjectStorage();
         $this->windowIndex = [];
         $this->usedChunks = [];
         $this->loadQueue = [];
         $this->hasSpawned = [];
         $this->spawnPosition = null;
         unset($this->buffer);
     }
     $this->perm->clearPermissions();
     $this->server->removePlayer($this);
 }
Пример #19
0
 public function unloadChunks($force = false)
 {
     if (count($this->unloadQueue) > 0) {
         $maxUnload = 96;
         $now = microtime(true);
         foreach ($this->unloadQueue as $index => $time) {
             Level::getXZ($index, $X, $Z);
             if (!$force) {
                 if ($maxUnload <= 0) {
                     break;
                 } elseif ($time > $now - 30) {
                     continue;
                 }
             }
             //If the chunk can't be unloaded, it stays on the queue
             if ($this->unloadChunk($X, $Z, true)) {
                 unset($this->unloadQueue[$index]);
                 --$maxUnload;
             }
         }
     }
 }
Пример #20
0
 protected function sendNextChunk()
 {
     if ($this->connected === \false) {
         return;
     }
     Timings::$playerChunkSendTimer->startTiming();
     $count = 0;
     foreach ($this->loadQueue as $index => $distance) {
         if ($count >= $this->chunksPerTick) {
             break;
         }
         $X = \null;
         $Z = \null;
         Level::getXZ($index, $X, $Z);
         ++$count;
         $this->usedChunks[$index] = \false;
         $this->level->registerChunkLoader($this, $X, $Z, \false);
         if (!$this->level->populateChunk($X, $Z)) {
             if ($this->spawned and $this->teleportPosition === \null) {
                 continue;
             } else {
                 break;
             }
         }
         unset($this->loadQueue[$index]);
         $this->level->requestChunk($X, $Z, $this);
     }
     if ($this->chunkLoadCount >= $this->spawnThreshold and $this->spawned === \false and $this->teleportPosition === \null) {
         $this->doFirstSpawn();
     }
     Timings::$playerChunkSendTimer->stopTiming();
 }
Пример #21
0
 /**
  * WARNING: Do not use this, it's only for internal use.
  * Changes to this function won't be recorded on the version.
  *
  * @param int $currentTick
  *
  * @return bool
  */
 public function doTick($currentTick)
 {
     $this->timings->doTick->startTiming();
     $this->checkTime();
     if ($currentTick % 200 === 0) {
         $this->sendTime();
     }
     $this->unloadChunks();
     $X = null;
     $Z = null;
     //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[PHP_INT_SIZE === 8 ? ($block->x & 0xfffffff) << 35 | ($block->y & 0x7f) << 28 | $block->z & 0xfffffff : $block->x . ":" . $block->y . ":" . $block->z]);
         $block->onUpdate(self::BLOCK_UPDATE_SCHEDULED);
     }
     $this->timings->doTickPending->stopTiming();
     $this->timings->entityTick->startTiming();
     //Update entities that need update
     Timings::$tickEntityTimer->startTiming();
     foreach ($this->updateEntities as $id => $entity) {
         if ($entity->closed or !$entity->onUpdate($currentTick)) {
             unset($this->updateEntities[$id]);
         }
     }
     Timings::$tickEntityTimer->stopTiming();
     $this->timings->entityTick->stopTiming();
     $this->timings->tileEntityTick->startTiming();
     //Update tiles that need update
     if (count($this->updateTiles) > 0) {
         //Timings::$tickTileEntityTimer->startTiming();
         foreach ($this->updateTiles as $id => $tile) {
             if ($tile->onUpdate() !== true) {
                 unset($this->updateTiles[$id]);
             }
         }
         //Timings::$tickTileEntityTimer->stopTiming();
     }
     $this->timings->tileEntityTick->stopTiming();
     $this->timings->doTickTiles->startTiming();
     $this->tickChunks();
     $this->timings->doTickTiles->stopTiming();
     if (count($this->changedCount) > 0) {
         if (count($this->players) > 0) {
             foreach ($this->changedCount as $index => $mini) {
                 for ($Y = 0; $Y < 8; ++$Y) {
                     if (($mini & 1 << $Y) === 0) {
                         continue;
                     }
                     if (count($this->changedBlocks[$index][$Y]) < 256) {
                         continue;
                     } else {
                         $X = null;
                         $Z = null;
                         if (PHP_INT_SIZE === 8) {
                             $X = $index >> 32 << 32 >> 32;
                             $Z = ($index & 4294967295.0) << 32 >> 32;
                         } else {
                             list($X, $Z) = explode(":", $index);
                             $X = (int) $X;
                             $Z = (int) $Z;
                         }
                         foreach ($this->getUsingChunk($X, $Z) as $p) {
                             $p->unloadChunk($X, $Z);
                         }
                         unset($this->changedBlocks[$index][$Y]);
                     }
                 }
             }
             $this->changedCount = [];
             if (count($this->changedBlocks) > 0) {
                 foreach ($this->changedBlocks as $index => $mini) {
                     foreach ($mini as $blocks) {
                         /** @var Block $b */
                         foreach ($blocks as $b) {
                             $pk = new UpdateBlockPacket();
                             $pk->x = $b->x;
                             $pk->y = $b->y;
                             $pk->z = $b->z;
                             $pk->block = $b->getId();
                             $pk->meta = $b->getDamage();
                             Server::broadcastPacket($this->getUsingChunk($b->x >> 4, $b->z >> 4), $pk);
                         }
                     }
                 }
                 $this->changedBlocks = [];
             }
         } else {
             $this->changedCount = [];
             $this->changedBlocks = [];
         }
     }
     $this->processChunkRequest();
     foreach ($this->moveToSend as $index => $entry) {
         Level::getXZ($index, $chunkX, $chunkZ);
         $pk = new MoveEntityPacket();
         $pk->entities = $entry;
         Server::broadcastPacket($this->getUsingChunk($chunkX, $chunkZ), $pk);
     }
     $this->moveToSend = [];
     foreach ($this->motionToSend as $index => $entry) {
         Level::getXZ($index, $chunkX, $chunkZ);
         $pk = new SetEntityMotionPacket();
         $pk->entities = $entry;
         Server::broadcastPacket($this->getUsingChunk($chunkX, $chunkZ), $pk);
     }
     $this->motionToSend = [];
     $this->timings->doTick->stopTiming();
 }
Пример #22
0
 protected function sendNextChunk()
 {
     if ($this->connected === false) {
         return;
     }
     $count = 0;
     foreach ($this->loadQueue as $index => $distance) {
         if ($count >= $this->chunksPerTick) {
             break;
         }
         Level::getXZ($index, $X, $Z);
         if (!$this->level->isChunkPopulated($X, $Z)) {
             $this->level->generateChunk($X, $Z);
             if ($this->spawned) {
                 continue;
             } else {
                 break;
             }
         }
         ++$count;
         unset($this->loadQueue[$index]);
         $this->usedChunks[$index] = true;
         $this->level->useChunk($X, $Z, $this);
         $chunk = $this->level->getChunk($X, $Z);
         if ($chunk instanceof AnvilChunk) {
             $this->kick("Playing on Anvil worlds is not yet implemented");
             //TODO!
             /*$pk = new ChunkDataPacket();
             				$pk->chunkX = $X;
             				$pk->chunkZ = $Z;
             				$pk->groundUp = true;
             				$ids = "";
             				$meta = "";
             				$blockLight = "";
             				$skyLight = "";
             				$biomeIds = $chunk->getBiomeIdArray();
             				$bitmap = 0;
             				for($s = 0; $s < 8; ++$s){
             					$section = $chunk->getSection($s);
             					if(!($section instanceof EmptyChunkSection)){
             						$bitmap |= 1 << $s;
             					}else{
             						continue;
             					}
             					$ids .= $section->getIdArray();
             					$meta .= $section->getDataArray();
             					$blockLight .= $section->getLightArray();
             					$skyLight .= $section->getSkyLightArray();
             				}
             
             				$pk->payload = zlib_encode($ids . $meta . $blockLight . $skyLight . $biomeIds, ZLIB_ENCODING_DEFLATE, Level::$COMPRESSION_LEVEL);
             				$pk->primaryBitmap = $bitmap;
             				$this->putRawPacket($pk);*/
         } elseif ($chunk instanceof McRegionChunk) {
             $task = new McRegionToAnvil($this, $chunk);
             $this->server->getScheduler()->scheduleAsyncTask($task);
         } elseif ($chunk instanceof LevelDBChunk) {
             $task = new LevelDBToAnvil($this, $chunk);
             $this->server->getScheduler()->scheduleAsyncTask($task);
         }
         foreach ($chunk->getEntities() as $entity) {
             if ($entity !== $this) {
                 $entity->spawnTo($this);
             }
         }
         foreach ($chunk->getTiles() as $tile) {
             if ($tile instanceof Spawnable) {
                 $tile->spawnTo($this);
             }
         }
     }
     if (count($this->usedChunks) >= 4 and $this->spawned === false) {
         $this->bigBrother_setTitleBar(TextFormat::YELLOW . TextFormat::BOLD . "This is a beta version of BigBrother.", 0);
         $this->spawned = true;
         $pk = new SetTimePacket();
         $pk->time = $this->level->getTime();
         $pk->started = $this->level->stopTime == false;
         $this->dataPacket($pk);
         $pos = $this->level->getSafeSpawn($this);
         $this->server->getPluginManager()->callEvent($ev = new PlayerRespawnEvent($this, $pos));
         $this->teleport($ev->getRespawnPosition());
         $this->sendSettings();
         $this->inventory->sendContents($this);
         $this->inventory->sendArmorContents($this);
         $this->server->getPluginManager()->callEvent($ev = new PlayerJoinEvent($this, TextFormat::YELLOW . $this->getName() . " joined the game"));
         if (strlen(trim($ev->getJoinMessage())) > 0) {
             $this->server->broadcastMessage($ev->getJoinMessage());
         }
         $this->spawnToAll();
         if ($this->server->getUpdater()->hasUpdate() and $this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)) {
             $this->server->getUpdater()->showPlayerUpdate($this);
         }
     }
 }