Merge pull request #13704 from SimonWalton-HiFi/delay-physics

Enable physics after ES indicates all nearby entities received
This commit is contained in:
Simon Walton 2018-08-01 18:15:00 -07:00 committed by GitHub
commit 88fafc7a1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 185 additions and 38 deletions

View file

@ -17,7 +17,6 @@
#include "EntityServer.h"
EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) :
OctreeSendThread(myServer, node)
{
@ -100,7 +99,7 @@ void EntityTreeSendThread::preDistributionProcessing() {
}
}
void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
bool viewFrustumChanged, bool isFullScene) {
if (viewFrustumChanged || _traversal.finished()) {
EntityTreeElementPointer root = std::dynamic_pointer_cast<EntityTreeElement>(_myServer->getOctree()->getRoot());
@ -111,7 +110,7 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST);
newView.lodScaleFactor = powf(2.0f, lodLevelOffset);
startNewTraversal(newView, root);
// When the viewFrustum changed the sort order may be incorrect, so we re-sort
@ -156,7 +155,20 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
OctreeServer::trackTreeTraverseTime((float)(usecTimestampNow() - startTime));
}
OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene);
bool sendComplete = OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene);
if (sendComplete && nodeData->wantReportInitialCompletion() && _traversal.finished()) {
// Dealt with all nearby entities.
nodeData->setReportInitialCompletion(false);
// Send EntityQueryInitialResultsComplete reliable packet ...
auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete,
sizeof(OCTREE_PACKET_SEQUENCE), true);
initialCompletion->writePrimitive(OCTREE_PACKET_SEQUENCE(nodeData->getSequenceNumber() - 1U));
DependencyManager::get<NodeList>()->sendPacket(std::move(initialCompletion), *node);
}
return sendComplete;
}
bool EntityTreeSendThread::addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID,
@ -301,6 +313,7 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En
bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) {
if (_sendQueue.empty()) {
params.stopReason = EncodeBitstreamParams::FINISHED;
OctreeServer::trackEncodeTime(OctreeServer::SKIP_TIME);
return false;
}

View file

@ -31,7 +31,7 @@ public:
EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node);
protected:
void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
bool traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
bool viewFrustumChanged, bool isFullScene) override;
private slots:

View file

@ -211,10 +211,9 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode*
//_totalWastedBytes += 0;
_trueBytesSent += numBytes;
numPackets++;
NLPacket& sentPacket = nodeData->getPacket();
if (debug) {
NLPacket& sentPacket = nodeData->getPacket();
sentPacket.seek(sizeof(OCTREE_PACKET_FLAGS));
OCTREE_PACKET_SEQUENCE sequence;
@ -231,9 +230,9 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode*
// second packet
OctreeServer::didCallWriteDatagram(this);
DependencyManager::get<NodeList>()->sendUnreliablePacket(nodeData->getPacket(), *node);
DependencyManager::get<NodeList>()->sendUnreliablePacket(sentPacket, *node);
numBytes = nodeData->getPacket().getDataSize();
numBytes = sentPacket.getDataSize();
_totalBytes += numBytes;
_totalPackets++;
// we count wasted bytes here because we were unable to fit the stats packet
@ -243,8 +242,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode*
numPackets++;
if (debug) {
NLPacket& sentPacket = nodeData->getPacket();
sentPacket.seek(sizeof(OCTREE_PACKET_FLAGS));
OCTREE_PACKET_SEQUENCE sequence;
@ -265,9 +262,10 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode*
if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) {
// just send the octree packet
OctreeServer::didCallWriteDatagram(this);
DependencyManager::get<NodeList>()->sendUnreliablePacket(nodeData->getPacket(), *node);
NLPacket& sentPacket = nodeData->getPacket();
DependencyManager::get<NodeList>()->sendUnreliablePacket(sentPacket, *node);
int numBytes = nodeData->getPacket().getDataSize();
int numBytes = sentPacket.getDataSize();
_totalBytes += numBytes;
_totalPackets++;
int thisWastedBytes = udt::MAX_PACKET_SIZE - numBytes;
@ -276,8 +274,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode*
_trueBytesSent += numBytes;
if (debug) {
NLPacket& sentPacket = nodeData->getPacket();
sentPacket.seek(sizeof(OCTREE_PACKET_FLAGS));
OCTREE_PACKET_SEQUENCE sequence;
@ -434,7 +430,7 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode*
return _truePacketsSent;
}
void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) {
bool OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) {
// calculate max number of packets that can be sent during this interval
int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxQueryPacketsPerSecond() / INTERVALS_PER_SECOND));
int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval());
@ -517,4 +513,6 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre
<< " maxPacketsPerInterval = " << maxPacketsPerInterval
<< " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval;
}
return params.stopReason == EncodeBitstreamParams::FINISHED;
}

