Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support entity properties > 1 MTU #830

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions assignment-client/src/Agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Agent::Agent(ReceivedMessage& message) :
{ PacketType::MixedAudio, PacketType::SilentAudioFrame },
PacketReceiver::makeUnsourcedListenerReference<Agent>(this, &Agent::handleAudioPacket));
packetReceiver.registerListenerForTypes(
{ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
{ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityDataLarge, PacketType::EntityErase },
PacketReceiver::makeSourcedListenerReference<Agent>(this, &Agent::handleOctreePacket));
packetReceiver.registerListener(PacketType::SelectedAudioFormat,
PacketReceiver::makeUnsourcedListenerReference<Agent>(this, &Agent::handleSelectedAudioFormat));
Expand Down Expand Up @@ -168,7 +168,7 @@ void Agent::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNo
packetType = message->getType();
} // fall through to piggyback message

if (packetType == PacketType::EntityData) {
if (packetType == PacketType::EntityData || packetType == PacketType::EntityDataLarge) {
_entityViewer.processDatagram(*message, senderNode);
} else if (packetType == PacketType::EntityErase) {
_entityViewer.processEraseMessage(*message, senderNode);
Expand Down
3 changes: 2 additions & 1 deletion assignment-client/src/avatars/AvatarMixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
PacketReceiver::makeSourcedListenerReference<AvatarMixer>(this, &AvatarMixer::queueIncomingPacket));
packetReceiver.registerListener(PacketType::BulkAvatarTraitsAck,
PacketReceiver::makeSourcedListenerReference<AvatarMixer>(this, &AvatarMixer::queueIncomingPacket));
packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityDataLarge, PacketType::EntityErase },
PacketReceiver::makeSourcedListenerReference<AvatarMixer>(this, &AvatarMixer::handleOctreePacket));

packetReceiver.registerListenerForTypes({
Expand Down Expand Up @@ -1123,6 +1123,7 @@ void AvatarMixer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, Sh
}

case PacketType::EntityData:
case PacketType::EntityDataLarge:
_entityViewer.processDatagram(*message, senderNode);
break;

Expand Down
9 changes: 6 additions & 3 deletions assignment-client/src/avatars/ScriptableAvatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ void ScriptableAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityDa
OctreePacketData packetData(false, AvatarTraits::MAXIMUM_TRAIT_SIZE);
EncodeBitstreamParams params;
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
EntityPropertyList firstDidntFitProperty;
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra, firstDidntFitProperty);

