public function onUnloadChunk(ChunkUnloadEvent $event) { if ($event->getLevel()->getName() !== "world_pvp") { return; } $chunk = $event->getChunk(); $hash = Level::chunkHash($chunk->getX(), $chunk->getZ()); if (isset($this->modelLocs[$hash])) { foreach ($this->modelLocs[$hash] as $id => $model) { if (isset($this->models[$id])) { $this->models[$id]->_kill(); unset($this->models[$id]); } } } if (isset($this->shopLocs[$hash])) { foreach ($this->shopLocs[$hash] as $col => $loc) { if (isset($this->shops[$col])) { $this->shops[$col]->_kill(); unset($this->shops[$col]); } } } if ($hash === $this->bowHash) { $this->bow->_kill(); $this->bow = null; } }
public function onUnload(ChunkUnloadEvent $event) { if ($event->getLevel() === $this->level) { foreach ($this->locs[Level::chunkHash($event->getChunk()->getX(), $event->getChunk()->getZ())] as $id => $spawn) { if (isset($this->spawns[$spawn->getId()])) { $this->level->removeEntity($this->spawns[$spawn->getId()]); } } } }
public function resetMine() { $chunks = []; for ($x = $this->getA()->getX(); $x - 16 <= $this->getB()->getX(); $x += 16) { for ($z = $this->getA()->getZ(); $z - 16 <= $this->getB()->getZ(); $z += 16) { //$this->getLevel()->getServer()->getLogger()->info(Level::chunkHash($x >> 4, $z >> 4)); $chunk = $this->level->getChunk($x >> 4, $z >> 4, true); $chunkClass = get_class($chunk); $chunks[Level::chunkHash($x >> 4, $z >> 4)] = $chunk->toBinary(); } } //var_dump($chunks); $resetTask = new MineResetTask($chunks, $this->a, $this->b, $this->data, $this->getLevel()->getId(), $this->base->getRegionBlocker()->blockZone($this->a, $this->b, $this->level), $chunkClass); $this->base->scheduleReset($resetTask); }
public function spawnTo(Player $player) { if (!isset($this->hasSpawned[$player->getLoaderId()]) && isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])) { $pk = new AddEntityPacket(); $pk->eid = $this->getID(); $pk->type = static::NETWORK_ID; $pk->x = $this->x; $pk->y = $this->y; $pk->z = $this->z; $pk->speedX = 0; $pk->speedY = 0; $pk->speedZ = 0; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; $pk->metadata = $this->dataProperties; $player->dataPacket($pk); $this->hasSpawned[$player->getLoaderId()] = $player; } }
/** * Actions to execute when run * * @return void */ public function onRun() { $chunkClass = $this->chunkClass; /** @var Chunk[] $chunks */ $chunks = unserialize($this->chunks); foreach ($chunks as $hash => $binary) { $chunks[$hash] = $chunkClass::fromBinary($binary); } $sum = []; $id = array_keys(unserialize($this->ratioData)); for ($i = 0; $i < count($id); $i++) { $blockId = explode(":", $id[$i]); if (!isset($blockId[1])) { $blockId[1] = 0; } $id[$i] = $blockId; } $m = array_values(unserialize($this->ratioData)); $sum[0] = $m[0]; for ($l = 1; $l < count($m); $l++) { $sum[$l] = $sum[$l - 1] + $m[$l]; } for ($x = $this->a->getX(); $x <= $this->b->getX(); $x++) { for ($y = $this->a->getY(); $y <= $this->b->getY(); $y++) { for ($z = $this->a->getZ(); $z <= $this->b->getZ(); $z++) { $a = rand(0, end($sum)); for ($l = 0; $l < count($sum); $l++) { if ($a <= $sum[$l]) { $hash = Level::chunkHash($x >> 4, $z >> 4); if (isset($chunks[$hash])) { $chunks[$hash]->setBlock($x & 0xf, $y & 0x7f, $z & 0xf, $id[$l][0] & 0xff, $id[$l][1] & 0xff); } $l = count($sum); } } } } } $this->setResult($chunks); }
/** * 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; }
public function doChunkGarbageCollection() { $this->timings->doChunkGC->startTiming(); $X = null; $Z = null; foreach ($this->chunks as $index => $chunk) { if (!isset($this->unloadQueue[$index]) and (!isset($this->usedChunks[$index]) or count($this->usedChunks[$index]) === 0)) { Level::getXZ($index, $X, $Z); if (!$this->isSpawnChunk($X, $Z)) { $this->unloadChunkRequest($X, $Z, true); } } } foreach ($this->provider->getLoadedChunks() as $chunk) { if (!isset($this->chunks[Level::chunkHash($chunk->getX(), $chunk->getZ())])) { $this->provider->unloadChunk($chunk->getX(), $chunk->getZ(), false); } } $this->provider->doGarbageCollection(); $this->timings->doChunkGC->stopTiming(); }
protected function loadRegion($x, $z) { if (!isset($this->regions[$index = Level::chunkHash($x, $z)])) { $this->regions[$index] = new RegionLoader($this, $x, $z); } }
protected function enqueueChunk($levelID, $chunkX, $chunkZ) { if (!isset($this->requestQueue[$levelID])) { $this->requestQueue[$levelID] = []; } if (!isset($this->requestQueue[$levelID][$index = Level::chunkHash($chunkX, $chunkZ)])) { $this->requestQueue[$levelID][$index] = 1; } else { $this->requestQueue[$levelID][$index]++; arsort($this->requestQueue[$levelID]); } }
/** * 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; }
public function setChunk($chunkX, $chunkZ, FullChunk $chunk) { if (!$chunk instanceof Chunk) { throw new ChunkException("Invalid Chunk class"); } $chunk->setProvider($this); $chunk->setX($chunkX); $chunk->setZ($chunkZ); if (isset($this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)]) and $this->chunks[$index] !== $chunk) { $this->unloadChunk($chunkX, $chunkZ, false); } $this->chunks[$index] = $chunk; }
/** * 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; }
/** * @param Player $player */ public function spawnTo(Player $player) { if (!isset($this->hasSpawned[$player->getLoaderId()]) and isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])) { $this->hasSpawned[$player->getLoaderId()] = $player; } }
protected function generateChunk($levelID, $chunkX, $chunkZ) { if (isset($this->levels[$levelID]) and !isset($this->generatedQueue[$levelID][$index = Level::chunkHash($chunkX, $chunkZ)])) { $this->levels[$levelID]->populateChunk($chunkX, $chunkZ); //Request population directly if (isset($this->levels[$levelID])) { $this->generatedQueue[$levelID][$index] = true; foreach ($this->levels[$levelID]->getChangedChunks() as $index => $chunk) { if ($chunk->isPopulated()) { $this->sendChunk($levelID, $chunk); $this->levels[$levelID]->cleanChangedChunk($index); } } if (count($this->generatedQueue[$levelID]) > 4) { $this->levels[$levelID]->doGarbageCollection(); $this->generatedQueue[$levelID] = []; $this->levels[$levelID]->cleanChangedChunks(); } } } }
/** * @param int $chunkX * @param int $chunkZ * @param FullChunk $chunk */ public function setChunk($chunkX, $chunkZ, FullChunk $chunk) { $this->chunks[$index = Level::chunkHash($chunkX, $chunkZ)] = $chunk; $this->changes[$index] = $chunk; if ($chunk->isPopulated()) { //TODO: Queue to be sent } }
protected function checkTeleportPosition() { if ($this->teleportPosition !== null) { $chunkX = $this->teleportPosition->x >> 4; $chunkZ = $this->teleportPosition->z >> 4; for ($X = -1; $X <= 1; ++$X) { for ($Z = -1; $Z <= 1; ++$Z) { if (!isset($this->usedChunks[$index = Level::chunkHash($chunkX + $X, $chunkZ + $Z)]) or $this->usedChunks[$index] === false) { return false; } } } $this->sendPosition($this, null, null, 1, Network::CHANNEL_WORLD_CHUNKS); $this->forceMovement = $this->teleportPosition; $this->teleportPosition = null; return true; } return true; }
public function loadChunk($chunkX, $chunkZ, $create = false) { $index = Level::chunkHash($chunkX, $chunkZ); if (isset($this->chunks[$index])) { return true; } $regionX = $regionZ = null; self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); $this->loadRegion($regionX, $regionZ); $this->level->timings->syncChunkLoadDataTimer->startTiming(); $chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32); if ($chunk === null and $create) { $chunk = $this->getEmptyChunk($chunkX, $chunkZ); } $this->level->timings->syncChunkLoadDataTimer->stopTiming(); if ($chunk !== null) { $this->chunks[$index] = $chunk; return true; } else { return false; } }
public function spawnTo(Player $player) { if (isset($this->hasSpawned[$player->getLoaderId()]) or !isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])) { return; } if (!$this->dummyReceiver instanceof DummyReceiver) { return; } $pk = new AddPlayerPacket(); $pk->uuid = $this->dummyReceiver->randomUUID; $pk->username = $this->dummyReceiver->getName(); $pk->eid = $this->getId(); $pk->x = $this->x; $pk->y = $this->y; $pk->z = $this->z; $pk->speedX = $this->motionX; $pk->speedY = $this->motionY; $pk->speedZ = $this->motionZ; $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; $pk->item = Item::get(Item::DIAMOND_PICKAXE); $pk->metadata = $this->dummyReceiver->getDataProperties(); $player->dataPacket($pk); $this->dummyReceiver->getInventory()->sendArmorContents($player); if (!$this instanceof Player) { $this->server->removePlayerListData($this->dummyReceiver->randomUUID, [$player]); } $this->hasSpawned[$player->getLoaderId()] = $player; }
public function generateChunk($chunkX, $chunkZ) { $this->random->setSeed(0xdeadbeef ^ $chunkX << 8 ^ $chunkZ ^ $this->level->getSeed()); $noise = Generator::getFastNoise3D($this->noiseBase, 16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16); $chunk = $this->level->getChunk($chunkX, $chunkZ); $biomeCache = []; for ($x = 0; $x < 16; ++$x) { for ($z = 0; $z < 16; ++$z) { $minSum = 0; $maxSum = 0; $weightSum = 0; $biome = $this->pickBiome($chunkX * 16 + $x, $chunkZ * 16 + $z); $chunk->setBiomeId($x, $z, $biome->getId()); $color = [0, 0, 0]; for ($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx) { for ($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz) { $weight = self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE]; if ($sx === 0 and $sz === 0) { $adjacent = $biome; } else { $index = Level::chunkHash($chunkX * 16 + $x + $sx, $chunkZ * 16 + $z + $sz); if (isset($biomeCache[$index])) { $adjacent = $biomeCache[$index]; } else { $biomeCache[$index] = $adjacent = $this->pickBiome($chunkX * 16 + $x + $sx, $chunkZ * 16 + $z + $sz); } } $minSum += ($adjacent->getMinElevation() - 1) * $weight; $maxSum += $adjacent->getMaxElevation() * $weight; $bColor = $adjacent->getColor(); $color[0] += ($bColor >> 16) ** 2 * $weight; $color[1] += ($bColor >> 8 & 0xff) ** 2 * $weight; $color[2] += ($bColor & 0xff) ** 2 * $weight; $weightSum += $weight; } } $minSum /= $weightSum; $maxSum /= $weightSum; $chunk->setBiomeColor($x, $z, sqrt($color[0] / $weightSum), sqrt($color[1] / $weightSum), sqrt($color[2] / $weightSum)); $solidLand = false; for ($y = 127; $y >= 0; --$y) { if ($y === 0) { $chunk->setBlockId($x, $y, $z, Block::BEDROCK); continue; } // A noiseAdjustment of 1 will guarantee ground, a noiseAdjustment of -1 will guarantee air. //$effHeight = min($y - $smoothHeight - $minSum, $noiseAdjustment = 2 * (($maxSum - $y) / ($maxSum - $minSum)) - 1; // To generate caves, we bring the noiseAdjustment down away from 1. $caveLevel = $minSum - 10; $distAboveCaveLevel = max(0, $y - $caveLevel); // must be positive $noiseAdjustment = min($noiseAdjustment, 0.4 + $distAboveCaveLevel / 10); $noiseValue = $noise[$x][$z][$y] + $noiseAdjustment; if ($noiseValue > 0) { $chunk->setBlockId($x, $y, $z, Block::STONE); $solidLand = true; } elseif ($y <= $this->waterHeight && $solidLand == false) { $chunk->setBlockId($x, $y, $z, Block::STILL_WATER); } } } } foreach ($this->generationPopulators as $populator) { $populator->populate($this->level, $chunkX, $chunkZ, $this->random); } }
public function setChunk($chunkX, $chunkZ, FullChunk $chunk) { if (!$chunk instanceof Chunk) { throw new \Exception("Invalid Chunk class"); } $chunk->setProvider($this); if ($chunk->isPopulated() === false) { $this->unloadChunk($chunkX, $chunkZ, false); $regionX = $regionZ = null; self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); $this->loadRegion($regionX, $regionZ); $region = $this->getRegion($regionX, $regionZ); $region->removeChunk($chunkX - $region->getX() * 32, $chunkZ - $region->getZ() * 32); $this->loadChunk($chunkX, $chunkZ); } else { $chunk->setX($chunkX); $chunk->setZ($chunkZ); $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; //$this->saveChunk($chunkX, $chunkZ); } }
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; }
protected function loadRegion($x, $z) { if (isset($this->regions[$index = Level::chunkHash($x, $z)])) { return true; } $this->regions[$index] = new RegionLoader($this, $x, $z); return true; }
/** * @param int $chunkX * @param int $chunkZ * @param FullChunk $chunk */ public function setChunk($chunkX, $chunkZ, FullChunk $chunk = null) { if ($chunk === null) { unset($this->chunks[Level::chunkHash($chunkX, $chunkZ)]); return; } $this->chunks[Level::chunkHash($chunkX, $chunkZ)] = $chunk; }
protected function checkTeleportPosition() { if ($this->teleportPosition !== null) { $chunkX = $this->teleportPosition->x >> 4; $chunkZ = $this->teleportPosition->z >> 4; for ($X = -1; $X <= 1; ++$X) { for ($Z = -1; $Z <= 1; ++$Z) { if (!isset($this->usedChunks[$index = Level::chunkHash($chunkX + $X, $chunkZ + $Z)]) or $this->usedChunks[$index] === false) { return false; } } } $this->sendPosition($this, $this->pitch, $this->yaw, 1); $this->spawnToAll(); $this->forceMovement = $this->teleportPosition; $this->teleportPosition = null; return true; } return true; }
protected function queueUnloadChunk($x, $z) { $this->unloadQueue[Level::chunkHash($x, $z)] = microtime(true); }
public function addPlayerMovement($chunkX, $chunkZ, $entityId, $x, $y, $z, $yaw, $pitch, $onGround, $headYaw = null) { if (!isset($this->moveToSend[$index = Level::chunkHash($chunkX, $chunkZ)])) { $this->moveToSend[$index] = []; } $pk = new MovePlayerPacket(); $pk->eid = $entityId; $pk->x = $x; $pk->y = $y; $pk->z = $z; $pk->yaw = $headYaw === null ? $yaw : $headYaw; $pk->bodyYaw = $yaw; $pk->pitch = $pitch; $pk->onGround = $onGround; $pk->mode = MovePlayerPacket::MODE_NORMAL; $this->moveToSend[$index][$entityId] = $pk; }
public function onChunkChanged(FullChunk $chunk) { $this->loadQueue[Level::chunkHash($chunk->getX(), $chunk->getZ())] = abs(($this->x >> 4) - $chunk->getX()) + abs(($this->z >> 4) - $chunk->getZ()); }
public function generateChunk($chunkX, $chunkZ) { $this->random->setSeed(0xdeadbeef ^ $chunkX << 8 ^ $chunkZ ^ $this->level->getSeed()); $noise = Generator::getFastNoise3D($this->noiseBase, 16, 128, 16, 4, 8, 4, $chunkX * 16, 0, $chunkZ * 16); $chunk = $this->level->getChunk($chunkX, $chunkZ); $biomeCache = []; for ($x = 0; $x < 16; ++$x) { for ($z = 0; $z < 16; ++$z) { $minSum = 0; $maxSum = 0; $weightSum = 0; $biome = $this->pickBiome($chunkX * 16 + $x, $chunkZ * 16 + $z); $chunk->setBiomeId($x, $z, $biome->getId()); $color = [0, 0, 0]; for ($sx = -self::$SMOOTH_SIZE; $sx <= self::$SMOOTH_SIZE; ++$sx) { for ($sz = -self::$SMOOTH_SIZE; $sz <= self::$SMOOTH_SIZE; ++$sz) { $weight = self::$GAUSSIAN_KERNEL[$sx + self::$SMOOTH_SIZE][$sz + self::$SMOOTH_SIZE]; if ($sx === 0 and $sz === 0) { $adjacent = $biome; } else { $index = Level::chunkHash($chunkX * 16 + $x + $sx, $chunkZ * 16 + $z + $sz); if (isset($biomeCache[$index])) { $adjacent = $biomeCache[$index]; } else { $biomeCache[$index] = $adjacent = $this->pickBiome($chunkX * 16 + $x + $sx, $chunkZ * 16 + $z + $sz); } } $minSum += ($adjacent->getMinElevation() - 1) * $weight; $maxSum += $adjacent->getMaxElevation() * $weight; $bColor = $adjacent->getColor(); $color[0] += ($bColor >> 16) ** 2 * $weight; $color[1] += ($bColor >> 8 & 0xff) ** 2 * $weight; $color[2] += ($bColor & 0xff) ** 2 * $weight; $weightSum += $weight; } } $minSum /= $weightSum; $maxSum /= $weightSum; $chunk->setBiomeColor($x, $z, sqrt($color[0] / $weightSum), sqrt($color[1] / $weightSum), sqrt($color[2] / $weightSum)); $smoothHeight = ($maxSum - $minSum) / 2; for ($y = 0; $y < 128; ++$y) { if ($y === 0) { $chunk->setBlockId($x, $y, $z, Block::BEDROCK); continue; } $noiseValue = $noise[$x][$z][$y] - 1 / $smoothHeight * ($y - $smoothHeight - $minSum); if ($noiseValue > 0) { $chunk->setBlockId($x, $y, $z, Block::STONE); } elseif ($y <= $this->waterHeight) { $chunk->setBlockId($x, $y, $z, Block::STILL_WATER); } } } } foreach ($this->generationPopulators as $populator) { $populator->populate($this->level, $chunkX, $chunkZ, $this->random); } }
public function addEntityMovement($chunkX, $chunkZ, $entityId, $x, $y, $z, $yaw, $pitch, $headYaw = null) { if (!isset($this->moveToSend[$index = Level::chunkHash($chunkX, $chunkZ)])) { $this->moveToSend[$index] = []; } $this->moveToSend[$index][$entityId] = [$entityId, $x, $y, $z, $yaw, $headYaw === null ? $yaw : $headYaw, $pitch]; }
public function serverToInterface(DesktopPlayer $player, DataPacket $packet) { switch ($packet->pid()) { case Info::DISCONNECT_PACKET: if ($player->bigBrother_getStatus() === 0) { $pk = new LoginDisconnectPacket(); $pk->reason = TextFormat::toJSON($packet->message === "" ? "You have been disconnected." : $packet->message); } else { $pk = new PlayDisconnectPacket(); $pk->reason = TextFormat::toJSON($packet->message === "" ? "You have been disconnected." : $packet->message); } return $pk; case Info::TEXT_PACKET: echo $player->getSetting("Lang") . "\n"; /*if($packet->message === "chat.type.achievement"){ /*$pk = new ScoreboardObjectivePacket(); $pk->ObjectiveName = $packet->parameters[0]; $pk->Mode = 0; $pk->ObjectiveValue = 3; return $pk;*/ /*echo "TextPacket: achievement\n"; return null; }else{ $pk = new STCChatPacket(); $pk->message = TextFormat::toJSON($packet->message, $packet->type, $packet->parameters); }*/ //return $pk; return null; case Info::SET_TIME_PACKET: $pk = new TimeUpdatePacket(); $pk->age = $packet->time; $pk->time = $packet->time; //TODO: calculate offset from MCPE return $pk; case Info::START_GAME_PACKET: $packets = []; $pk = new JoinGamePacket(); $pk->eid = $packet->eid; $pk->gamemode = $packet->gamemode; $pk->dimension = 0; $pk->difficulty = $player->getServer()->getDifficulty(); $pk->maxPlayers = $player->getServer()->getMaxPlayers(); $pk->levelType = "default"; $packets[] = $pk; $pk = new SpawnPositionPacket(); $pk->spawnX = $packet->spawnX; $pk->spawnY = $packet->spawnY; $pk->spawnZ = $packet->spawnZ; $packets[] = $pk; $pk = new PlayerAbilitiesPacket(); $pk->flyingSpeed = 0.05; $pk->walkingSpeed = 0.1; $pk->canFly = ($player->getGamemode() & 0x1) > 0; $pk->damageDisabled = ($player->getGamemode() & 0x1) > 0; $pk->isFlying = false; $pk->isCreative = ($player->getGamemode() & 0x1) > 0; $packets[] = $pk; $pk = new PositionAndLookPacket(); $pk->x = $packet->x; $pk->y = $packet->y; $pk->z = $packet->z; $pk->yaw = $player->yaw; $pk->pitch = $player->pitch; $packets[] = $pk; return $packets; case Info::ADD_PLAYER_PACKET: $packets = []; $packetplayer = $player->getServer()->getPlayerExact($packet->username); $pk = new PlayerListPacket(); $pk->actionID = PlayerListPacket::TYPE_ADD; $pk->players[] = [$packetplayer->getUniqueId()->toBinary(), $packetplayer->getName(), [], $packetplayer->getGamemode(), 0, false]; if ($packetplayer instanceof DesktopPlayer) { $pk->players[0][2] = $packetplayer->bigBrother_getPeroperties(); } $packets[] = $pk; $pk = new SpawnPlayerPacket(); $pk->eid = $packet->eid; $pk->uuid = $packetplayer->getUniqueId()->toBinary(); $pk->x = $packet->x; $pk->z = $packet->z; $pk->y = $packet->y; $pk->yaw = $packet->yaw; $pk->pitch = $packet->pitch; $pk->item = $packetplayer->getInventory()->getItemInHand()->getId(); $pk->metadata = $packet->metadata; $packets[] = $pk; $pk = new EntityTeleportPacket(); $pk->eid = $packet->eid; $pk->x = $packet->x; $pk->y = $packet->y; $pk->z = $packet->z; $pk->yaw = $packet->yaw; $pk->pitch = $packet->pitch; $packets[] = $pk; return $packets; /*case Info::ADD_ENTITY_PACKET: return null;*/ /*case Info::REMOVE_PLAYER_PACKET: $pk = new PlayerListPacket(); $pk->actionID = PlayerListPacket::TYPE_REMOVE; $pk->players[] = [ $packet->clientId->toBinary() ]; $packets[] = $pk; $pk = new DestroyEntitiesPacket(); $pk->ids[] = $packet->eid; $packets[] = $pk; return $packets;*/ /*case Info::ADD_ENTITY_PACKET: return null;*/ /*case Info::REMOVE_PLAYER_PACKET: $pk = new PlayerListPacket(); $pk->actionID = PlayerListPacket::TYPE_REMOVE; $pk->players[] = [ $packet->clientId->toBinary() ]; $packets[] = $pk; $pk = new DestroyEntitiesPacket(); $pk->ids[] = $packet->eid; $packets[] = $pk; return $packets;*/ case Info::REMOVE_ENTITY_PACKET: $pk = new DestroyEntitiesPacket(); $pk->ids[] = $packet->eid; return $pk; case Info::ADD_ITEM_ENTITY_PACKET: $packets = []; $pk = new SpawnObjectPacket(); $pk->eid = $packet->eid; $pk->type = 2; $pk->x = $packet->x; $pk->y = $packet->y; $pk->z = $packet->z; $pk->yaw = $player->yaw; $pk->pitch = $player->pitch; $packets[] = $pk; $pk = new EntityMetadataPacket(); $pk->eid = $packet->eid; $pk->metadata = [0 => [0 => 0, 1 => 0], 10 => [0 => 5, 1 => $packet->item]]; $packets[] = $pk; return $packets; /*case Info::REMOVE_ITEM_ENTITY_PACKET: return null;*/ /*case Info::REMOVE_ITEM_ENTITY_PACKET: return null;*/ case Info::MOVE_ENTITY_PACKET: $packets = []; foreach ($packet->entities as $d) { $pk = new EntityTeleportPacket(); $pk->eid = $d[0]; $pk->x = $d[1]; $pk->y = $d[2] - $player->getEyeHeight(); $pk->z = $d[3]; $pk->yaw = $d[4]; $pk->pitch = $d[6]; $packets[] = $pk; $pk = new EntityHeadLookPacket(); $pk->eid = $d[0]; $pk->yaw = $d[5]; $packets[] = $pk; } return $packets; case Info::MOVE_PLAYER_PACKET: if ($packet->eid === 0) { $pk = new PositionAndLookPacket(); $pk->x = $packet->x; $pk->y = $packet->y - $player->getEyeHeight(); $pk->z = $packet->z; $pk->yaw = $packet->yaw; $pk->pitch = $packet->pitch; $pk->onGround = $player->isOnGround(); return $pk; } else { $packets = []; $pk = new EntityTeleportPacket(); $pk->eid = $packet->eid; $pk->x = $packet->x; $pk->y = $packet->y - $player->getEyeHeight(); $pk->z = $packet->z; $pk->yaw = $packet->yaw; $pk->pitch = $packet->pitch; $packets[] = $pk; $pk = new EntityHeadLookPacket(); $pk->eid = $packet->eid; $pk->yaw = $packet->yaw; $packets[] = $pk; return $packets; } case Info::UPDATE_BLOCK_PACKET: //TODO $pk = new BlockChangePacket(); $pk->x = $packet->x; $pk->y = $packet->y; $pk->z = $packet->z; $pk->blockId = $packet->blockId; $pk->blockMeta = $packet->blockData; return $pk; case Info::MOB_EQUIPMENT_PACKET: $pk = new EntityEquipmentPacket(); $pk->eid = $packet->eid; $pk->slot = $packet->slot; $pk->item = $packet->item; return $pk; case Info::MOB_ARMOR_EQUIPMENT_PACKET: $packets = []; foreach ($packet->slots as $num => $item) { $pk = new EntityEquipmentPacket(); $pk->eid = $packet->eid; $pk->slot = $num + 1; $pk->item = $item; $packets[] = $pk; } return $packets; case Info::SET_ENTITY_DATA_PACKET: /*if(isset($packet->metadata[16])){ if($packet->metadata[16][1] === 2){ $pk = new UseBedPacket(); //Bug $pk->eid = $packet->eid; $bedXYZ = $player->getSetting("BedXYZ"); $pk->bedX = $bedXYZ[0]; $pk->bedY = $bedXYZ[1]; $pk->bedZ = $bedXYZ[2]; $player->removeSetting("BedXYZ"); }else{ $pk = new CAnimatePacket(); $pk->eid = $packet->eid; $pk->actionID = 2; } return $pk; }elseif(isset($packet->metadata[17])){ $player->setSetting(["BedXYZ" => $packet->metadata[17][1]]); }*/ $pk = new EntityMetadataPacket(); $pk->eid = $packet->eid; $pk->metadata = $packet->metadata; return $pk; case Info::SET_ENTITY_MOTION_PACKET: $pk = new EntityVelocityPacket(); $pk->eid = $packet->eid; $pk->velocityX = $packet->motionX; $pk->velocityY = $packet->motionY; $pk->velocityZ = $packet->motionZ; return $pk; case Info::SET_HEALTH_PACKET: $pk = new UpdateHealthPacket(); $pk->health = $packet->health; $pk->food = 20; $pk->saturation = 5; return $pk; case Info::SET_SPAWN_POSITION_PACKET: $pk = new SpawnPositionPacket(); $pk->spawnX = $packet->x; $pk->spawnY = $packet->y; $pk->spawnZ = $packet->z; return $pk; case Info::ANIMATE_PACKET: switch ($packet->action) { case 1: $pk = new CAnimatePacket(); $pk->actionID = 0; $pk->eid = $packet->eid; return $pk; break; case 3: //LeaveBed $pk = new CAnimatePacket(); $pk->actionID = 2; $pk->eid = $packet->eid; return $pk; break; default: echo "AnimatePacket: " . $packet->action . "\n"; break; } return null; case Info::RESPAWN_PACKET: $pk = new CRespawnPacket(); $pk->dimension = 0; $pk->difficulty = $player->getServer()->getDifficulty(); $pk->gamemode = $player->getGamemode(); $pk->levelType = "default"; return $pk; /*case Info::CONTAINER_OPEN_PACKET: $pk = new OpenWindowPacket(); $pk->windowID = $packet->windowid; $pk->inventoryType = $packet->type; $pk->windowTitle = ""; $pk->slots = $packet->slots; return $pk; case Info::CONTAINER_CLOSE_PACKET: $pk = new STCCloseWindowPacket(); $pk->windowID = $packet->windowid; return $pk; case Info::CONTAINER_SET_SLOT_PACKET: echo "ContainerSetSlotPacket: 0x".bin2hex(chr($packet->windowid))."\n"; $pk = new SetSlotPacket(); $pk->windowID = $packet->windowid; if($pk->windowID === 0x00){ $pk->slot = $packet->slot + 36; }elseif($pk->windowID === 0x78){ $pk->windowID = 0; $pk->slot = $packet->slot + 5; }else{ $pk->slot = $packet->slot; } $pk->item = $packet->item; return $pk; case Info::CONTAINER_SET_CONTENT_PACKET://Bug echo "ContainerSetContentPacket: 0x".bin2hex(chr($packet->windowid))."\n"; if($packet->windowid !== 0x79 and $packet->windowid !== 0x78){ $pk = new WindowItemsPacket(); $pk->windowID = 0; for($i = 0; $i < 5; ++$i){ $pk->items[] = Item::get(Item::AIR, 0, 0); } $pk->items[] = $player->getInventory()->getHelmet(); $pk->items[] = $player->getInventory()->getChestplate(); $pk->items[] = $player->getInventory()->getLeggings(); $pk->items[] = $player->getInventory()->getBoots(); if($player->getGamemode() === 0){ for($i = 9; $i < 36; ++$i){ $pk->items[] = $player->getInventory()->getItem($i); } }else{ for($i = 0; $i < 27; ++$i){ $pk->items[] = Item::get(Item::AIR, 0, 0); } } for($i = 0; $i < 9; ++$i){ $pk->items[] = $player->getInventory()->getItem($i); } return $pk; } return null;*/ /*case Info::CONTAINER_OPEN_PACKET: $pk = new OpenWindowPacket(); $pk->windowID = $packet->windowid; $pk->inventoryType = $packet->type; $pk->windowTitle = ""; $pk->slots = $packet->slots; return $pk; case Info::CONTAINER_CLOSE_PACKET: $pk = new STCCloseWindowPacket(); $pk->windowID = $packet->windowid; return $pk; case Info::CONTAINER_SET_SLOT_PACKET: echo "ContainerSetSlotPacket: 0x".bin2hex(chr($packet->windowid))."\n"; $pk = new SetSlotPacket(); $pk->windowID = $packet->windowid; if($pk->windowID === 0x00){ $pk->slot = $packet->slot + 36; }elseif($pk->windowID === 0x78){ $pk->windowID = 0; $pk->slot = $packet->slot + 5; }else{ $pk->slot = $packet->slot; } $pk->item = $packet->item; return $pk; case Info::CONTAINER_SET_CONTENT_PACKET://Bug echo "ContainerSetContentPacket: 0x".bin2hex(chr($packet->windowid))."\n"; if($packet->windowid !== 0x79 and $packet->windowid !== 0x78){ $pk = new WindowItemsPacket(); $pk->windowID = 0; for($i = 0; $i < 5; ++$i){ $pk->items[] = Item::get(Item::AIR, 0, 0); } $pk->items[] = $player->getInventory()->getHelmet(); $pk->items[] = $player->getInventory()->getChestplate(); $pk->items[] = $player->getInventory()->getLeggings(); $pk->items[] = $player->getInventory()->getBoots(); if($player->getGamemode() === 0){ for($i = 9; $i < 36; ++$i){ $pk->items[] = $player->getInventory()->getItem($i); } }else{ for($i = 0; $i < 27; ++$i){ $pk->items[] = Item::get(Item::AIR, 0, 0); } } for($i = 0; $i < 9; ++$i){ $pk->items[] = $player->getInventory()->getItem($i); } return $pk; } return null;*/ case Info::CRAFTING_DATA_PACKET: $player->setSetting(["Recipes" => $packet->entries, "cleanRecipes" => $packet->cleanRecipes]); return null; case Info::BLOCK_ENTITY_DATA_PACKET: $nbt = new NBT(NBT::LITTLE_ENDIAN); $nbt->read($packet->namedtag); $nbt = $nbt->getData(); if ($nbt["id"] !== Tile::SIGN) { return null; } else { $index = Level::chunkHash($packet->x >> 4, $packet->z >> 4); if (isset($player->usedChunks[$index]) and $player->usedChunks[$index]) { $pk = new UpdateSignPacket(); $pk->x = $packet->x; $pk->y = $packet->y; $pk->z = $packet->z; $pk->line1 = TextFormat::toJSON($nbt["Text1"]); $pk->line2 = TextFormat::toJSON($nbt["Text2"]); $pk->line3 = TextFormat::toJSON($nbt["Text3"]); $pk->line4 = TextFormat::toJSON($nbt["Text4"]); return $pk; } } return null; case Info::SET_DIFFICULTY_PACKET: $pk = new ServerDifficultyPacket(); $pk->difficulty = $packet->difficulty; return $pk; case Info::SET_PLAYER_GAMETYPE_PACKET: $packets = []; $pk = new PlayerAbilitiesPacket(); $pk->flyingSpeed = 0.05; $pk->walkingSpeed = 0.1; $pk->canFly = ($player->getGamemode() & 0x1) > 0; $pk->damageDisabled = ($player->getGamemode() & 0x1) > 0; $pk->isFlying = false; $pk->isCreative = ($player->getGamemode() & 0x1) > 0; $packets[] = $pk; $pk = new ChangeGameStatePacket(); $pk->reason = 3; $pk->value = $player->getGamemode(); $packets[] = $pk; return $packets; case Info::PLAY_STATUS_PACKET: case Info::PLAYER_LIST_PACKET: case Info::ADVENTURE_SETTINGS_PACKET: case Info::FULL_CHUNK_DATA_PACKET: case Info::BATCH_PACKET: return null; default: echo "[Send] 0x" . bin2hex(chr($packet->pid())) . "\n"; return null; } }