View file

@ -52,7 +52,7 @@ protected:
/// Implements generic processing behavior for this thread.
virtual bool process() override;
virtual void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
virtual bool traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
bool viewFrustumChanged, bool isFullScene);
virtual bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) = 0;

View file

@ -378,6 +378,7 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI
static const uint32_t INVALID_FRAME = UINT32_MAX;
static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation
static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entities before physics enabled
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
@ -5499,12 +5500,14 @@ void Application::update(float deltaTime) {
// we haven't yet enabled physics. we wait until we think we have all the collision information
// for nearby entities before starting bullet up.
quint64 now = usecTimestampNow();
const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND;
if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) {
// Check for flagged EntityData having arrived.
auto entityTreeRenderer = getEntities();
if (isServerlessMode() ||
(entityTreeRenderer && _octreeProcessor.octreeSequenceIsComplete(entityTreeRenderer->getLastOctreeMessageSequence()) )) {
// we've received a new full-scene octree stats packet, or it's been long enough to try again anyway
_lastPhysicsCheckTime = now;
_fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter;
_lastQueriedViews.clear(); // Force new view.
// process octree stats packets are sent in between full sends of a scene (this isn't currently true).
// We keep physics disabled until we've received a full scene and everything near the avatar in that
@ -6153,11 +6156,23 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) {
return; // bail early if settings are not loaded
}
_octreeQuery.setConicalViews(_conicalViews);
const bool isModifiedQuery = !_physicsEnabled;
if (isModifiedQuery) {
// Create modified view that is a simple sphere.
ConicalViewFrustum sphericalView;
sphericalView.setSimpleRadius(INITIAL_QUERY_RADIUS);
_octreeQuery.setConicalViews({ sphericalView });
_octreeQuery.setOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE);
static constexpr float MIN_LOD_ADJUST = -20.0f;
_octreeQuery.setBoundaryLevelAdjust(MIN_LOD_ADJUST);
} else {
_octreeQuery.setConicalViews(_conicalViews);
auto lodManager = DependencyManager::get<LODManager>();
_octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale());
_octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust());
}
_octreeQuery.setReportInitialCompletion(isModifiedQuery);
auto lodManager = DependencyManager::get<LODManager>();
_octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale());
_octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust());
auto nodeList = DependencyManager::get<NodeList>();
@ -6305,6 +6320,7 @@ void Application::clearDomainOctreeDetails() {
_octreeServerSceneStats.clear();
});
_octreeProcessor.resetCompletionSequenceNumber();
// reset the model renderer
getEntities()->clear();

View file

@ -21,9 +21,9 @@ OctreePacketProcessor::OctreePacketProcessor() {
setObjectName("Octree Packet Processor");
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
packetReceiver.registerDirectListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
this, "handleOctreePacket");
const PacketReceiver::PacketTypeList octreePackets =
{ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase, PacketType::EntityQueryInitialResultsComplete };
packetReceiver.registerDirectListenerForTypes(octreePackets, this, "handleOctreePacket");
}
void OctreePacketProcessor::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
@ -111,8 +111,36 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
}
} break;
case PacketType::EntityQueryInitialResultsComplete: {
// Read sequence #
OCTREE_PACKET_SEQUENCE completionNumber;
message->readPrimitive(&completionNumber);
_completionSequenceNumber = completionNumber;
} break;
default: {
// nothing to do
} break;
}
}
void OctreePacketProcessor::resetCompletionSequenceNumber() {
_completionSequenceNumber = INVALID_SEQUENCE;
}
namespace {
template<typename T> bool lessThanWraparound(int a, int b) {
constexpr int MAX_T_VALUE = std::numeric_limits<T>::max();
if (b <= a) {
b += MAX_T_VALUE;
}
return (b - a) < (MAX_T_VALUE / 2);
}
}
bool OctreePacketProcessor::octreeSequenceIsComplete(int sequenceNumber) const {
// If we've received the flagged seq # and the current one is >= it.
return _completionSequenceNumber != INVALID_SEQUENCE &&
!lessThanWraparound<OCTREE_PACKET_SEQUENCE>(sequenceNumber, _completionSequenceNumber);
}

View file

