mirror of
https://github.com/lubosz/overte.git
synced 2025-04-19 16:44:04 +02:00
Merge remote-tracking branch 'upstream/master' into destroy
This commit is contained in:
commit
3c7f1a0c4b
19 changed files with 286 additions and 49 deletions
|
@ -25,6 +25,9 @@
|
|||
#include "AssignmentClientChildData.h"
|
||||
#include "SharedUtil.h"
|
||||
#include <QtCore/QJsonDocument>
|
||||
#ifdef _POSIX_SOURCE
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor";
|
||||
const int WAIT_FOR_CHILD_MSECS = 1000;
|
||||
|
@ -71,6 +74,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AssignmentClientStatus, this, "handleChildStatusPacket");
|
||||
|
||||
adjustOSResources(std::max(_numAssignmentClientForks, _maxAssignmentClientForks));
|
||||
// use QProcess to fork off a process for each of the child assignment clients
|
||||
for (unsigned int i = 0; i < _numAssignmentClientForks; i++) {
|
||||
spawnChildClient();
|
||||
|
@ -372,3 +376,27 @@ bool AssignmentClientMonitor::handleHTTPRequest(HTTPConnection* connection, cons
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::adjustOSResources(unsigned int numForks) const
|
||||
{
|
||||
#ifdef _POSIX_SOURCE
|
||||
// QProcess on Unix uses six (I think) descriptors, some temporarily, for each child proc.
|
||||
// Formula based on tests with a Ubuntu 16.04 VM.
|
||||
unsigned requiredDescriptors = 30 + 6 * numForks;
|
||||
struct rlimit descLimits;
|
||||
if (getrlimit(RLIMIT_NOFILE, &descLimits) == 0) {
|
||||
if (descLimits.rlim_cur < requiredDescriptors) {
|
||||
descLimits.rlim_cur = requiredDescriptors;
|
||||
if (setrlimit(RLIMIT_NOFILE, &descLimits) == 0) {
|
||||
qDebug() << "Resetting descriptor limit to" << requiredDescriptors;
|
||||
} else {
|
||||
const char *const errorString = strerror(errno);
|
||||
qDebug() << "Failed to reset descriptor limit to" << requiredDescriptors << ":" << errorString;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const char *const errorString = strerror(errno);
|
||||
qDebug() << "Failed to read descriptor limit:" << errorString;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public slots:
|
|||
private:
|
||||
void spawnChildClient();
|
||||
void simultaneousWaitOnChildren(int waitMsecs);
|
||||
void adjustOSResources(unsigned int numForks) const;
|
||||
|
||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ Item {
|
|||
|
||||
Timer {
|
||||
id: refreshTimer;
|
||||
interval: 4000;
|
||||
interval: 6000;
|
||||
onTriggered: {
|
||||
if (transactionHistory.atYBeginning) {
|
||||
console.log("Refreshing 1st Page of Recent Activity...");
|
||||
|
@ -211,6 +211,7 @@ Item {
|
|||
|
||||
HifiModels.PSFListModel {
|
||||
id: transactionHistoryModel;
|
||||
property int lastPendingCount: 0;
|
||||
listModelName: "transaction history"; // For debugging. Alternatively, we could specify endpoint for that purpose, even though it's not used directly.
|
||||
listView: transactionHistory;
|
||||
itemsPerPage: 6;
|
||||
|
@ -221,8 +222,26 @@ Item {
|
|||
processPage: function (data) {
|
||||
console.debug('processPage', transactionHistoryModel.listModelName, JSON.stringify(data));
|
||||
var result, pending; // Set up or get the accumulator for pending.
|
||||
if (transactionHistoryModel.currentPageToRetrieve == 1) {
|
||||
pending = {transaction_type: "pendingCount", count: 0};
|
||||
if (transactionHistoryModel.currentPageToRetrieve === 1) {
|
||||
// The initial data elements inside the ListModel MUST contain all keys
|
||||
// that will be used in future data.
|
||||
pending = {
|
||||
transaction_type: "pendingCount",
|
||||
count: 0,
|
||||
created_at: 0,
|
||||
hfc_text: "",
|
||||
id: "",
|
||||
message: "",
|
||||
place_name: "",
|
||||
received_certs: 0,
|
||||
received_money: 0,
|
||||
recipient_name: "",
|
||||
sender_name: "",
|
||||
sent_certs: 0,
|
||||
sent_money: 0,
|
||||
status: "",
|
||||
transaction_text: ""
|
||||
};
|
||||
result = [pending];
|
||||
} else {
|
||||
pending = transactionHistoryModel.get(0);
|
||||
|
@ -239,6 +258,15 @@ Item {
|
|||
}
|
||||
});
|
||||
|
||||
if (lastPendingCount === 0) {
|
||||
lastPendingCount = pending.count;
|
||||
} else {
|
||||
if (lastPendingCount !== pending.count) {
|
||||
transactionHistoryModel.getNextPageIfNotEnoughVerticalResults();
|
||||
}
|
||||
lastPendingCount = pending.count;
|
||||
}
|
||||
|
||||
// Only auto-refresh if the user hasn't scrolled
|
||||
// and there is more data to grab
|
||||
if (transactionHistory.atYBeginning && data.history.length) {
|
||||
|
@ -257,13 +285,13 @@ Item {
|
|||
ListView {
|
||||
id: transactionHistory;
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
policy: transactionHistory.contentHeight > parent.parent.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded;
|
||||
parent: transactionHistory.parent;
|
||||
anchors.top: transactionHistory.top;
|
||||
anchors.left: transactionHistory.right;
|
||||
anchors.leftMargin: 4;
|
||||
anchors.bottom: transactionHistory.bottom;
|
||||
width: 20;
|
||||
policy: transactionHistory.contentHeight > parent.parent.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded;
|
||||
parent: transactionHistory.parent;
|
||||
anchors.top: transactionHistory.top;
|
||||
anchors.left: transactionHistory.right;
|
||||
anchors.leftMargin: 4;
|
||||
anchors.bottom: transactionHistory.bottom;
|
||||
width: 20;
|
||||
}
|
||||
anchors.centerIn: parent;
|
||||
width: parent.width - 12;
|
||||
|
@ -340,7 +368,7 @@ Item {
|
|||
}
|
||||
|
||||
HifiControlsUit.Separator {
|
||||
colorScheme: 1;
|
||||
colorScheme: 1;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
|
|
@ -38,6 +38,16 @@ ListModel {
|
|||
onSearchFilterChanged: if (initialized) { getFirstPage('delayClear'); }
|
||||
onTagsFilterChanged: if (initialized) { getFirstPage('delayClear'); }
|
||||
|
||||
// When considering a value for `itemsPerPage` in YOUR model, consider the following:
|
||||
// - If your ListView delegates are of variable width/height, ensure you select
|
||||
// an `itemsPerPage` value that would be sufficient to show one full page of data
|
||||
// if all of the delegates were at their minimum heights.
|
||||
// - If your first ListView delegate contains some special data (as in WalletHome's
|
||||
// "Recent Activity" view), beware that your `itemsPerPage` value may _never_ reasonably be
|
||||
// high enough such that the first page of data causes the view to be one-screen in height
|
||||
// after retrieving the first page. This means data will automatically pop-in (after a short delay)
|
||||
// until the combined heights of your View's delegates reach one-screen in height OR there is
|
||||
// no more data to retrieve. See "needsMoreVerticalResults()" below.
|
||||
property int itemsPerPage: 100;
|
||||
|
||||
// State.
|
||||
|
@ -81,12 +91,35 @@ ListModel {
|
|||
function getNextPageIfVerticalScroll() {
|
||||
if (needsEarlyYFetch()) { getNextPage(); }
|
||||
}
|
||||
function needsMoreHorizontalResults() {
|
||||
return flickable
|
||||
&& currentPageToRetrieve > 0
|
||||
&& flickable.contentWidth < flickable.width;
|
||||
}
|
||||
function needsMoreVerticalResults() {
|
||||
return flickable
|
||||
&& currentPageToRetrieve > 0
|
||||
&& flickable.contentHeight < flickable.height;
|
||||
}
|
||||
function getNextPageIfNotEnoughHorizontalResults() {
|
||||
if (needsMoreHorizontalResults()) {
|
||||
getNextPage();
|
||||
}
|
||||
}
|
||||
function getNextPageIfNotEnoughVerticalResults() {
|
||||
if (needsMoreVerticalResults()) {
|
||||
getNextPage();
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
initialized = true;
|
||||
if (flickable && pageAhead > 0.0) {
|
||||
// Pun: Scrollers are usually one direction or another, such that only one of the following will actually fire.
|
||||
flickable.contentXChanged.connect(getNextPageIfHorizontalScroll);
|
||||
flickable.contentYChanged.connect(getNextPageIfVerticalScroll);
|
||||
flickable.contentWidthChanged.connect(getNextPageIfNotEnoughHorizontalResults);
|
||||
flickable.contentHeightChanged.connect(getNextPageIfNotEnoughVerticalResults);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -5512,12 +5513,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
|
||||
|
@ -6162,11 +6165,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>();
|
||||
|
||||
|
@ -6314,6 +6329,7 @@ void Application::clearDomainOctreeDetails() {
|
|||
_octreeServerSceneStats.clear();
|
||||
});
|
||||
|
||||
_octreeProcessor.resetCompletionSequenceNumber();
|
||||
// reset the model renderer
|
||||
getEntities()->clear();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -132,6 +132,7 @@ public:
|
|||
OctreeDataPersist,
|
||||
|
||||
EntityClone,
|
||||
EntityQueryInitialResultsComplete,
|
||||
|
||||
NUM_PACKET_TYPE
|
||||
};
|
||||
|
|
|
@ -192,6 +192,8 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe
|
|||
_elementsInLastWindow = 0;
|
||||
_entitiesInLastWindow = 0;
|
||||
}
|
||||
|
||||
_lastOctreeMessageSequence = sequence;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in a new issue