mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 14:03:55 +02:00
Merge pull request #3632 from ey6es/metavoxels
Added network condition simulator for metavoxels, fixed crash issues with reliable deltas.
This commit is contained in:
commit
650660a0fc
16 changed files with 463 additions and 43 deletions
|
@ -237,8 +237,9 @@ void MetavoxelSession::update() {
|
|||
|
||||
// go back to the beginning with the current packet and note that there's a delta pending
|
||||
_sequencer.getOutputStream().getUnderlying().device()->seek(start);
|
||||
MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID };
|
||||
out << QVariant::fromValue(msg);
|
||||
MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID, sendRecord->getPacketNumber(),
|
||||
_sequencer.getIncomingPacketNumber() };
|
||||
out << (_reliableDeltaMessage = QVariant::fromValue(msg));
|
||||
_sequencer.endPacket();
|
||||
|
||||
} else {
|
||||
|
@ -254,8 +255,9 @@ void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) {
|
|||
}
|
||||
|
||||
PacketRecord* MetavoxelSession::maybeCreateSendRecord() const {
|
||||
return _reliableDeltaChannel ? new PacketRecord(_reliableDeltaLOD, _reliableDeltaData) :
|
||||
new PacketRecord(_lod, _sender->getData());
|
||||
return _reliableDeltaChannel ? new PacketRecord(_sequencer.getOutgoingPacketNumber(),
|
||||
_reliableDeltaLOD, _reliableDeltaData) : new PacketRecord(_sequencer.getOutgoingPacketNumber(),
|
||||
_lod, _sender->getData());
|
||||
}
|
||||
|
||||
void MetavoxelSession::handleMessage(const QVariant& message) {
|
||||
|
@ -290,8 +292,7 @@ void MetavoxelSession::sendPacketGroup(int alreadySent) {
|
|||
for (int i = 0; i < additionalPackets; i++) {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
if (_reliableDeltaChannel) {
|
||||
MetavoxelDeltaPendingMessage msg = { _reliableDeltaID };
|
||||
out << QVariant::fromValue(msg);
|
||||
out << _reliableDeltaMessage;
|
||||
} else {
|
||||
out << QVariant();
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ private:
|
|||
MetavoxelLOD _reliableDeltaLOD;
|
||||
Bitstream::WriteMappings _reliableDeltaWriteMappings;
|
||||
int _reliableDeltaID;
|
||||
QVariant _reliableDeltaMessage;
|
||||
};
|
||||
|
||||
/// Handles persistence in a separate thread.
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "ui/AttachmentsDialog.h"
|
||||
#include "ui/InfoView.h"
|
||||
#include "ui/MetavoxelEditor.h"
|
||||
#include "ui/MetavoxelNetworkSimulator.h"
|
||||
#include "ui/ModelsBrowser.h"
|
||||
#include "ui/LoginDialog.h"
|
||||
#include "ui/NodeBounds.h"
|
||||
|
@ -431,6 +432,8 @@ Menu::Menu() :
|
|||
QMenu* metavoxelOptionsMenu = developerMenu->addMenu("Metavoxels");
|
||||
addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::DisplayHermiteData, 0, false,
|
||||
Application::getInstance()->getMetavoxels(), SLOT(refreshVoxelData()));
|
||||
addActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::NetworkSimulator, 0, this,
|
||||
SLOT(showMetavoxelNetworkSimulator()));
|
||||
|
||||
QMenu* handOptionsMenu = developerMenu->addMenu("Hands");
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false);
|
||||
|
@ -1378,6 +1381,13 @@ void Menu::showMetavoxelEditor() {
|
|||
_MetavoxelEditor->raise();
|
||||
}
|
||||
|
||||
void Menu::showMetavoxelNetworkSimulator() {
|
||||
if (!_metavoxelNetworkSimulator) {
|
||||
_metavoxelNetworkSimulator = new MetavoxelNetworkSimulator();
|
||||
}
|
||||
_metavoxelNetworkSimulator->raise();
|
||||
}
|
||||
|
||||
void Menu::showScriptEditor() {
|
||||
if(!_ScriptEditor || !_ScriptEditor->isVisible()) {
|
||||
_ScriptEditor = new ScriptEditorWindow();
|
||||
|
|
|
@ -78,6 +78,7 @@ class AttachmentsDialog;
|
|||
class BandwidthDialog;
|
||||
class LodToolsDialog;
|
||||
class MetavoxelEditor;
|
||||
class MetavoxelNetworkSimulator;
|
||||
class ChatWindow;
|
||||
class OctreeStatsDialog;
|
||||
class MenuItemProperties;
|
||||
|
@ -218,6 +219,7 @@ private slots:
|
|||
void cycleFrustumRenderMode();
|
||||
void runTests();
|
||||
void showMetavoxelEditor();
|
||||
void showMetavoxelNetworkSimulator();
|
||||
void showScriptEditor();
|
||||
void showChat();
|
||||
void toggleConsole();
|
||||
|
@ -274,6 +276,7 @@ private:
|
|||
FrustumDrawMode _frustumDrawMode;
|
||||
ViewFrustumOffset _viewFrustumOffset;
|
||||
QPointer<MetavoxelEditor> _MetavoxelEditor;
|
||||
QPointer<MetavoxelNetworkSimulator> _metavoxelNetworkSimulator;
|
||||
QPointer<ScriptEditorWindow> _ScriptEditor;
|
||||
QPointer<ChatWindow> _chatWindow;
|
||||
QDialog* _jsConsole;
|
||||
|
@ -430,6 +433,7 @@ namespace MenuOption {
|
|||
const QString MuteEnvironment = "Mute Environment";
|
||||
const QString MyLocations = "My Locations...";
|
||||
const QString NameLocation = "Name this location";
|
||||
const QString NetworkSimulator = "Network Simulator...";
|
||||
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
|
||||
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
|
||||
const QString OctreeStats = "Voxel and Entity Statistics";
|
||||
|
|
|
@ -39,6 +39,15 @@ REGISTER_META_OBJECT(StaticModelRenderer)
|
|||
|
||||
static int bufferPointVectorMetaTypeId = qRegisterMetaType<BufferPointVector>();
|
||||
|
||||
MetavoxelSystem::NetworkSimulation::NetworkSimulation(float dropRate, float repeatRate,
|
||||
int minimumDelay, int maximumDelay, int bandwidthLimit) :
|
||||
dropRate(dropRate),
|
||||
repeatRate(repeatRate),
|
||||
minimumDelay(minimumDelay),
|
||||
maximumDelay(maximumDelay),
|
||||
bandwidthLimit(bandwidthLimit) {
|
||||
}
|
||||
|
||||
void MetavoxelSystem::init() {
|
||||
MetavoxelClientManager::init();
|
||||
DefaultMetavoxelRendererImplementation::init();
|
||||
|
@ -61,6 +70,16 @@ MetavoxelLOD MetavoxelSystem::getLOD() {
|
|||
return _lod;
|
||||
}
|
||||
|
||||
void MetavoxelSystem::setNetworkSimulation(const NetworkSimulation& simulation) {
|
||||
QWriteLocker locker(&_networkSimulationLock);
|
||||
_networkSimulation = simulation;
|
||||
}
|
||||
|
||||
MetavoxelSystem::NetworkSimulation MetavoxelSystem::getNetworkSimulation() {
|
||||
QReadLocker locker(&_networkSimulationLock);
|
||||
return _networkSimulation;
|
||||
}
|
||||
|
||||
class SimulateVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
|
@ -678,6 +697,28 @@ void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) {
|
|||
}
|
||||
}
|
||||
|
||||
Throttle::Throttle() :
|
||||
_limit(INT_MAX),
|
||||
_total(0) {
|
||||
}
|
||||
|
||||
bool Throttle::shouldThrottle(int bytes) {
|
||||
// clear expired buckets
|
||||
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
while (!_buckets.isEmpty() && now >= _buckets.first().first) {
|
||||
_total -= _buckets.takeFirst().second;
|
||||
}
|
||||
|
||||
// if possible, add the new bucket
|
||||
if (_total + bytes > _limit) {
|
||||
return true;
|
||||
}
|
||||
const int BUCKET_DURATION = 1000;
|
||||
_buckets.append(Bucket(now + BUCKET_DURATION, bytes));
|
||||
_total += bytes;
|
||||
return false;
|
||||
}
|
||||
|
||||
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) :
|
||||
MetavoxelClient(node, updater) {
|
||||
}
|
||||
|
@ -692,10 +733,59 @@ MetavoxelData MetavoxelSystemClient::getAugmentedData() {
|
|||
return _augmentedData;
|
||||
}
|
||||
|
||||
class ReceiveDelayer : public QObject {
|
||||
public:
|
||||
|
||||
ReceiveDelayer(const SharedNodePointer& node, const QByteArray& packet);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void timerEvent(QTimerEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
SharedNodePointer _node;
|
||||
QByteArray _packet;
|
||||
};
|
||||
|
||||
ReceiveDelayer::ReceiveDelayer(const SharedNodePointer& node, const QByteArray& packet) :
|
||||
_node(node),
|
||||
_packet(packet) {
|
||||
}
|
||||
|
||||
void ReceiveDelayer::timerEvent(QTimerEvent* event) {
|
||||
QMutexLocker locker(&_node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(_node->getLinkedData());
|
||||
if (client) {
|
||||
QMetaObject::invokeMethod(&client->getSequencer(), "receivedDatagram", Q_ARG(const QByteArray&, _packet));
|
||||
}
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
int MetavoxelSystemClient::parseData(const QByteArray& packet) {
|
||||
// process through sequencer
|
||||
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size());
|
||||
MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation();
|
||||
if (randFloat() < simulation.dropRate) {
|
||||
return packet.size();
|
||||
}
|
||||
int count = (randFloat() < simulation.repeatRate) ? 2 : 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (simulation.bandwidthLimit > 0) {
|
||||
_receiveThrottle.setLimit(simulation.bandwidthLimit);
|
||||
if (_receiveThrottle.shouldThrottle(packet.size())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int delay = randIntInRange(simulation.minimumDelay, simulation.maximumDelay);
|
||||
if (delay > 0) {
|
||||
ReceiveDelayer* delayer = new ReceiveDelayer(_node, packet);
|
||||
delayer->startTimer(delay);
|
||||
|
||||
} else {
|
||||
QMetaObject::invokeMethod(&_sequencer, "receivedDatagram", Q_ARG(const QByteArray&, packet));
|
||||
}
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::METAVOXELS).updateValue(packet.size());
|
||||
}
|
||||
return packet.size();
|
||||
}
|
||||
|
||||
|
@ -774,9 +864,52 @@ void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) {
|
|||
QThreadPool::globalInstance()->start(new Augmenter(_node, _data, getAugmentedData(), _remoteDataLOD));
|
||||
}
|
||||
|
||||
class SendDelayer : public QObject {
|
||||
public:
|
||||
|
||||
SendDelayer(const SharedNodePointer& node, const QByteArray& data);
|
||||
|
||||
virtual void timerEvent(QTimerEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
SharedNodePointer _node;
|
||||
QByteArray _data;
|
||||
};
|
||||
|
||||
SendDelayer::SendDelayer(const SharedNodePointer& node, const QByteArray& data) :
|
||||
_node(node),
|
||||
_data(data.constData(), data.size()) {
|
||||
}
|
||||
|
||||
void SendDelayer::timerEvent(QTimerEvent* event) {
|
||||
NodeList::getInstance()->writeDatagram(_data, _node);
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
|
||||
NodeList::getInstance()->writeDatagram(data, _node);
|
||||
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
|
||||
MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation();
|
||||
if (randFloat() < simulation.dropRate) {
|
||||
return;
|
||||
}
|
||||
int count = (randFloat() < simulation.repeatRate) ? 2 : 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (simulation.bandwidthLimit > 0) {
|
||||
_sendThrottle.setLimit(simulation.bandwidthLimit);
|
||||
if (_sendThrottle.shouldThrottle(data.size())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int delay = randIntInRange(simulation.minimumDelay, simulation.maximumDelay);
|
||||
if (delay > 0) {
|
||||
SendDelayer* delayer = new SendDelayer(_node, data);
|
||||
delayer->startTimer(delay);
|
||||
|
||||
} else {
|
||||
NodeList::getInstance()->writeDatagram(data, _node);
|
||||
}
|
||||
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
|
||||
}
|
||||
}
|
||||
|
||||
BufferData::~BufferData() {
|
||||
|
|
|
@ -31,12 +31,27 @@ class MetavoxelSystem : public MetavoxelClientManager {
|
|||
|
||||
public:
|
||||
|
||||
class NetworkSimulation {
|
||||
public:
|
||||
float dropRate;
|
||||
float repeatRate;
|
||||
int minimumDelay;
|
||||
int maximumDelay;
|
||||
int bandwidthLimit;
|
||||
|
||||
NetworkSimulation(float dropRate = 0.0f, float repeatRate = 0.0f, int minimumDelay = 0,
|
||||
int maximumDelay = 0, int bandwidthLimit = 0);
|
||||
};
|
||||
|
||||
virtual void init();
|
||||
|
||||
virtual MetavoxelLOD getLOD();
|
||||
|
||||
const Frustum& getFrustum() const { return _frustum; }
|
||||
|
||||
void setNetworkSimulation(const NetworkSimulation& simulation);
|
||||
NetworkSimulation getNetworkSimulation();
|
||||
|
||||
const AttributePointer& getPointBufferAttribute() { return _pointBufferAttribute; }
|
||||
const AttributePointer& getHeightfieldBufferAttribute() { return _heightfieldBufferAttribute; }
|
||||
const AttributePointer& getVoxelBufferAttribute() { return _voxelBufferAttribute; }
|
||||
|
@ -93,6 +108,9 @@ private:
|
|||
MetavoxelLOD _lod;
|
||||
QReadWriteLock _lodLock;
|
||||
Frustum _frustum;
|
||||
|
||||
NetworkSimulation _networkSimulation;
|
||||
QReadWriteLock _networkSimulationLock;
|
||||
};
|
||||
|
||||
/// Generic abstract base class for objects that handle a signal.
|
||||
|
@ -116,6 +134,28 @@ typedef QVector<BufferPoint> BufferPointVector;
|
|||
|
||||
Q_DECLARE_METATYPE(BufferPointVector)
|
||||
|
||||
/// Simple throttle for limiting bandwidth on a per-second basis.
|
||||
class Throttle {
|
||||
public:
|
||||
|
||||
Throttle();
|
||||
|
||||
/// Sets the per-second limit.
|
||||
void setLimit(int limit) { _limit = limit; }
|
||||
|
||||
/// Determines whether the message with the given size should be throttled (discarded). If not, registers the message
|
||||
/// as having been processed (i.e., contributing to later throttling).
|
||||
bool shouldThrottle(int bytes);
|
||||
|
||||
private:
|
||||
|
||||
int _limit;
|
||||
int _total;
|
||||
|
||||
typedef QPair<qint64, int> Bucket;
|
||||
QList<Bucket> _buckets;
|
||||
};
|
||||
|
||||
/// A client session associated with a single server.
|
||||
class MetavoxelSystemClient : public MetavoxelClient {
|
||||
Q_OBJECT
|
||||
|
@ -145,6 +185,9 @@ private:
|
|||
MetavoxelData _augmentedData;
|
||||
MetavoxelData _renderedAugmentedData;
|
||||
QReadWriteLock _augmentedDataLock;
|
||||
|
||||
Throttle _sendThrottle;
|
||||
Throttle _receiveThrottle;
|
||||
};
|
||||
|
||||
/// Base class for cached static buffers.
|
||||
|
|
87
interface/src/ui/MetavoxelNetworkSimulator.cpp
Normal file
87
interface/src/ui/MetavoxelNetworkSimulator.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// MetavoxelNetworkSimulator.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QSpinBox>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MetavoxelNetworkSimulator.h"
|
||||
|
||||
const int BYTES_PER_KILOBYTE = 1024;
|
||||
|
||||
MetavoxelNetworkSimulator::MetavoxelNetworkSimulator() :
|
||||
QWidget(Application::getInstance()->getGLWidget(), Qt::Dialog) {
|
||||
|
||||
setWindowTitle("Metavoxel Network Simulator");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QVBoxLayout* topLayout = new QVBoxLayout();
|
||||
setLayout(topLayout);
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
topLayout->addLayout(form);
|
||||
|
||||
MetavoxelSystem::NetworkSimulation simulation = Application::getInstance()->getMetavoxels()->getNetworkSimulation();
|
||||
|
||||
form->addRow("Drop Rate:", _dropRate = new QDoubleSpinBox());
|
||||
_dropRate->setSuffix("%");
|
||||
_dropRate->setValue(simulation.dropRate * 100.0);
|
||||
connect(_dropRate, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Repeat Rate:", _repeatRate = new QDoubleSpinBox());
|
||||
_repeatRate->setSuffix("%");
|
||||
_repeatRate->setValue(simulation.repeatRate * 100.0);
|
||||
connect(_repeatRate, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Minimum Delay:", _minimumDelay = new QSpinBox());
|
||||
_minimumDelay->setMaximum(1000);
|
||||
_minimumDelay->setSuffix("ms");
|
||||
_minimumDelay->setValue(simulation.minimumDelay);
|
||||
connect(_minimumDelay, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Maximum Delay:", _maximumDelay = new QSpinBox());
|
||||
_maximumDelay->setMaximum(1000);
|
||||
_maximumDelay->setSuffix("ms");
|
||||
_maximumDelay->setValue(simulation.maximumDelay);
|
||||
connect(_maximumDelay, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
form->addRow("Bandwidth Limit:", _bandwidthLimit = new QSpinBox());
|
||||
_bandwidthLimit->setMaximum(1024 * 1024);
|
||||
_bandwidthLimit->setSuffix("KB/s");
|
||||
_bandwidthLimit->setValue(simulation.bandwidthLimit / BYTES_PER_KILOBYTE);
|
||||
connect(_bandwidthLimit, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
&MetavoxelNetworkSimulator::updateMetavoxelSystem);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this);
|
||||
topLayout->addWidget(buttons);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &QWidget::close);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
void MetavoxelNetworkSimulator::updateMetavoxelSystem() {
|
||||
int bandwidthLimit = _bandwidthLimit->value() * BYTES_PER_KILOBYTE;
|
||||
if (bandwidthLimit > 0) {
|
||||
// make sure the limit is enough to let at least one packet through
|
||||
const int MINIMUM_BANDWIDTH_LIMIT = 2048;
|
||||
bandwidthLimit = qMax(bandwidthLimit, MINIMUM_BANDWIDTH_LIMIT);
|
||||
}
|
||||
Application::getInstance()->getMetavoxels()->setNetworkSimulation(MetavoxelSystem::NetworkSimulation(
|
||||
_dropRate->value() / 100.0, _repeatRate->value() / 100.0, qMin(_minimumDelay->value(), _maximumDelay->value()),
|
||||
qMax(_minimumDelay->value(), _maximumDelay->value()), bandwidthLimit));
|
||||
}
|
41
interface/src/ui/MetavoxelNetworkSimulator.h
Normal file
41
interface/src/ui/MetavoxelNetworkSimulator.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// MetavoxelNetworkSimulator.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_MetavoxelNetworkSimulator_h
|
||||
#define hifi_MetavoxelNetworkSimulator_h
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QDoubleSpinBox;
|
||||
class QSpinBox;
|
||||
|
||||
/// Allows tweaking network simulation (packet drop percentage, etc.) settings for metavoxels.
|
||||
class MetavoxelNetworkSimulator : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelNetworkSimulator();
|
||||
|
||||
private slots:
|
||||
|
||||
void updateMetavoxelSystem();
|
||||
|
||||
private:
|
||||
|
||||
QDoubleSpinBox* _dropRate;
|
||||
QDoubleSpinBox* _repeatRate;
|
||||
QSpinBox* _minimumDelay;
|
||||
QSpinBox* _maximumDelay;
|
||||
QSpinBox* _bandwidthLimit;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelNetworkSimulator_h
|
|
@ -107,7 +107,8 @@ PacketRecord* Endpoint::maybeCreateReceiveRecord() const {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PacketRecord::PacketRecord(const MetavoxelLOD& lod, const MetavoxelData& data) :
|
||||
PacketRecord::PacketRecord(int packetNumber, const MetavoxelLOD& lod, const MetavoxelData& data) :
|
||||
_packetNumber(packetNumber),
|
||||
_lod(lod),
|
||||
_data(data) {
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
PacketRecord* baselineReceiveRecord = NULL);
|
||||
virtual ~Endpoint();
|
||||
|
||||
const DatagramSequencer& getSequencer() const { return _sequencer; }
|
||||
DatagramSequencer& getSequencer() { return _sequencer; }
|
||||
|
||||
virtual void update();
|
||||
|
||||
|
@ -45,10 +45,10 @@ protected slots:
|
|||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
void recordSend();
|
||||
void recordReceive();
|
||||
virtual void recordReceive();
|
||||
|
||||
void clearSendRecordsBefore(int index);
|
||||
void clearReceiveRecordsBefore(int index);
|
||||
virtual void clearSendRecordsBefore(int index);
|
||||
virtual void clearReceiveRecordsBefore(int index);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -71,14 +71,16 @@ protected:
|
|||
class PacketRecord {
|
||||
public:
|
||||
|
||||
PacketRecord(const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData());
|
||||
PacketRecord(int packetNumber = 0, const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData());
|
||||
virtual ~PacketRecord();
|
||||
|
||||
int getPacketNumber() const { return _packetNumber; }
|
||||
const MetavoxelLOD& getLOD() const { return _lod; }
|
||||
const MetavoxelData& getData() const { return _data; }
|
||||
|
||||
private:
|
||||
|
||||
int _packetNumber;
|
||||
MetavoxelLOD _lod;
|
||||
MetavoxelData _data;
|
||||
};
|
||||
|
|
|
@ -216,12 +216,71 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable)
|
|||
}
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::getAcknowledgedSendRecord(int packetNumber) const {
|
||||
PacketRecord* lastAcknowledged = getLastAcknowledgedSendRecord();
|
||||
if (lastAcknowledged->getPacketNumber() == packetNumber) {
|
||||
return lastAcknowledged;
|
||||
}
|
||||
foreach (PacketRecord* record, _clearedSendRecords) {
|
||||
if (record->getPacketNumber() == packetNumber) {
|
||||
return record;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::getAcknowledgedReceiveRecord(int packetNumber) const {
|
||||
PacketRecord* lastAcknowledged = getLastAcknowledgedReceiveRecord();
|
||||
if (lastAcknowledged->getPacketNumber() == packetNumber) {
|
||||
return lastAcknowledged;
|
||||
}
|
||||
foreach (PacketRecord* record, _clearedReceiveRecords) {
|
||||
if (record->getPacketNumber() == packetNumber) {
|
||||
return record;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MetavoxelClient::dataChanged(const MetavoxelData& oldData) {
|
||||
// make thread-safe copy
|
||||
QWriteLocker locker(&_dataCopyLock);
|
||||
_dataCopy = _data;
|
||||
}
|
||||
|
||||
void MetavoxelClient::recordReceive() {
|
||||
Endpoint::recordReceive();
|
||||
|
||||
// clear the cleared lists
|
||||
foreach (PacketRecord* record, _clearedSendRecords) {
|
||||
delete record;
|
||||
}
|
||||
_clearedSendRecords.clear();
|
||||
|
||||
foreach (PacketRecord* record, _clearedReceiveRecords) {
|
||||
delete record;
|
||||
}
|
||||
_clearedReceiveRecords.clear();
|
||||
}
|
||||
|
||||
void MetavoxelClient::clearSendRecordsBefore(int index) {
|
||||
// move to cleared list
|
||||
QList<PacketRecord*>::iterator end = _sendRecords.begin() + index + 1;
|
||||
for (QList<PacketRecord*>::const_iterator it = _sendRecords.begin(); it != end; it++) {
|
||||
_clearedSendRecords.append(*it);
|
||||
}
|
||||
_sendRecords.erase(_sendRecords.begin(), end);
|
||||
}
|
||||
|
||||
void MetavoxelClient::clearReceiveRecordsBefore(int index) {
|
||||
// move to cleared list
|
||||
QList<PacketRecord*>::iterator end = _receiveRecords.begin() + index + 1;
|
||||
for (QList<PacketRecord*>::const_iterator it = _receiveRecords.begin(); it != end; it++) {
|
||||
_clearedReceiveRecords.append(*it);
|
||||
}
|
||||
_receiveRecords.erase(_receiveRecords.begin(), end);
|
||||
}
|
||||
|
||||
void MetavoxelClient::writeUpdateMessage(Bitstream& out) {
|
||||
ClientStateMessage state = { _updater->getLOD() };
|
||||
out << QVariant::fromValue(state);
|
||||
|
@ -232,7 +291,9 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
|||
if (userType == MetavoxelDeltaMessage::Type) {
|
||||
PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord();
|
||||
if (_reliableDeltaChannel) {
|
||||
_remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = _reliableDeltaLOD);
|
||||
MetavoxelData reference = _remoteData;
|
||||
MetavoxelLOD referenceLOD = _remoteDataLOD;
|
||||
_remoteData.readDelta(reference, referenceLOD, in, _remoteDataLOD = _reliableDeltaLOD);
|
||||
_sequencer.getInputStream().persistReadMappings(in.getAndResetReadMappings());
|
||||
in.clearPersistentMappings();
|
||||
_reliableDeltaChannel = NULL;
|
||||
|
@ -255,13 +316,22 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
|||
}
|
||||
} else if (userType == MetavoxelDeltaPendingMessage::Type) {
|
||||
// check the id to make sure this is not a delta we've already processed
|
||||
int id = message.value<MetavoxelDeltaPendingMessage>().id;
|
||||
if (id > _reliableDeltaID) {
|
||||
_reliableDeltaID = id;
|
||||
MetavoxelDeltaPendingMessage pending = message.value<MetavoxelDeltaPendingMessage>();
|
||||
if (pending.id > _reliableDeltaID) {
|
||||
_reliableDeltaID = pending.id;
|
||||
_reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX);
|
||||
_reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream());
|
||||
_reliableDeltaLOD = getLastAcknowledgedSendRecord()->getLOD();
|
||||
PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord();
|
||||
PacketRecord* sendRecord = getAcknowledgedSendRecord(pending.receivedPacketNumber);
|
||||
if (!sendRecord) {
|
||||
qWarning() << "Missing send record for delta" << pending.receivedPacketNumber;
|
||||
return;
|
||||
}
|
||||
_reliableDeltaLOD = sendRecord->getLOD();
|
||||
PacketRecord* receiveRecord = getAcknowledgedReceiveRecord(pending.sentPacketNumber);
|
||||
if (!receiveRecord) {
|
||||
qWarning() << "Missing receive record for delta" << pending.sentPacketNumber;
|
||||
return;
|
||||
}
|
||||
_remoteDataLOD = receiveRecord->getLOD();
|
||||
_remoteData = receiveRecord->getData();
|
||||
}
|
||||
|
@ -271,10 +341,11 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
|||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::maybeCreateSendRecord() const {
|
||||
return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _updater->getLOD());
|
||||
return new PacketRecord(_sequencer.getOutgoingPacketNumber(),
|
||||
_reliableDeltaChannel ? _reliableDeltaLOD : _updater->getLOD());
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::maybeCreateReceiveRecord() const {
|
||||
return new PacketRecord(_remoteDataLOD, _remoteData);
|
||||
return new PacketRecord(_sequencer.getIncomingPacketNumber(), _remoteDataLOD, _remoteData);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,8 +116,16 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
PacketRecord* getAcknowledgedSendRecord(int packetNumber) const;
|
||||
PacketRecord* getAcknowledgedReceiveRecord(int packetNumber) const;
|
||||
|
||||
virtual void dataChanged(const MetavoxelData& oldData);
|
||||
|
||||
virtual void recordReceive();
|
||||
|
||||
virtual void clearSendRecordsBefore(int index);
|
||||
virtual void clearReceiveRecordsBefore(int index);
|
||||
|
||||
virtual void writeUpdateMessage(Bitstream& out);
|
||||
virtual void handleMessage(const QVariant& message, Bitstream& in);
|
||||
|
||||
|
@ -132,9 +140,13 @@ protected:
|
|||
ReliableChannel* _reliableDeltaChannel;
|
||||
MetavoxelLOD _reliableDeltaLOD;
|
||||
int _reliableDeltaID;
|
||||
QVariant _reliableDeltaMessage;
|
||||
|
||||
MetavoxelData _dataCopy;
|
||||
QReadWriteLock _dataCopyLock;
|
||||
|
||||
QList<PacketRecord*> _clearedSendRecords;
|
||||
QList<PacketRecord*> _clearedReceiveRecords;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelClientManager_h
|
||||
|
|
|
@ -734,6 +734,22 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no visible colors, we can clear everything
|
||||
bool foundOpaque = false;
|
||||
for (const QRgb* src = colorContents.constData(), *end = src + colorContents.size(); src != end; src++) {
|
||||
if (qAlpha(*src) != 0) {
|
||||
foundOpaque = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundOpaque) {
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0));
|
||||
info.outputValues[1] = AttributeValue(_outputs.at(1));
|
||||
info.outputValues[2] = AttributeValue(_outputs.at(2));
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
VoxelColorDataPointer newColorPointer(new VoxelColorData(colorContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(),
|
||||
encodeInline<VoxelColorDataPointer>(newColorPointer));
|
||||
|
|
|
@ -68,6 +68,8 @@ class MetavoxelDeltaPendingMessage {
|
|||
public:
|
||||
|
||||
STREAM int id;
|
||||
STREAM int sentPacketNumber;
|
||||
STREAM int receivedPacketNumber;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaPendingMessage)
|
||||
|
|
|
@ -81,7 +81,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
case PacketTypeAudioStreamStats:
|
||||
return 1;
|
||||
case PacketTypeMetavoxelData:
|
||||
return 7;
|
||||
return 8;
|
||||
case PacketTypeVoxelData:
|
||||
return VERSION_VOXELS_HAS_FILE_BREAKS;
|
||||
default:
|
||||
|
|
|
@ -603,31 +603,27 @@ int RandomVisitor::visit(MetavoxelInfo& info) {
|
|||
class TestSendRecord : public PacketRecord {
|
||||
public:
|
||||
|
||||
TestSendRecord(const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData(),
|
||||
const SharedObjectPointer& localState = SharedObjectPointer(), int packetNumber = 0);
|
||||
TestSendRecord(int packetNumber = 0, const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData(),
|
||||
const SharedObjectPointer& localState = SharedObjectPointer());
|
||||
|
||||
const SharedObjectPointer& getLocalState() const { return _localState; }
|
||||
int getPacketNumber() const { return _packetNumber; }
|
||||
|
||||
private:
|
||||
|
||||
SharedObjectPointer _localState;
|
||||
int _packetNumber;
|
||||
|
||||
};
|
||||
|
||||
TestSendRecord::TestSendRecord(const MetavoxelLOD& lod, const MetavoxelData& data,
|
||||
const SharedObjectPointer& localState, int packetNumber) :
|
||||
PacketRecord(lod, data),
|
||||
_localState(localState),
|
||||
_packetNumber(packetNumber) {
|
||||
TestSendRecord::TestSendRecord(int packetNumber, const MetavoxelLOD& lod, const MetavoxelData& data,
|
||||
const SharedObjectPointer& localState) :
|
||||
PacketRecord(packetNumber, lod, data),
|
||||
_localState(localState) {
|
||||
}
|
||||
|
||||
class TestReceiveRecord : public PacketRecord {
|
||||
public:
|
||||
|
||||
TestReceiveRecord(const MetavoxelLOD& lod = MetavoxelLOD(), const MetavoxelData& data = MetavoxelData(),
|
||||
const SharedObjectPointer& remoteState = SharedObjectPointer());
|
||||
TestReceiveRecord(int packetNumber = 0, const MetavoxelLOD& lod = MetavoxelLOD(),
|
||||
const MetavoxelData& data = MetavoxelData(), const SharedObjectPointer& remoteState = SharedObjectPointer());
|
||||
|
||||
const SharedObjectPointer& getRemoteState() const { return _remoteState; }
|
||||
|
||||
|
@ -636,9 +632,9 @@ private:
|
|||
SharedObjectPointer _remoteState;
|
||||
};
|
||||
|
||||
TestReceiveRecord::TestReceiveRecord(const MetavoxelLOD& lod,
|
||||
TestReceiveRecord::TestReceiveRecord(int packetNumber, const MetavoxelLOD& lod,
|
||||
const MetavoxelData& data, const SharedObjectPointer& remoteState) :
|
||||
PacketRecord(lod, data),
|
||||
PacketRecord(packetNumber, lod, data),
|
||||
_remoteState(remoteState) {
|
||||
}
|
||||
|
||||
|
@ -1110,14 +1106,14 @@ void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) {
|
|||
|
||||
PacketRecord* TestEndpoint::maybeCreateSendRecord() const {
|
||||
if (_reliableDeltaChannel) {
|
||||
return new TestSendRecord(_reliableDeltaLOD, _reliableDeltaData, _localState, _sequencer.getOutgoingPacketNumber());
|
||||
return new TestSendRecord(_sequencer.getOutgoingPacketNumber(), _reliableDeltaLOD, _reliableDeltaData, _localState);
|
||||
}
|
||||
return new TestSendRecord(_lod, (_mode == METAVOXEL_CLIENT_MODE) ? MetavoxelData() : _data,
|
||||
_localState, _sequencer.getOutgoingPacketNumber());
|
||||
return new TestSendRecord(_sequencer.getOutgoingPacketNumber(), _lod,
|
||||
(_mode == METAVOXEL_CLIENT_MODE) ? MetavoxelData() : _data, _localState);
|
||||
}
|
||||
|
||||
PacketRecord* TestEndpoint::maybeCreateReceiveRecord() const {
|
||||
return new TestReceiveRecord(_remoteDataLOD, _remoteData, _remoteState);
|
||||
return new TestReceiveRecord(_sequencer.getIncomingPacketNumber(), _remoteDataLOD, _remoteData, _remoteState);
|
||||
}
|
||||
|
||||
void TestEndpoint::handleHighPriorityMessage(const QVariant& message) {
|
||||
|
|
Loading…
Reference in a new issue