@ -22,13 +22,23 @@ class OctreePacketProcessor : public ReceivedPacketProcessor {
public:
OctreePacketProcessor();
bool octreeSequenceIsComplete(int sequenceNumber) const;
signals:
void packetVersionMismatch();
public slots:
void resetCompletionSequenceNumber();
protected:
virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
private slots:
void handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
private:
static constexpr int INVALID_SEQUENCE = -1;
std::atomic<int> _completionSequenceNumber { INVALID_SEQUENCE };
};
#endif // hifi_OctreePacketProcessor_h

View file

@ -132,6 +132,7 @@ public:
OctreeDataPersist,
EntityClone,
EntityQueryInitialResultsComplete,
NUM_PACKET_TYPE
};

View file

@ -192,6 +192,8 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
_elementsInLastWindow = 0;
_entitiesInLastWindow = 0;
}
_lastOctreeMessageSequence = sequence;
}
}

View file

@ -56,6 +56,8 @@ public:
float getAverageUncompressPerPacket() const { return _uncompressPerPacket.getAverage(); }
float getAverageReadBitstreamPerPacket() const { return _readBitstreamPerPacket.getAverage(); }
OCTREE_PACKET_SEQUENCE getLastOctreeMessageSequence() const { return _lastOctreeMessageSequence; }
protected:
virtual OctreePointer createTree() = 0;
@ -77,6 +79,7 @@ protected:
int _packetsInLastWindow = 0;
int _elementsInLastWindow = 0;
int _entitiesInLastWindow = 0;
std::atomic<OCTREE_PACKET_SEQUENCE> _lastOctreeMessageSequence;
};

View file

@ -27,6 +27,10 @@ OctreeQuery::OctreeQuery(bool randomizeConnectionID) {
}
}
OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, int rhs) {
return lhs = OctreeQuery::OctreeQueryFlags(lhs | rhs);
}
int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) {
unsigned char* bufferStart = destinationBuffer;
@ -76,7 +80,12 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) {
memcpy(destinationBuffer, binaryParametersDocument.data(), binaryParametersBytes);
destinationBuffer += binaryParametersBytes;
}
OctreeQueryFlags queryFlags { NoFlags };
queryFlags |= (_reportInitialCompletion ? OctreeQuery::WantInitialCompletion : 0);
memcpy(destinationBuffer, &queryFlags, sizeof(queryFlags));
destinationBuffer += sizeof(queryFlags);
return destinationBuffer - bufferStart;
}
@ -150,6 +159,12 @@ int OctreeQuery::parseData(ReceivedMessage& message) {
QWriteLocker jsonParameterLocker { &_jsonParametersLock };
_jsonParameters = newJsonDocument.object();
}
OctreeQueryFlags queryFlags;
memcpy(&queryFlags, sourceBuffer, sizeof(queryFlags));
sourceBuffer += sizeof(queryFlags);
_reportInitialCompletion = bool(queryFlags & OctreeQueryFlags::WantInitialCompletion);
return sourceBuffer - startPosition;
}

View file

@ -52,6 +52,10 @@ public:
bool hasReceivedFirstQuery() const { return _hasReceivedFirstQuery; }
// Want a report when the initial query is complete.
bool wantReportInitialCompletion() const { return _reportInitialCompletion; }
void setReportInitialCompletion(bool reportInitialCompletion) { _reportInitialCompletion = reportInitialCompletion; }
signals:
void incomingConnectionIDChanged();
@ -73,8 +77,12 @@ protected:
QJsonObject _jsonParameters;
QReadWriteLock _jsonParametersLock;
enum OctreeQueryFlags : uint16_t { NoFlags = 0x0, WantInitialCompletion = 0x1 };
friend OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, const int rhs);
bool _hasReceivedFirstQuery { false };
bool _reportInitialCompletion { false };
};
#endif // hifi_OctreeQuery_h

View file

