public function encodePacket()
 {
     $packetIDVarInt = VarInt::writeUnsignedVarInt($this->getPacketID());
     $encodedPacket = $this->encodeContents();
     $packetLengthVarInt = VarInt::writeUnsignedVarInt(strlen($encodedPacket) + $packetIDVarInt->getDataLength());
     return $packetLengthVarInt->getEncoded() . $packetIDVarInt->getEncoded() . $encodedPacket;
 }
 /**
  * Parse the raw data into the packet
  * @param $data String the raw data to parse (minus packet ID and packet length
  */
 public function fromRawData($data)
 {
     $secretLength = VarInt::readUnsignedVarInt($data);
     $data = substr($data, $secretLength->getDataLength());
     $secretData = substr($data, 0, $secretLength->getValue());
     $data = substr($data, $secretLength->getValue());
     $verifyLength = VarInt::readUnsignedVarInt($data);
     $data = substr($data, $verifyLength->getDataLength());
     $verifyData = substr($data, 0, $verifyLength->getValue());
     $this->setToken($verifyData)->setSecret($secretData);
 }
 /**
  * Called whenever there is data available on the stream
  * @param $data String the raw data
  */
 public function onData($data)
 {
     //if we're in encryption stage decrypt it first
     if ($this->secret !== null) {
         mcrypt_generic_init($this->encryptor, $this->secret, $this->secret);
         $data = mdecrypt_generic($this->encryptor, $data);
         mcrypt_generic_deinit($this->encryptor);
     }
     //attempt to parse the data as a packet
     try {
         //add the data to the current buffer
         $this->packetBuffer .= $data;
         //for as long as we have data left in the buffer
         do {
             //read the packet length from the stream
             $packetLengthVarInt = VarInt::readUnsignedVarInt($this->packetBuffer);
             //not enough data to read the packet length, wait for more data
             if ($packetLengthVarInt === false) {
                 return;
             }
             //total length of the packet is the length of the varint + it's value
             $totalLength = $packetLengthVarInt->getDataLength() + $packetLengthVarInt->getValue();
             //if we don't have enough data to read the entire packet wait for more data to enter
             $bufferLength = strlen($this->packetBuffer);
             if ($bufferLength < $totalLength) {
                 return;
             }
             //remove the packet length varint from the buffer
             $this->packetBuffer = substr($this->packetBuffer, $packetLengthVarInt->getDataLength());
             //read the packet ID from the buffer
             $packetDataWithPacketID = substr($this->packetBuffer, 0, $packetLengthVarInt->getValue());
             //remove the rest of the packet from the buffer
             $this->packetBuffer = substr($this->packetBuffer, $packetLengthVarInt->getValue());
             //read the packet ID
             $packetID = VarInt::readUnsignedVarInt($packetDataWithPacketID);
             //get the raw packet data
             $packetData = substr($packetDataWithPacketID, $packetID->getDataLength());
             $this->lastPacket = $this->currentTime();
             //trigger packet processing
             $this->processPacket($packetID->getValue(), $packetData);
             //if we have buffer left run again
         } while (strlen($this->packetBuffer) > 0);
         //if any exceptions are thrown (error parsing the packets e.t.c.) send a disconnect packet
     } catch (Exception $ex) {
         echo "EXCEPTION IN PACKET PARSING {$ex->getMessage()}\n";
         echo $ex->getTraceAsString();
         $dis = new DisconnectPacket();
         $dis->setReason('Internal Server Error: ' . $ex->getMessage());
         $this->end($dis->encodePacket());
     }
 }
 /**
  * Get the encoded contents of the packet (minus packetID/length)
  * @return String
  */
 protected function encodeContents()
 {
     $serverIDEncoded = StringType::write($this->serverID);
     $encodedPublicKey = base64_decode($this->getPublicKey());
     $publicKeyLength = VarInt::writeUnsignedVarInt(strlen($encodedPublicKey));
     $encodedToken = $this->getToken();
     $tokenLength = VarInt::writeUnsignedVarInt(strlen($encodedToken));
     return $serverIDEncoded->getEncoded() . $publicKeyLength->getEncoded() . $encodedPublicKey . $tokenLength->getEncoded() . $encodedToken;
 }
 /**
  * Parse the raw data
  * @param $data String the raw data to parse (minus packet ID and packet length
  * @throws InvalidDataException
  */
 function fromRawData($data)
 {
     $versionVarInt = VarInt::readUnsignedVarInt($data);
     $data = substr($data, $versionVarInt->getDataLength());
     $addressStringLength = VarInt::readUnsignedVarInt($data);
     $data = substr($data, $addressStringLength->getDataLength());
     $address = substr($data, 0, $addressStringLength->getValue());
     $data = substr($data, $addressStringLength->getValue());
     $portShort = unpack('nshort', substr($data, 0, 2))['short'];
     $data = substr($data, 2);
     $nextVarInt = VarInt::readUnsignedVarInt($data);
     try {
         $nextStage = Stage::get($nextVarInt->getValue());
         //disconnect if not a valid stage
         if ($nextStage != Stage::LOGIN() && $nextStage != Stage::STATUS()) {
             throw new InvalidDataException('Stage must be LOGIN or STATUS on handshake');
         }
         //set all of the data
         $this->setNextStage($nextStage)->setServerPort($portShort)->setProtocolVersion($versionVarInt->getValue())->setServerAddress($address);
     } catch (InvalidArgumentException $ex) {
         throw new InvalidDataException('Stage is not a valid number');
     }
 }