public function handle($address, $port, $packet) { $offset = 2; $packetType = ord($packet[$offset++]); $sessionID = Binary::readInt(substr($packet, $offset, 4)); $offset += 4; $payload = substr($packet, $offset); switch ($packetType) { case self::HANDSHAKE: //Handshake $reply = chr(self::HANDSHAKE); $reply .= Binary::writeInt($sessionID); $reply .= self::getTokenString($this->token, $address) . ""; $this->server->getNetwork()->sendPacket($address, $port, $reply); break; case self::STATISTICS: //Stat $token = Binary::readInt(substr($payload, 0, 4)); if ($token !== self::getTokenString($this->token, $address) and $token !== self::getTokenString($this->lastToken, $address)) { break; } $reply = chr(self::STATISTICS); $reply .= Binary::writeInt($sessionID); if ($this->timeout < microtime(true)) { $this->regenerateInfo(); } if (strlen($payload) === 8) { $reply .= $this->longData; } else { $reply .= $this->shortData; } $this->server->getNetwork()->sendPacket($address, $port, $reply); break; } }
public function readChunk($x, $z, $generate = true, $forward = false) { $index = self::getChunkOffset($x, $z); if ($index < 0 or $index >= 4096) { return null; } $this->lastUsed = time(); if (!$this->isChunkGenerated($index)) { if ($generate === true) { //Allocate space $this->locationTable[$index][0] = ++$this->lastSector; $this->locationTable[$index][1] = 1; fseek($this->filePointer, $this->locationTable[$index][0] << 12); fwrite($this->filePointer, str_pad(Binary::writeInt(-1) . chr(self::COMPRESSION_ZLIB), 4096, "", STR_PAD_RIGHT)); $this->writeLocationIndex($index); } else { return null; } } fseek($this->filePointer, $this->locationTable[$index][0] << 12); $length = Binary::readInt(fread($this->filePointer, 4)); $compression = ord(fgetc($this->filePointer)); if ($length <= 0 or $length >= self::MAX_SECTOR_LENGTH) { //Not yet generated / corrupted if ($length >= self::MAX_SECTOR_LENGTH) { $this->locationTable[$index][0] = ++$this->lastSector; $this->locationTable[$index][1] = 1; MainLogger::getLogger()->error("Corrupted chunk header detected"); } $this->generateChunk($x, $z); fseek($this->filePointer, $this->locationTable[$index][0] << 12); $length = Binary::readInt(fread($this->filePointer, 4)); $compression = ord(fgetc($this->filePointer)); } if ($length > $this->locationTable[$index][1] << 12) { //Invalid chunk, bigger than defined number of sectors MainLogger::getLogger()->error("Corrupted bigger chunk detected"); $this->locationTable[$index][1] = $length >> 12; $this->writeLocationIndex($index); } elseif ($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP) { MainLogger::getLogger()->error("Invalid compression type"); return null; } $chunk = Chunk::fromBinary(fread($this->filePointer, $length - 1), $this->levelProvider); if ($chunk instanceof Chunk) { return $chunk; } elseif ($forward === false) { MainLogger::getLogger()->error("Corrupted chunk detected"); $this->generateChunk($x, $z); return $this->readChunk($x, $z, $generate, true); } else { return null; } }
public function __construct($level, CompoundTag $nbt = null) { if ($nbt === null) { $this->provider = $level; $this->nbt = new CompoundTag("Level", []); return; } $this->nbt = $nbt; if (!isset($this->nbt->Entities) or !$this->nbt->Entities instanceof ListTag) { $this->nbt->Entities = new ListTag("Entities", []); $this->nbt->Entities->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->TileEntities) or !$this->nbt->TileEntities instanceof ListTag) { $this->nbt->TileEntities = new ListTag("TileEntities", []); $this->nbt->TileEntities->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->TileTicks) or !$this->nbt->TileTicks instanceof ListTag) { $this->nbt->TileTicks = new ListTag("TileTicks", []); $this->nbt->TileTicks->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->Sections) or !$this->nbt->Sections instanceof ListTag) { $this->nbt->Sections = new ListTag("Sections", []); $this->nbt->Sections->setTagType(NBT::TAG_Compound); } if (!isset($this->nbt->BiomeColors) or !$this->nbt->BiomeColors instanceof IntArrayTag) { $this->nbt->BiomeColors = new IntArrayTag("BiomeColors", array_fill(0, 256, 0)); } if (!isset($this->nbt->HeightMap) or !$this->nbt->HeightMap instanceof IntArrayTag) { $this->nbt->HeightMap = new IntArrayTag("HeightMap", array_fill(0, 256, 0)); } $sections = []; foreach ($this->nbt->Sections as $section) { if ($section instanceof CompoundTag) { $y = (int) $section["Y"]; if ($y < 8) { $sections[$y] = new ChunkSection($section); } } } for ($y = 0; $y < 8; ++$y) { if (!isset($sections[$y])) { $sections[$y] = new EmptyChunkSection($y); } } $extraData = []; if (!isset($this->nbt->ExtraData) or !$this->nbt->ExtraData instanceof ByteArrayTag) { $this->nbt->ExtraData = new ByteArrayTag("ExtraData", Binary::writeInt(0)); } else { $stream = new BinaryStream($this->nbt->ExtraData->getValue()); $count = $stream->getInt(); for ($i = 0; $i < $count; ++$i) { $key = $stream->getInt(); $extraData[$key] = $stream->getShort(); } } parent::__construct($level, (int) $this->nbt["xPos"], (int) $this->nbt["zPos"], $sections, $this->nbt->BiomeColors->getValue(), $this->nbt->HeightMap->getValue(), $this->nbt->Entities->getValue(), $this->nbt->TileEntities->getValue()); if (isset($this->nbt->Biomes)) { $this->checkOldBiomes($this->nbt->Biomes->getValue()); unset($this->nbt->Biomes); } unset($this->nbt->Sections, $this->nbt->ExtraData); }
public function putInt($v) { $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeInt($v) : Binary::writeLInt($v); }
public function saveChunk($X, $Z, $force = false) { $X = (int) $X; $Z = (int) $Z; if (!$this->isChunkLoaded($X, $Z)) { return false; } $index = self::getIndex($X, $Z); if ($force !== true and (!isset($this->chunkChange[$index]) or $this->chunkChange[$index][-1] === false)) { //No changes in chunk return true; } $path = $this->getChunkPath($X, $Z); if (!file_exists(dirname($path))) { @mkdir(dirname($path), 0755); } $bitmap = 0; $this->cleanChunk($X, $Z); for ($Y = 0; $Y < 8; ++$Y) { if ($this->chunks[$index][$Y] !== false and (isset($this->chunkChange[$index][$Y]) and $this->chunkChange[$index][$Y] === 0 or !$this->isMiniChunkEmpty($X, $Z, $Y))) { $bitmap |= 1 << $Y; } else { $this->chunks[$index][$Y] = false; } $this->chunkChange[$index][$Y] = 0; } $this->chunkInfo[$index][0] = $bitmap; $this->chunkChange[$index][-1] = false; $chunk = ""; $chunk .= chr($bitmap); $chunk .= Binary::writeInt($this->chunkInfo[$index][1]); $namedtag = new NBT(NBT::BIG_ENDIAN); $namedtag->setData($this->chunkInfo[$index][2]); $namedtag = $namedtag->write(); $chunk .= Binary::writeInt(strlen($namedtag)) . $namedtag; $chunk .= $this->chunkInfo[$index][3]; //biomes for ($Y = 0; $Y < 8; ++$Y) { $t = 1 << $Y; if (($bitmap & $t) === $t) { $chunk .= $this->chunks[$index][$Y]; } } file_put_contents($path, zlib_encode($chunk, self::ZLIB_ENCODING, self::ZLIB_LEVEL)); return true; }
public function toFastBinary() { $biomeColors = pack("N*", ...$this->getBiomeColorArray()); $heightMap = pack("N*", ...$this->getHeightMapArray()); return Binary::writeInt($this->x) . Binary::writeInt($this->z) . $this->getBlockIdArray() . $this->getBlockDataArray() . $this->getBlockSkyLightArray() . $this->getBlockLightArray() . $this->getBiomeIdArray() . $biomeColors . $heightMap . chr(($this->isPopulated() ? 1 << 1 : 0) + ($this->isGenerated() ? 1 : 0)); }
/** * Broadcasts a list of packets in a batch to a list of players * * @param Player[] $players * @param DataPacket[]|string $packets * @param bool $forceSync */ public function batchPackets(array $players, array $packets, $forceSync = true) { $str = ""; foreach ($packets as $p) { if ($p instanceof DataPacket) { if (!$p->isEncoded) { $p->encode(); } $str .= Binary::writeInt(strlen($p->buffer)) . $p->buffer; } else { $str .= Binary::writeInt(strlen($p)) . $p; } } $targets = []; foreach ($players as $p) { $targets[] = $this->identifiers[spl_object_hash($p)]; } $this->broadcastPacketsCallback(zlib_encode($str, ZLIB_ENCODING_DEFLATE, $this->networkCompressionLevel), $targets); }
/** * Broadcasts a list of packets in a batch to a list of players * * @param Player[] $players * @param DataPacket[]|string $packets * @param bool $forceSync * @param int $channel */ public function batchPackets(array $players, array $packets, $forceSync = false, $channel = 0) { Timings::$playerNetworkTimer->startTiming(); $str = ""; foreach ($packets as $p) { if ($p instanceof DataPacket) { if (!$p->isEncoded) { $p->encode(); } $str .= Binary::writeInt(strlen($p->buffer)) . $p->buffer; } else { $str .= Binary::writeInt(strlen($p)) . $p; } } $targets = []; foreach ($players as $p) { if ($p->isConnected()) { $targets[] = $this->identifiers[spl_object_hash($p)]; } } if (!$forceSync and $this->networkCompressionAsync) { $task = new CompressBatchedTask($str, $targets, $this->networkCompressionLevel, $channel); $this->getScheduler()->scheduleAsyncTask($task); } else { $this->broadcastPacketsCallback(zlib_encode($str, ZLIB_ENCODING_DEFLATE, $this->networkCompressionLevel), $targets, $channel); } Timings::$playerNetworkTimer->stopTiming(); }
public static function randomUUID() { return Utils::toUUID(Binary::writeInt(time()) . Binary::writeShort(getmypid()) . Binary::writeShort(getmyuid()) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)), 2); }
public static function compressName($name) { $name = strtolower($name); // [0-9a-z_]{3,16} $output = 0; for ($offset = 0; $offset < strlen($name); $offset++) { $order = ord(substr($name, $offset, 1)); $zero = ord("0"); $alpha = ord("a"); $ord = $order - $zero; $alphaOrd = $order - $alpha; if (0 <= $ord and $ord <= 9) { $output += $ord; } elseif (0 <= $alphaOrd and $alphaOrd <= 25) { $output += $alphaOrd + 10; } elseif ($order === ord("_")) { $output += 36; } $output <<= 6; } $out = Binary::writeInt($output & 0xffffffff); $output >>= 32; $out = Binary::writeLong($output) . $out; return $out; }
public function putInt($v, bool $network = false) { if ($network === true) { $this->buffer .= Binary::writeVarInt($v); } else { $this->buffer .= $this->endianness === self::BIG_ENDIAN ? Binary::writeInt($v) : Binary::writeLInt($v); } }
protected function receiveChunk($levelID, FullChunk $chunk) { if (($level = $this->server->getLevel($levelID)) instanceof Level) { $level->generateChunkCallback($chunk->getX(), $chunk->getZ(), $chunk); } else { $buffer = chr(GenerationManager::PACKET_CLOSE_LEVEL) . Binary::writeInt($levelID); $this->generationThread->pushMainToThreadPacket($buffer); } }
public function writePacket($data) { @socket_write($this->socket->getSocket(), Binary::writeInt(strlen($data)) . $data); }
public function appendInt($v) { $this->buffer .= Binary::writeInt($v); }
public function sendChunk($levelID, FullChunk $chunk) { $binary = chr(self::PACKET_SEND_CHUNK) . Binary::writeInt($levelID) . chr(strlen($class = get_class($chunk))) . $class . $chunk->toBinary(); $this->thread->pushThreadToMainPacket($binary); }
public function handle($address, $port, $packet) { $offset = 2; $packetType = ord($packet[$offset++]); $sessionID = Binary::readInt(substr($packet, $offset, 4)); $offset += 4; $payload = substr($packet, $offset); switch ($packetType) { case self::HANDSHAKE: //Handshake $reply = chr(self::HANDSHAKE); $reply .= Binary::writeInt($sessionID); $reply .= self::getTokenString($this->token, $address) . ""; $this->server->sendPacket($address, $port, $reply); break; case self::STATISTICS: //Stat $token = Binary::readInt(substr($payload, 0, 4)); if ($token !== self::getTokenString($this->token, $address) and $token !== self::getTokenString($this->lastToken, $address)) { break; } $reply = chr(self::STATISTICS); $reply .= Binary::writeInt($sessionID); if (strlen($payload) === 8) { if ($this->timeout < microtime(true)) { $this->regenerateInfo(); } $reply .= $this->longData; } else { $reply .= $this->server->getServerName() . "" . (($this->server->getGamemode() & 0x1) === 0 ? "SMP" : "CMP") . "" . ($this->server->getDefaultLevel() === null ? "unknown" : $this->server->getDefaultLevel()->getName()) . "" . count($this->server->getOnlinePlayers()) . "" . $this->server->getMaxPlayers() . "" . Binary::writeLShort($this->server->getPort()) . $this->server->getIp() . ""; } $this->server->sendPacket($address, $port, $reply); break; } }
protected function createBlank() { fseek($this->filePointer, 0); ftruncate($this->filePointer, 0); $this->lastSector = 1; $table = ""; for ($i = 0; $i < 1024; ++$i) { $this->locationTable[$i] = [0, 0]; $table .= Binary::writeInt(0); } $time = time(); for ($i = 0; $i < 1024; ++$i) { $this->locationTable[$i][2] = $time; $table .= Binary::writeInt($time); } fwrite($this->filePointer, $table, 4096 * 2); }
protected function putInt($v) { $this->buffer .= Binary::writeInt($v); }
public function putInt($v) { $this->buffer .= Binary::writeInt($v); }
protected function writeLocationIndex($index) { fseek($this->filePointer, $index << 2); fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index][0] << 8 | $this->locationTable[$index][1]), 4); fseek($this->filePointer, 4096 + ($index << 2)); fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index][2]), 4); }