@ -69,7 +69,7 @@ bool ConicalViewFrustum::intersects(const AABox& box) const {
return intersects(position, distance, radius);
}
bool ConicalViewFrustum::getAngularSize(const AACube& cube) const {
float ConicalViewFrustum::getAngularSize(const AACube& cube) const {
auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere
auto position = cube.calcCenter() - _position; // position of bounding sphere in view-frame
float distance = glm::length(position);
@ -77,7 +77,7 @@ bool ConicalViewFrustum::getAngularSize(const AACube& cube) const {
return getAngularSize(distance, radius);
}
bool ConicalViewFrustum::getAngularSize(const AABox& box) const {
float ConicalViewFrustum::getAngularSize(const AABox& box) const {
auto radius = 0.5f * glm::length(box.getScale()); // radius of bounding sphere
auto position = box.calcCenter() - _position; // position of bounding sphere in view-frame
float distance = glm::length(position);
@ -107,7 +107,7 @@ bool ConicalViewFrustum::intersects(const glm::vec3& relativePosition, float dis
sqrtf(distance * distance - radius * radius) * _cosAngle - radius * _sinAngle;
}
bool ConicalViewFrustum::getAngularSize(float distance, float radius) const {
float ConicalViewFrustum::getAngularSize(float distance, float radius) const {
const float AVOID_DIVIDE_BY_ZERO = 0.001f;
float angularSize = radius / (distance + AVOID_DIVIDE_BY_ZERO);
return angularSize;
@ -144,3 +144,8 @@ int ConicalViewFrustum::deserialize(const unsigned char* sourceBuffer) {
return sourceBuffer - startPosition;
}
void ConicalViewFrustum::setSimpleRadius(float radius) {
_radius = radius;
_farClip = radius / 2.0f;
}

View file

@ -45,15 +45,18 @@ public:
bool intersects(const AACube& cube) const;
bool intersects(const AABox& box) const;
bool getAngularSize(const AACube& cube) const;
bool getAngularSize(const AABox& box) const;
float getAngularSize(const AACube& cube) const;
float getAngularSize(const AABox& box) const;
bool intersects(const glm::vec3& relativePosition, float distance, float radius) const;
bool getAngularSize(float distance, float radius) const;
float getAngularSize(float distance, float radius) const;
int serialize(unsigned char* destinationBuffer) const;
int deserialize(const unsigned char* sourceBuffer);
// Just test for within radius.
void setSimpleRadius(float radius);
private:
glm::vec3 _position { 0.0f, 0.0f, 0.0f };
glm::vec3 _direction { 0.0f, 0.0f, 1.0f };

View file

@ -86,12 +86,12 @@ local packet_types = {
[22] = "ICEServerPeerInformation",
[23] = "ICEServerQuery",
[24] = "OctreeStats",
[25] = "Jurisdiction",
[25] = "UNUSED_PACKET_TYPE_1",
[26] = "AvatarIdentityRequest",
[27] = "AssignmentClientStatus",
[28] = "NoisyMute",
[29] = "AvatarIdentity",
[30] = "AvatarBillboard",
[30] = "NodeIgnoreRequest",
[31] = "DomainConnectRequest",
[32] = "DomainServerRequireDTLS",
[33] = "NodeJsonStats",
@ -115,7 +115,52 @@ local packet_types = {
[51] = "AssetUpload",
[52] = "AssetUploadReply",
[53] = "AssetGetInfo",
[54] = "AssetGetInfoReply"
[54] = "AssetGetInfoReply",
[55] = "DomainDisconnectRequest",
[56] = "DomainServerRemovedNode",
[57] = "MessagesData",
[58] = "MessagesSubscribe",
[59] = "MessagesUnsubscribe",
[60] = "ICEServerHeartbeatDenied",
[61] = "AssetMappingOperation",
[62] = "AssetMappingOperationReply",
[63] = "ICEServerHeartbeatACK",
[64] = "NegotiateAudioFormat",
[65] = "SelectedAudioFormat",
[66] = "MoreEntityShapes",
[67] = "NodeKickRequest",
[68] = "NodeMuteRequest",
[69] = "RadiusIgnoreRequest",
[70] = "UsernameFromIDRequest",
[71] = "UsernameFromIDReply",
[72] = "AvatarQuery",
[73] = "RequestsDomainListData",
[74] = "PerAvatarGainSet",
[75] = "EntityScriptGetStatus",
[76] = "EntityScriptGetStatusReply",
[77] = "ReloadEntityServerScript",
[78] = "EntityPhysics",
[79] = "EntityServerScriptLog",
[80] = "AdjustAvatarSorting",
[81] = "OctreeFileReplacement",
[82] = "CollisionEventChanges",
[83] = "ReplicatedMicrophoneAudioNoEcho",
[84] = "ReplicatedMicrophoneAudioWithEcho",
[85] = "ReplicatedInjectAudio",
[86] = "ReplicatedSilentAudioFrame",
[87] = "ReplicatedAvatarIdentity",
[88] = "ReplicatedKillAvatar",
[89] = "ReplicatedBulkAvatarData",
[90] = "DomainContentReplacementFromUrl",
[91] = "ChallengeOwnership",
[92] = "EntityScriptCallMethod",
[93] = "ChallengeOwnershipRequest",
[94] = "ChallengeOwnershipReply",
[95] = "OctreeDataFileRequest",
[96] = "OctreeDataFileReply",
[97] = "OctreeDataPersist",
[98] = "EntityClone",
[99] = "EntityQueryInitialResultsComplete"
}
local unsourced_packet_types = {