Merge branch '404DomainRedirect' of https://github.com/wayne-chen/hifi into 404DomainRedirect

This commit is contained in:
Wayne Chen 2018-08-29 16:12:57 -07:00
commit 0c8964b16f
15 changed files with 234 additions and 23 deletions

View file

@ -463,19 +463,15 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
limitedNodeList->eachNodeBreakable([nodeConnection, username, &existingNodeID](const SharedNodePointer& node){
if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) {
// we have a node that already has these exact sockets - this can occur if a node
// is failing to connect to the domain
// we'll re-use the existing node ID
// as long as the user hasn't changed their username (by logging in or logging out)
auto existingNodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
if (existingNodeData->getUsername() == username) {
qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID();
existingNodeID = node->getUUID();
return false;
}
// we have a node that already has these exact sockets
// this can occur if a node is failing to connect to the domain
// remove the old node before adding the new node
qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID();
existingNodeID = node->getUUID();
return false;
}
return true;
});

View file

@ -1845,6 +1845,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
});
EntityTree::setAddMaterialToEntityOperator([this](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
if (_aboutToQuit) {
return false;
}
// try to find the renderable
auto renderable = getEntities()->renderableForEntityId(entityID);
if (renderable) {
@ -1860,6 +1864,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
return false;
});
EntityTree::setRemoveMaterialFromEntityOperator([this](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
if (_aboutToQuit) {
return false;
}
// try to find the renderable
auto renderable = getEntities()->renderableForEntityId(entityID);
if (renderable) {

View file

@ -312,6 +312,9 @@ public:
Q_INVOKABLE void copyToClipboard(const QString& text);
int getOtherAvatarsReplicaCount() { return DependencyManager::get<AvatarHashMap>()->getReplicaCount(); }
void setOtherAvatarsReplicaCount(int count) { DependencyManager::get<AvatarHashMap>()->setReplicaCount(count); }
#if defined(Q_OS_ANDROID)
void beforeEnterBackground();
void enterBackground();

View file

@ -38,7 +38,7 @@ void ConnectionMonitor::init() {
connect(&_timer, &QTimer::timeout, this, []() {
qDebug() << "ConnectionMonitor: Showing connection failure window";
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(true);
//DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(true);
});
}
@ -48,5 +48,5 @@ void ConnectionMonitor::startTimer() {
void ConnectionMonitor::stopTimer() {
_timer.stop();
DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(false);
//DependencyManager::get<DialogsManager>()->setDomainConnectionFailureVisibility(false);
}

View file

@ -190,4 +190,12 @@ void TestScriptingInterface::saveObject(QVariant variant, const QString& filenam
void TestScriptingInterface::showMaximized() {
qApp->getWindow()->showMaximized();
}
void TestScriptingInterface::setOtherAvatarsReplicaCount(int count) {
qApp->setOtherAvatarsReplicaCount(count);
}
int TestScriptingInterface::getOtherAvatarsReplicaCount() {
return qApp->getOtherAvatarsReplicaCount();
}

View file

@ -149,6 +149,20 @@ public slots:
*/
void showMaximized();
/**jsdoc
* Values higher than 0 will create replicas of other-avatars when entering a domain for testing purpouses
* @function Test.setOtherAvatarsReplicaCount
* @param {number} count - Number of replicas we want to create
*/
Q_INVOKABLE void setOtherAvatarsReplicaCount(int count);
/**jsdoc
* Return the number of replicas that are being created of other-avatars when entering a domain
* @function Test.getOtherAvatarsReplicaCount
* @returns {number} Current number of replicas of other-avatars.
*/
Q_INVOKABLE int getOtherAvatarsReplicaCount();
private:
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
QString _testResultsLocation;

View file

@ -156,6 +156,10 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn
// integrate phase forward in time.
_phase += omega * dt;
if (_phase < 0.0f) {
_phase = 0.0f;
}
// detect loop trigger events
if (_phase >= 1.0f) {
triggersOut.setTrigger(_id + "Loop");

View file

@ -458,7 +458,6 @@ protected:
glm::vec3 _lastAngularVelocity;
glm::vec3 _angularAcceleration;
glm::quat _lastOrientation;
glm::vec3 _worldUpDirection { Vectors::UP };
bool _moving { false }; ///< set when position is changing

View file

@ -918,7 +918,18 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
PACKET_READ_CHECK(AvatarGlobalPosition, sizeof(AvatarDataPacket::AvatarGlobalPosition));
auto data = reinterpret_cast<const AvatarDataPacket::AvatarGlobalPosition*>(sourceBuffer);
auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]);
glm::vec3 offset = glm::vec3(0.0f, 0.0f, 0.0f);
if (_replicaIndex > 0) {
const float SPACE_BETWEEN_AVATARS = 2.0f;
const int AVATARS_PER_ROW = 3;
int row = _replicaIndex % AVATARS_PER_ROW;
int col = floor(_replicaIndex / AVATARS_PER_ROW);
offset = glm::vec3(row * SPACE_BETWEEN_AVATARS, 0.0f, col * SPACE_BETWEEN_AVATARS);
}
auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset;
if (_globalPosition != newValue) {
_globalPosition = newValue;
_globalPositionChanged = usecTimestampNow();

View file

@ -337,6 +337,7 @@ enum KillAvatarReason : uint8_t {
TheirAvatarEnteredYourBubble,
YourAvatarEnteredTheirBubble
};
Q_DECLARE_METATYPE(KillAvatarReason);
class QDataStream;
@ -1186,6 +1187,8 @@ public:
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {}
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {}
void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; }
int getReplicaIndex() { return _replicaIndex; }
signals:
@ -1445,6 +1448,7 @@ protected:
udt::SequenceNumber _identitySequenceNumber { 0 };
bool _hasProcessedFirstIdentity { false };
float _density;
int _replicaIndex { 0 };
// null unless MyAvatar or ScriptableAvatar sending traits data to mixer
std::unique_ptr<ClientTraitsHandler> _clientTraitsHandler;

View file

@ -21,6 +21,84 @@
#include "AvatarLogging.h"
#include "AvatarTraits.h"
void AvatarReplicas::addReplica(const QUuid& parentID, AvatarSharedPointer replica) {
if (parentID == QUuid()) {
return;
}
if (_replicasMap.find(parentID) == _replicasMap.end()) {
std::vector<AvatarSharedPointer> emptyReplicas = std::vector<AvatarSharedPointer>();
_replicasMap.insert(std::pair<QUuid, std::vector<AvatarSharedPointer>>(parentID, emptyReplicas));
}
auto &replicas = _replicasMap[parentID];
replica->setReplicaIndex((int)replicas.size() + 1);
replicas.push_back(replica);
}
std::vector<QUuid> AvatarReplicas::getReplicaIDs(const QUuid& parentID) {
std::vector<QUuid> ids;
if (_replicasMap.find(parentID) != _replicasMap.end()) {
auto &replicas = _replicasMap[parentID];
for (int i = 0; i < (int)replicas.size(); i++) {
ids.push_back(replicas[i]->getID());
}
} else if (_replicaCount > 0) {
for (int i = 0; i < _replicaCount; i++) {
ids.push_back(QUuid::createUuid());
}
}
return ids;
}
void AvatarReplicas::parseDataFromBuffer(const QUuid& parentID, const QByteArray& buffer) {
if (_replicasMap.find(parentID) != _replicasMap.end()) {
auto &replicas = _replicasMap[parentID];
for (auto avatar : replicas) {
avatar->parseDataFromBuffer(buffer);
}
}
}
void AvatarReplicas::removeReplicas(const QUuid& parentID) {
if (_replicasMap.find(parentID) != _replicasMap.end()) {
_replicasMap.erase(parentID);
}
}
void AvatarReplicas::processAvatarIdentity(const QUuid& parentID, const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged) {
if (_replicasMap.find(parentID) != _replicasMap.end()) {
auto &replicas = _replicasMap[parentID];
for (auto avatar : replicas) {
avatar->processAvatarIdentity(identityData, identityChanged, displayNameChanged);
}
}
}
void AvatarReplicas::processTrait(const QUuid& parentID, AvatarTraits::TraitType traitType, QByteArray traitBinaryData) {
if (_replicasMap.find(parentID) != _replicasMap.end()) {
auto &replicas = _replicasMap[parentID];
for (auto avatar : replicas) {
avatar->processTrait(traitType, traitBinaryData);
}
}
}
void AvatarReplicas::processDeletedTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID) {
if (_replicasMap.find(parentID) != _replicasMap.end()) {
auto &replicas = _replicasMap[parentID];
for (auto avatar : replicas) {
avatar->processDeletedTraitInstance(traitType, instanceID);
}
}
}
void AvatarReplicas::processTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType,
AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData) {
if (_replicasMap.find(parentID) != _replicasMap.end()) {
auto &replicas = _replicasMap[parentID];
for (auto avatar : replicas) {
avatar->processTraitInstance(traitType, instanceID, traitBinaryData);
}
}
}
AvatarHashMap::AvatarHashMap() {
auto nodeList = DependencyManager::get<NodeList>();
@ -64,6 +142,21 @@ bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range
return false;
}
void AvatarHashMap::setReplicaCount(int count) {
_replicas.setReplicaCount(count);
auto avatars = getAvatarIdentifiers();
for (int i = 0; i < avatars.size(); i++) {
KillAvatarReason reason = KillAvatarReason::NoReason;
if (avatars[i] != QUuid()) {
removeAvatar(avatars[i], reason);
auto replicaIDs = _replicas.getReplicaIDs(avatars[i]);
for (auto id : replicaIDs) {
removeAvatar(id, reason);
}
}
}
}
int AvatarHashMap::numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters) {
auto hashCopy = getHashCopy();
auto rangeMeters2 = rangeMeters * rangeMeters;
@ -135,18 +228,25 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer<ReceivedMessag
// make sure this isn't our own avatar data or for a previously ignored node
auto nodeList = DependencyManager::get<NodeList>();
bool isNewAvatar;
if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) {
auto avatar = newOrExistingAvatar(sessionUUID, sendingNode, isNewAvatar);
if (isNewAvatar) {
QWriteLocker locker(&_hashLock);
_pendingAvatars.insert(sessionUUID, { std::chrono::steady_clock::now(), 0, avatar });
}
auto replicaIDs = _replicas.getReplicaIDs(sessionUUID);
for (auto replicaID : replicaIDs) {
auto replicaAvatar = addAvatar(replicaID, sendingNode);
_replicas.addReplica(sessionUUID, replicaAvatar);
}
}
// have the matching (or new) avatar parse the data from the packet
int bytesRead = avatar->parseDataFromBuffer(byteArray);
message->seek(positionBeforeRead + bytesRead);
_replicas.parseDataFromBuffer(sessionUUID, byteArray);
return avatar;
} else {
// create a dummy AvatarData class to throw this data on the ground
@ -191,10 +291,13 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
bool displayNameChanged = false;
// In this case, the "sendingNode" is the Avatar Mixer.
avatar->processAvatarIdentity(message->getMessage(), identityChanged, displayNameChanged);
_replicas.processAvatarIdentity(identityUUID, message->getMessage(), identityChanged, displayNameChanged);
}
}
void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
while (message->getBytesLeftToRead()) {
// read the avatar ID to figure out which avatar this is for
auto avatarID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
@ -202,7 +305,6 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> mess
// grab the avatar so we can ask it to process trait data
bool isNewAvatar;
auto avatar = newOrExistingAvatar(avatarID, sendingNode, isNewAvatar);
// read the first trait type for this avatar
AvatarTraits::TraitType traitType;
message->readPrimitive(&traitType);
@ -217,13 +319,14 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> mess
AvatarTraits::TraitWireSize traitBinarySize;
bool skipBinaryTrait = false;
if (AvatarTraits::isSimpleTrait(traitType)) {
message->readPrimitive(&traitBinarySize);
// check if this trait version is newer than what we already have for this avatar
if (packetTraitVersion > lastProcessedVersions[traitType]) {
avatar->processTrait(traitType, message->read(traitBinarySize));
auto traitData = message->read(traitBinarySize);
avatar->processTrait(traitType, traitData);
_replicas.processTrait(avatarID, traitType, traitData);
lastProcessedVersions[traitType] = packetTraitVersion;
} else {
skipBinaryTrait = true;
@ -238,8 +341,11 @@ void AvatarHashMap::processBulkAvatarTraits(QSharedPointer<ReceivedMessage> mess
if (packetTraitVersion > processedInstanceVersion) {
if (traitBinarySize == AvatarTraits::DELETED_TRAIT_SIZE) {
avatar->processDeletedTraitInstance(traitType, traitInstanceID);
_replicas.processDeletedTraitInstance(avatarID, traitType, traitInstanceID);
} else {
avatar->processTraitInstance(traitType, traitInstanceID, message->read(traitBinarySize));
auto traitData = message->read(traitBinarySize);
avatar->processTraitInstance(traitType, traitInstanceID, traitData);
_replicas.processTraitInstance(avatarID, traitType, traitInstanceID, traitData);
}
processedInstanceVersion = packetTraitVersion;
} else {
@ -265,17 +371,31 @@ void AvatarHashMap::processKillAvatar(QSharedPointer<ReceivedMessage> message, S
KillAvatarReason reason;
message->readPrimitive(&reason);
removeAvatar(sessionUUID, reason);
auto replicaIDs = _replicas.getReplicaIDs(sessionUUID);
for (auto id : replicaIDs) {
removeAvatar(id, reason);
}
}
void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason) {
QWriteLocker locker(&_hashLock);
auto replicaIDs = _replicas.getReplicaIDs(sessionUUID);
_replicas.removeReplicas(sessionUUID);
for (auto id : replicaIDs) {
auto removedReplica = _avatarHash.take(id);
if (removedReplica) {
handleRemovedAvatar(removedReplica, removalReason);
}
}
_pendingAvatars.remove(sessionUUID);
auto removedAvatar = _avatarHash.take(sessionUUID);
if (removedAvatar) {
handleRemovedAvatar(removedAvatar, removalReason);
}
}
void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {

View file

@ -41,6 +41,27 @@
* @hifi-assignment-client
*/
class AvatarReplicas {
public:
AvatarReplicas() {}
void addReplica(const QUuid& parentID, AvatarSharedPointer replica);
std::vector<QUuid> getReplicaIDs(const QUuid& parentID);
void parseDataFromBuffer(const QUuid& parentID, const QByteArray& buffer);
void processAvatarIdentity(const QUuid& parentID, const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged);
void removeReplicas(const QUuid& parentID);
void processTrait(const QUuid& parentID, AvatarTraits::TraitType traitType, QByteArray traitBinaryData);
void processDeletedTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID);
void processTraitInstance(const QUuid& parentID, AvatarTraits::TraitType traitType,
AvatarTraits::TraitInstanceID instanceID, QByteArray traitBinaryData);
void setReplicaCount(int count) { _replicaCount = count; }
int getReplicaCount() { return _replicaCount; }
private:
std::map<QUuid, std::vector<AvatarSharedPointer>> _replicasMap;
int _replicaCount { 0 };
};
class AvatarHashMap : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
@ -77,6 +98,9 @@ public:
virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) const { return findAvatar(sessionID); }
int numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters);
void setReplicaCount(int count);
int getReplicaCount() { return _replicas.getReplicaCount(); };
signals:
/**jsdoc
@ -167,6 +191,8 @@ protected:
mutable QReadWriteLock _hashLock;
std::unordered_map<QUuid, AvatarTraits::TraitVersions> _processedTraitVersions;
AvatarReplicas _replicas;
private:
QUuid _lastOwnerSessionUUID;
};

View file

@ -765,7 +765,6 @@ void GLBackend::recycle() const {
}
_textureManagement._transferEngine->manageMemory();
Texture::KtxStorage::releaseOpenKtxFiles();
}
void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) {

View file

@ -405,6 +405,7 @@ bool GLTextureTransferEngineDefault::processActiveBufferQueue() {
_activeTransferQueue.splice(_activeTransferQueue.end(), activeBufferQueue);
}
Texture::KtxStorage::releaseOpenKtxFiles();
return true;
}

View file

@ -273,6 +273,7 @@ void NodeList::reset(bool skipDomainHandlerReset) {
// refresh the owner UUID to the NULL UUID
setSessionUUID(QUuid());
setSessionLocalID(Node::NULL_LOCAL_ID);
// if we setup the DTLS socket, also disconnect from the DTLS socket readyRead() so it can handle handshaking
if (_dtlsSocket) {
@ -647,6 +648,23 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
Node::LocalID newLocalID;
packetStream >> newUUID;
packetStream >> newLocalID;
// when connected, if the session ID or local ID were not null and changed, we should reset
auto currentLocalID = getSessionLocalID();
auto currentSessionID = getSessionUUID();
if (_domainHandler.isConnected() &&
((currentLocalID != Node::NULL_LOCAL_ID && newLocalID != currentLocalID) ||
(!currentSessionID.isNull() && newUUID != currentSessionID))) {
qCDebug(networking) << "Local ID or Session ID changed while connected to domain - forcing NodeList reset";
// reset the nodelist, but don't do a domain handler reset since we're about to process a good domain list
reset(true);
// tell the domain handler that we're no longer connected so that below
// it can re-perform actions as if we just connected
_domainHandler.setIsConnected(false);
}
setSessionLocalID(newLocalID);
setSessionUUID(newUUID);