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');
        }
    }