if (appendState == OctreeElement::COMPLETED) {
_entities[id] = entity;
Expand Down Expand Up @@ -432,7 +433,8 @@ void ScriptableAvatar::updateAvatarEntity(const QUuid& entityID, const QByteArra
OctreePacketData packetData(false, AvatarTraits::MAXIMUM_TRAIT_SIZE);
EncodeBitstreamParams params;
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
EntityPropertyList firstDidntFitProperty;
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra, firstDidntFitProperty);

if (appendState == OctreeElement::COMPLETED) {
_entities[entityID] = entity;
Expand All @@ -448,7 +450,8 @@ void ScriptableAvatar::updateAvatarEntity(const QUuid& entityID, const QByteArra
OctreePacketData packetData(false, AvatarTraits::MAXIMUM_TRAIT_SIZE);
EncodeBitstreamParams params;
EntityTreeElementExtraEncodeDataPointer extra { nullptr };
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra);
EntityPropertyList firstDidntFitProperty;
OctreeElement::AppendState appendState = entity->appendEntityData(&packetData, params, extra, firstDidntFitProperty);

if (appendState == OctreeElement::COMPLETED) {
QByteArray tempArray((const char*)packetData.getUncompressedData(), packetData.getUncompressedSize());
Expand Down
1 change: 1 addition & 0 deletions assignment-client/src/entities/EntityServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ EntityServer::EntityServer(ReceivedMessage& message) :
packetReceiver.registerListenerForTypes({ PacketType::EntityAdd,
PacketType::EntityClone,
PacketType::EntityEdit,
PacketType::EntityEditLarge,
PacketType::EntityErase,
PacketType::EntityPhysics },
PacketReceiver::makeSourcedListenerReference<EntityServer>(this, &EntityServer::handleEntityPacket));
Expand Down
107 changes: 71 additions & 36 deletions assignment-client/src/entities/EntityTreeSendThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,34 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
}
}

void addPacketHeader(OctreePacketData& packetData, bool includeExistsBits, OctreeServer *octreeServer, const uint16_t numEntities, int32_t& numEntitiesOffset) {
// This is the beginning of a new packet.
// We pack minimal data for this to be accepted as an OctreeElement payload for the root element.
// The Octree header bytes look like this:
//
// 0x00 octalcode for root
// 0x00 colors (1 bit where recipient should call: child->readElementDataFromBuffer())
// 0xXX childrenInTreeMask (when params.includeExistsBits is true: 1 bit where child is existant)
// 0x00 childrenInBufferMask (1 bit where recipient should call: child->readElementData() recursively)
const uint8_t zeroByte = 0;
packetData.appendValue(zeroByte); // octalcode
packetData.appendValue(zeroByte); // colors
if (includeExistsBits) {
uint8_t childrenExistBits = 0;
EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(octreeServer->getOctree()->getRoot());
for (int32_t i = 0; i < NUMBER_OF_CHILDREN; ++i) {
if (root->getChildAtIndex(i)) {
childrenExistBits += (1 << i);
}
}
packetData.appendValue(childrenExistBits); // childrenInTreeMask
}
packetData.appendValue(zeroByte); // childrenInBufferMask

numEntitiesOffset = packetData.getUncompressedByteOffset();
packetData.appendValue(numEntities);
}

bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) {
if (_sendQueue.empty()) {
params.stopReason = EncodeBitstreamParams::FINISHED;
Expand All @@ -325,38 +353,15 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream
}
quint64 encodeStart = usecTimestampNow();
if (!_packetData.hasContent()) {
// This is the beginning of a new packet.
// We pack minimal data for this to be accepted as an OctreeElement payload for the root element.
// The Octree header bytes look like this:
//
// 0x00 octalcode for root
// 0x00 colors (1 bit where recipient should call: child->readElementDataFromBuffer())
// 0xXX childrenInTreeMask (when params.includeExistsBits is true: 1 bit where child is existant)
// 0x00 childrenInBufferMask (1 bit where recipient should call: child->readElementData() recursively)
const uint8_t zeroByte = 0;
_packetData.appendValue(zeroByte); // octalcode
_packetData.appendValue(zeroByte); // colors
if (params.includeExistsBits) {
uint8_t childrenExistBits = 0;
EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(_myServer->getOctree()->getRoot());
for (int32_t i = 0; i < NUMBER_OF_CHILDREN; ++i) {
if (root->getChildAtIndex(i)) {
childrenExistBits += (1 << i);
}
}
_packetData.appendValue(childrenExistBits); // childrenInTreeMask
}
_packetData.appendValue(zeroByte); // childrenInBufferMask

// Pack zero for numEntities.
// But before we do: grab current byteOffset so we can come back later
// Also grab current byteOffset so we can come back later
// and update this with the real number.
_numEntities = 0;
_numEntitiesOffset = _packetData.getUncompressedByteOffset();
_packetData.appendValue(_numEntities);
addPacketHeader(_packetData, params.includeExistsBits, _myServer, _numEntities, _numEntitiesOffset);
}

LevelDetails entitiesLevel = _packetData.startLevel();
LevelDetails entitiesLargeLevel = _packetDataLarge.startLevel();;
uint64_t sendTime = usecTimestampNow();
auto nodeData = static_cast<OctreeQueryNode*>(params.nodeData);
nodeData->stats.encodeStarted();
Expand All @@ -371,18 +376,41 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream
// also send if we previously matched since this represents change to a matched item.
bool entityMatchesFilters = entity->matchesJSONFilters(jsonFilters);
bool entityPreviouslyMatchedFilter = entityNodeData->sentFilteredEntity(entityID);
bool entityHasPropsToSend = !_extraEncodeData->entities.contains(entityID) || !_extraEncodeData->entities.value(entityID).isEmpty();

if (entityMatchesFilters || entityNodeData->isEntityFlaggedAsExtra(entityID) || entityPreviouslyMatchedFilter) {
if ((entityMatchesFilters || entityNodeData->isEntityFlaggedAsExtra(entityID) || entityPreviouslyMatchedFilter) && entityHasPropsToSend) {
if (!jsonFilters.isEmpty() && entityMatchesFilters) {
// Record explicitly filtered-in entity so that extra entities can be flagged.
entityNodeData->insertSentFilteredEntity(entityID);
}
OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData, entityNode->getCanGetAndSetPrivateUserData());
EntityPropertyList firstDidntFitProperty = (EntityPropertyList)0;
OctreeElement::AppendState appendEntityState = entity->appendEntityData(&_packetData, params, _extraEncodeData, firstDidntFitProperty, entityNode->getCanGetAndSetPrivateUserData());

if (appendEntityState == OctreeElement::NONE && firstDidntFitProperty != 0) {
if (_numEntities != 0) {
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
break;
}

if (appendEntityState != OctreeElement::COMPLETED) {
if (appendEntityState == OctreeElement::PARTIAL) {
++_numEntities;
EntityPropertyList targetProperty = firstDidntFitProperty;
unsigned int bufferMultiplier = 2;
int32_t numEntitiesOffset;
while (true) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appendEntityData still doesn't report how much it overran the buffer by, so we have to do this loop to search for the right size. this seems dangerous (since there's no upper limit) and slow (since we could know the exact right size after the first attempt). we should definitely fix the latter issue in a followup, but I'm not sure how bad the lack of an upper limit really is.

_packetDataLarge.changeSettings(true, bufferMultiplier * _packetData.getTargetSize());
addPacketHeader(_packetDataLarge, params.includeExistsBits, _myServer, 1, numEntitiesOffset);
// TODO: should this just handle the single property (via _extraEncodeData) or should it just send everything since it's big anyways?
firstDidntFitProperty = (EntityPropertyList)0;
appendEntityState = entity->appendEntityData(&_packetDataLarge, params, _extraEncodeData, firstDidntFitProperty, entityNode->getCanGetAndSetPrivateUserData());
if (firstDidntFitProperty != targetProperty) {
// We don't update _numEntities here, as we only use that for individual packets
params.stopReason = EncodeBitstreamParams::SENT_LARGE;
break;
}
bufferMultiplier++;
}
break;
} else if (appendEntityState == OctreeElement::PARTIAL) {
++_numEntities;
params.stopReason = EncodeBitstreamParams::DIDNT_FIT;
break;
}
Expand All @@ -407,13 +435,20 @@ bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstream
_extraEncodeData->entities.clear();
}

if (_numEntities == 0) {
if (params.stopReason != EncodeBitstreamParams::SENT_LARGE) {
_packetDataLarge.discardLevel(entitiesLargeLevel);
if (_numEntities == 0) {
_packetData.discardLevel(entitiesLevel);
OctreeServer::trackEncodeTime((float)(usecTimestampNow() - encodeStart));
return false;
}
_packetData.endLevel(entitiesLevel);
_packetData.updatePriorBytes(_numEntitiesOffset, (const unsigned char*)&_numEntities, sizeof(_numEntities));
} else {
_packetData.discardLevel(entitiesLevel);
OctreeServer::trackEncodeTime((float)(usecTimestampNow() - encodeStart));
return false;
_packetDataLarge.endLevel(entitiesLargeLevel);
// _paacketDataLarge already has numEntities (1) set
}
_packetData.endLevel(entitiesLevel);
_packetData.updatePriorBytes(_numEntitiesOffset, (const unsigned char*)&_numEntities, sizeof(_numEntities));
OctreeServer::trackEncodeTime((float)(usecTimestampNow() - encodeStart));
return true;
}
Expand Down
Loading
Loading