mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-29 20:23:04 +02:00
Use separate priority-queues for hero & other avatars
This commit is contained in:
parent
167ddbecff
commit
13cda8d212
1 changed files with 146 additions and 125 deletions
|
@ -307,24 +307,24 @@ namespace {
|
|||
|
||||
} // Close anonymous namespace.
|
||||
|
||||
// Specialize computePriority() for avatars:
|
||||
namespace PrioritySortUtil {
|
||||
template<> float PriorityQueue<SortableAvatar>::computePriority(const SortableAvatar& thing) const {
|
||||
static constexpr float AVATAR_HERO_BONUS { 25.0f }; // Higher than any normal priority.
|
||||
|
||||
float priority = std::numeric_limits<float>::min();
|
||||
|
||||
for (const auto& view : _views) {
|
||||
priority = std::max(priority, computePriority(view, thing));
|
||||
}
|
||||
|
||||
if (thing.getAvatar()->getPriorityAvatar()) {
|
||||
priority += AVATAR_HERO_BONUS;
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
//// Specialize computePriority() for avatars:
|
||||
//namespace PrioritySortUtil {
|
||||
//template<> float PriorityQueue<SortableAvatar>::computePriority(const SortableAvatar& thing) const {
|
||||
// static constexpr float AVATAR_HERO_BONUS { 25.0f }; // Higher than any normal priority.
|
||||
//
|
||||
// float priority = std::numeric_limits<float>::min();
|
||||
//
|
||||
// for (const auto& view : _views) {
|
||||
// priority = std::max(priority, computePriority(view, thing));
|
||||
// }
|
||||
//
|
||||
// if (thing.getAvatar()->getPriorityAvatar()) {
|
||||
// priority += AVATAR_HERO_BONUS;
|
||||
// }
|
||||
//
|
||||
// return priority;
|
||||
//}
|
||||
//}
|
||||
|
||||
void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) {
|
||||
const float AVATAR_HERO_FRACTION { 0.4f };
|
||||
|
@ -388,11 +388,23 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
|
||||
// prepare to sort
|
||||
const auto& cameraViews = nodeData->getViewFrustums();
|
||||
PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(cameraViews,
|
||||
AvatarData::_avatarSortCoefficientSize,
|
||||
AvatarData::_avatarSortCoefficientCenter,
|
||||
AvatarData::_avatarSortCoefficientAge);
|
||||
sortedAvatars.reserve(_end - _begin);
|
||||
|
||||
using AvatarPriorityQueue = PrioritySortUtil::PriorityQueue<SortableAvatar>;
|
||||
// Keep two independent queues, one for heroes and one for the riff-raff.
|
||||
enum PriorityVariants { kHero, kNonhero };
|
||||
AvatarPriorityQueue avatarPriorityQueues[2] = { {cameraViews,
|
||||
AvatarData::_avatarSortCoefficientSize, AvatarData::_avatarSortCoefficientCenter, AvatarData::_avatarSortCoefficientAge},
|
||||
{cameraViews,
|
||||
AvatarData::_avatarSortCoefficientSize, AvatarData::_avatarSortCoefficientCenter, AvatarData::_avatarSortCoefficientAge}
|
||||
};
|
||||
|
||||
//PrioritySortUtil::PriorityQueue<SortableAvatar> sortedAvatars(cameraViews,
|
||||
// AvatarData::_avatarSortCoefficientSize,
|
||||
// AvatarData::_avatarSortCoefficientCenter,
|
||||
// AvatarData::_avatarSortCoefficientAge);
|
||||
//sortedAvatars.reserve(_end - _begin);
|
||||
|
||||
avatarPriorityQueues[kNonhero].reserve(_end - _begin);
|
||||
|
||||
for (auto listedNode = _begin; listedNode != _end; ++listedNode) {
|
||||
Node* otherNodeRaw = (*listedNode).data();
|
||||
|
@ -475,7 +487,8 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
const MixerAvatar* avatarNodeData = avatarClientNodeData->getConstAvatarData();
|
||||
auto lastEncodeTime = nodeData->getLastOtherAvatarEncodeTime(avatarNode->getLocalID());
|
||||
|
||||
sortedAvatars.push(SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime));
|
||||
avatarPriorityQueues[avatarNodeData->getPriorityAvatar() ? kHero : kNonhero].push(
|
||||
SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime));
|
||||
}
|
||||
|
||||
// If Avatar A's PAL WAS open but is no longer open, AND
|
||||
|
@ -501,16 +514,18 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
|
||||
// loop through our sorted avatars and allocate our bandwidth to them accordingly
|
||||
|
||||
int remainingAvatars = (int)sortedAvatars.size();
|
||||
int remainingAvatars = (int)avatarPriorityQueues[kHero].size() + (int)avatarPriorityQueues[kNonhero].size();
|
||||
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
||||
|
||||
auto avatarPacket = NLPacket::create(PacketType::BulkAvatarData);
|
||||
const int avatarPacketCapacity = avatarPacket->getPayloadCapacity();
|
||||
int avatarSpaceAvailable = avatarPacketCapacity;
|
||||
int numPacketsSent = 0;
|
||||
int numAvatarsSent = 0;
|
||||
auto identityPacketList = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
||||
|
||||
const auto& sortedAvatarVector = sortedAvatars.getSortedVector(numToSendEst);
|
||||
for (PriorityVariants currentVariant = kHero; currentVariant <= kNonhero; ++((int&)currentVariant)) {
|
||||
const auto& sortedAvatarVector = avatarPriorityQueues[currentVariant].getSortedVector(numToSendEst);
|
||||
for (const auto& sortedAvatar : sortedAvatarVector) {
|
||||
const Node* otherNode = sortedAvatar.getNode();
|
||||
auto lastEncodeForOther = sortedAvatar.getTimestamp();
|
||||
|
@ -534,17 +549,16 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
}
|
||||
}
|
||||
|
||||
bool overHeroBudget = frameByteEstimate > maxHeroBytesPerFrame;
|
||||
bool overHeroBudget = currentVariant == kHero && numAvatarDataBytes > maxHeroBytesPerFrame;
|
||||
if (overHeroBudget) {
|
||||
break; // No more heroes (this frame).
|
||||
}
|
||||
|
||||
auto startAvatarDataPacking = chrono::high_resolution_clock::now();
|
||||
|
||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||
const MixerAvatar* otherAvatar = otherNodeData->getConstAvatarData();
|
||||
|
||||
if (overHeroBudget && otherAvatar->getPriorityAvatar()) {
|
||||
continue; // No more heroes (this frame).
|
||||
}
|
||||
|
||||
// Typically all out-of-view avatars but such avatars' priorities will rise with time:
|
||||
bool isLowerPriority = sortedAvatar.getPriority() <= OUT_OF_VIEW_THRESHOLD;
|
||||
|
||||
|
@ -611,16 +625,23 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
|
||||
auto endAvatarDataPacking = chrono::high_resolution_clock::now();
|
||||
_stats.avatarDataPackingElapsedTime +=
|
||||
(quint64) chrono::duration_cast<chrono::microseconds>(endAvatarDataPacking - startAvatarDataPacking).count();
|
||||
(quint64)chrono::duration_cast<chrono::microseconds>(endAvatarDataPacking - startAvatarDataPacking).count();
|
||||
|
||||
if (!overBudget) {
|
||||
// use helper to add any changed traits to our packet list
|
||||
traitBytesSent += addChangedTraitsToBulkPacket(nodeData, otherNodeData, *traitsPacketList);
|
||||
}
|
||||
|
||||
numAvatarsSent++;
|
||||
remainingAvatars--;
|
||||
}
|
||||
|
||||
if (currentVariant == kHero) { // Dump any remaining heroes into the commoners.
|
||||
for (auto avIter = sortedAvatarVector.begin() + numAvatarsSent; avIter < sortedAvatarVector.end(); ++avIter) {
|
||||
avatarPriorityQueues[kNonhero].push(*avIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeData->getNumAvatarsSentLastFrame() > numToSendEst) {
|
||||
qCWarning(avatars) << "More avatars sent than upper estimate" << nodeData->getNumAvatarsSentLastFrame()
|
||||
<< " / " << numToSendEst;
|
||||
|
|
Loading…
Reference in a new issue