void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
    if (_shuttingDown) {
        qDebug() << "OctreeInboundPacketProcessor::processPacket() while shutting down... ignoring incoming packet";
        return;
    }

    bool debugProcessPacket = _myServer->wantsVerboseDebug();

    if (debugProcessPacket) {
        qDebug("OctreeInboundPacketProcessor::processPacket() packetData=%p packetLength=%d", &packet, packet.size());
    }

    int numBytesPacketHeader = numBytesForPacketHeader(packet);


    // Ask our tree subclass if it can handle the incoming packet...
    PacketType packetType = packetTypeForPacket(packet);
    if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
        PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket);
        _receivedPacketCount++;
        
        const unsigned char* packetData = reinterpret_cast<const unsigned char*>(packet.data());

        unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
        quint64 sentAt = (*((quint64*)(packetData + numBytesPacketHeader + sizeof(sequence))));
        quint64 arrivedAt = usecTimestampNow();
        if (sentAt > arrivedAt) {
            if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
                qDebug() << "unreasonable sentAt=" << sentAt << " usecs";
                qDebug() << "setting sentAt to arrivedAt=" << arrivedAt << " usecs";
            }
            sentAt = arrivedAt;
        }
        quint64 transitTime = arrivedAt - sentAt;
        int editsInPacket = 0;
        quint64 processTime = 0;
        quint64 lockWaitTime = 0;

        if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
            qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client";
            qDebug() << "    receivedBytes=" << packet.size();
            qDebug() << "         sequence=" << sequence;
            qDebug() << "           sentAt=" << sentAt << " usecs";
            qDebug() << "        arrivedAt=" << arrivedAt << " usecs";
            qDebug() << "      transitTime=" << transitTime << " usecs";
            qDebug() << "      sendingNode->getClockSkewUsec()=" << sendingNode->getClockSkewUsec() << " usecs";
            
            
        }
        
        if (debugProcessPacket) {
            qDebug() << "    numBytesPacketHeader=" << numBytesPacketHeader;
            qDebug() << "    sizeof(sequence)=" << sizeof(sequence);
            qDebug() << "    sizeof(sentAt)=" << sizeof(sentAt);
        }
        
        int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt);

        if (debugProcessPacket) {
            qDebug() << "    atByte=" << atByte;
            qDebug() << "    packet.size()=" << packet.size();
            if (atByte >= packet.size()) {
                qDebug() << "    ----- UNEXPECTED ---- got a packet without any edit details!!!! --------";
            }
        }
        

        unsigned char* editData = (unsigned char*)&packetData[atByte];
        while (atByte < packet.size()) {
        
            int maxSize = packet.size() - atByte;

            if (debugProcessPacket) {
                qDebug() << " --- inside while loop ---";
                qDebug() << "    maxSize=" << maxSize;
                qDebug("OctreeInboundPacketProcessor::processPacket() %c "
                       "packetData=%p packetLength=%d editData=%p atByte=%d maxSize=%d",
                        packetType, packetData, packet.size(), editData, atByte, maxSize);
            }

            quint64 startLock = usecTimestampNow();
            _myServer->getOctree()->lockForWrite();
            quint64 startProcess = usecTimestampNow();
            int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType,
                                                                                  reinterpret_cast<const unsigned char*>(packet.data()),
                                                                                  packet.size(),
                                                                                  editData, maxSize, sendingNode);

            if (debugProcessPacket) {
                qDebug() << "OctreeInboundPacketProcessor::processPacket() after processEditPacketData()..."
                                << "editDataBytesRead=" << editDataBytesRead;
            }

            _myServer->getOctree()->unlock();
            quint64 endProcess = usecTimestampNow();

            editsInPacket++;
            quint64 thisProcessTime = endProcess - startProcess;
            quint64 thisLockWaitTime = startProcess - startLock;
            processTime += thisProcessTime;
            lockWaitTime += thisLockWaitTime;

            // skip to next edit record in the packet
            editData += editDataBytesRead;
            atByte += editDataBytesRead;

            if (debugProcessPacket) {
                qDebug() << "    editDataBytesRead=" << editDataBytesRead;
                qDebug() << "    AFTER processEditPacketData atByte=" << atByte;
                qDebug() << "    AFTER processEditPacketData packet.size()=" << packet.size();
            }

        }

        if (debugProcessPacket) {
            qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %c "
                   "packetData=%p packetLength=%d editData=%p atByte=%d",
                    packetType, packetData, packet.size(), editData, atByte);
        }

        // Make sure our Node and NodeList knows we've heard from this node.
        QUuid& nodeUUID = DEFAULT_NODE_ID_REF;
        if (sendingNode) {
            sendingNode->setLastHeardMicrostamp(usecTimestampNow());
            nodeUUID = sendingNode->getUUID();
            if (debugProcessPacket) {
                qDebug() << "sender has uuid=" << nodeUUID;
            }
        } else {
            if (debugProcessPacket) {
                qDebug() << "sender has no known nodeUUID.";
            }
        }
        trackInboundPacket(nodeUUID, sequence, transitTime, editsInPacket, processTime, lockWaitTime);
    } else {
        qDebug("unknown packet ignored... packetType=%d", packetType);
    }
}
void OctreeInboundPacketProcessor::processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
    if (_shuttingDown) {
        qDebug() << "OctreeInboundPacketProcessor::processPacket() while shutting down... ignoring incoming packet";
        return;
    }

    bool debugProcessPacket = _myServer->wantsVerboseDebug();

    if (debugProcessPacket) {
        qDebug("OctreeInboundPacketProcessor::processPacket() payload=%p payloadLength=%lld",
               packet->getPayload(),
               packet->getPayloadSize());
    }

    // Ask our tree subclass if it can handle the incoming packet...
    PacketType packetType = packet->getType();
    
    if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
        PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket);
        _receivedPacketCount++;

        unsigned short int sequence;
        packet->readPrimitive(&sequence);

        quint64 sentAt;
        packet->readPrimitive(&sentAt);
        
        quint64 arrivedAt = usecTimestampNow();
        if (sentAt > arrivedAt) {
            if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
                qDebug() << "unreasonable sentAt=" << sentAt << " usecs";
                qDebug() << "setting sentAt to arrivedAt=" << arrivedAt << " usecs";
            }
            sentAt = arrivedAt;
        }

        quint64 transitTime = arrivedAt - sentAt;
        int editsInPacket = 0;
        quint64 processTime = 0;
        quint64 lockWaitTime = 0;

        if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
            qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client";
            qDebug() << "    receivedBytes=" << packet->getDataSize();
            qDebug() << "         sequence=" << sequence;
            qDebug() << "           sentAt=" << sentAt << " usecs";
            qDebug() << "        arrivedAt=" << arrivedAt << " usecs";
            qDebug() << "      transitTime=" << transitTime << " usecs";
            qDebug() << "      sendingNode->getClockSkewUsec()=" << sendingNode->getClockSkewUsec() << " usecs";


        }

        if (debugProcessPacket) {
            qDebug() << "    numBytesPacketHeader=" << NLPacket::totalHeaderSize(packetType);
            qDebug() << "    sizeof(sequence)=" << sizeof(sequence);
            qDebug() << "    sizeof(sentAt)=" << sizeof(sentAt);
            qDebug() << "    atByte (in payload)=" << packet->pos();
            qDebug() << "    payload size=" << packet->getPayloadSize();

            if (!packet->bytesLeftToRead()) {
                qDebug() << "    ----- UNEXPECTED ---- got a packet without any edit details!!!! --------";
            }
        }
        
        const unsigned char* editData = nullptr;
        
        while (packet->bytesLeftToRead() > 0) {

            editData = reinterpret_cast<const unsigned char*>(packet->getPayload() + packet->pos());

            int maxSize = packet->bytesLeftToRead();

            if (debugProcessPacket) {
                qDebug() << " --- inside while loop ---";
                qDebug() << "    maxSize=" << maxSize;
                qDebug("OctreeInboundPacketProcessor::processPacket() %hhu "
                       "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld maxSize=%d",
                        packetType, packet->getPayload(), packet->getPayloadSize(), editData,
                        packet->pos(), maxSize);
            }

            quint64 startProcess, startLock = usecTimestampNow();
            int editDataBytesRead;
            _myServer->getOctree()->withWriteLock([&] {
                startProcess = usecTimestampNow();
                editDataBytesRead =
                    _myServer->getOctree()->processEditPacketData(*packet, editData, maxSize, sendingNode);
            });
            quint64 endProcess = usecTimestampNow();

            if (debugProcessPacket) {
                qDebug() << "OctreeInboundPacketProcessor::processPacket() after processEditPacketData()..."
                    << "editDataBytesRead=" << editDataBytesRead;
            }

            editsInPacket++;
            quint64 thisProcessTime = endProcess - startProcess;
            quint64 thisLockWaitTime = startProcess - startLock;
            processTime += thisProcessTime;
            lockWaitTime += thisLockWaitTime;

            // skip to next edit record in the packet
            packet->seek(packet->pos() + editDataBytesRead);

            if (debugProcessPacket) {
                qDebug() << "    editDataBytesRead=" << editDataBytesRead;
                qDebug() << "    AFTER processEditPacketData payload position=" << packet->pos();
                qDebug() << "    AFTER processEditPacketData payload size=" << packet->getPayloadSize();
            }

        }

        if (debugProcessPacket) {
            qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %hhu "
                   "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld",
                    packetType, packet->getPayload(), packet->getPayloadSize(), editData, packet->pos());
        }

        // Make sure our Node and NodeList knows we've heard from this node.
        QUuid& nodeUUID = DEFAULT_NODE_ID_REF;
        if (sendingNode) {
            nodeUUID = sendingNode->getUUID();
            if (debugProcessPacket) {
                qDebug() << "sender has uuid=" << nodeUUID;
            }
        } else {
            if (debugProcessPacket) {
                qDebug() << "sender has no known nodeUUID.";
            }
        }
        trackInboundPacket(nodeUUID, sequence, transitTime, editsInPacket, processTime, lockWaitTime);
    } else {
        qDebug("unknown packet ignored... packetType=%hhu", packetType);
    }
}