mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 08:49:05 +02:00
Merge pull request #2999 from ey6es/metavoxels
Provide a way to stream enums that aren't object properties, added tests for delta streaming, fixed Windows initialization bug.
This commit is contained in:
commit
5ed1dfc4b0
4 changed files with 272 additions and 107 deletions
|
@ -79,10 +79,6 @@ IDStreamer& IDStreamer::operator>>(int& value) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QByteArray getEnumName(const QMetaEnum& metaEnum) {
|
|
||||||
return QByteArray(metaEnum.scope()) + "::" + metaEnum.name();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) {
|
int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) {
|
||||||
getMetaObjects().insert(className, metaObject);
|
getMetaObjects().insert(className, metaObject);
|
||||||
|
|
||||||
|
@ -90,17 +86,6 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta
|
||||||
for (const QMetaObject* superClass = metaObject; superClass; superClass = superClass->superClass()) {
|
for (const QMetaObject* superClass = metaObject; superClass; superClass = superClass->superClass()) {
|
||||||
getMetaObjectSubClasses().insert(superClass, metaObject);
|
getMetaObjectSubClasses().insert(superClass, metaObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the streamers for all enumerators
|
|
||||||
// temporarily disabled: crashes on Windows
|
|
||||||
//for (int i = 0; i < metaObject->enumeratorCount(); i++) {
|
|
||||||
// QMetaEnum metaEnum = metaObject->enumerator(i);
|
|
||||||
// const TypeStreamer*& streamer = getEnumStreamers()[QPair<QByteArray, QByteArray>(metaEnum.scope(), metaEnum.name())];
|
|
||||||
// if (!streamer) {
|
|
||||||
// getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum));
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +210,8 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) {
|
||||||
}
|
}
|
||||||
connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*)));
|
connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*)));
|
||||||
QPointer<SharedObject>& reference = _sharedObjectReferences[it.key()->getOriginID()];
|
QPointer<SharedObject>& reference = _sharedObjectReferences[it.key()->getOriginID()];
|
||||||
if (reference) {
|
if (reference && reference != it.key()) {
|
||||||
|
// the object has been replaced by a successor, so we can forget about the original
|
||||||
_sharedObjectStreamer.removePersistentID(reference);
|
_sharedObjectStreamer.removePersistentID(reference);
|
||||||
reference->disconnect(this);
|
reference->disconnect(this);
|
||||||
}
|
}
|
||||||
|
@ -259,7 +245,8 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()];
|
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()];
|
||||||
if (reference) {
|
if (reference && reference != it.value()) {
|
||||||
|
// the object has been replaced by a successor, so we can forget about the original
|
||||||
_sharedObjectStreamer.removePersistentValue(reference.data());
|
_sharedObjectStreamer.removePersistentValue(reference.data());
|
||||||
}
|
}
|
||||||
reference = it.value();
|
reference = it.value();
|
||||||
|
@ -311,7 +298,7 @@ void Bitstream::writeRawDelta(const QObject* value, const QObject* reference) {
|
||||||
}
|
}
|
||||||
const QMetaObject* metaObject = value->metaObject();
|
const QMetaObject* metaObject = value->metaObject();
|
||||||
_metaObjectStreamer << metaObject;
|
_metaObjectStreamer << metaObject;
|
||||||
foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) {
|
foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) {
|
||||||
propertyWriter.writeDelta(*this, value, reference);
|
propertyWriter.writeDelta(*this, value, reference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,7 +476,7 @@ Bitstream& Bitstream::operator<<(const QObject* object) {
|
||||||
}
|
}
|
||||||
const QMetaObject* metaObject = object->metaObject();
|
const QMetaObject* metaObject = object->metaObject();
|
||||||
_metaObjectStreamer << metaObject;
|
_metaObjectStreamer << metaObject;
|
||||||
foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) {
|
foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) {
|
||||||
propertyWriter.write(*this, object);
|
propertyWriter.write(*this, object);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -574,7 +561,7 @@ Bitstream& Bitstream::operator<(const QMetaObject* metaObject) {
|
||||||
if (_metadataType == NO_METADATA) {
|
if (_metadataType == NO_METADATA) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
const QVector<PropertyWriter>& propertyWriters = getPropertyWriters(metaObject);
|
const QVector<PropertyWriter>& propertyWriters = getPropertyWriters().value(metaObject);
|
||||||
*this << propertyWriters.size();
|
*this << propertyWriters.size();
|
||||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||||
foreach (const PropertyWriter& propertyWriter, propertyWriters) {
|
foreach (const PropertyWriter& propertyWriter, propertyWriters) {
|
||||||
|
@ -608,7 +595,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
||||||
qWarning() << "Unknown class name: " << className << "\n";
|
qWarning() << "Unknown class name: " << className << "\n";
|
||||||
}
|
}
|
||||||
if (_metadataType == NO_METADATA) {
|
if (_metadataType == NO_METADATA) {
|
||||||
objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject));
|
objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
int storedPropertyCount;
|
int storedPropertyCount;
|
||||||
|
@ -632,7 +619,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
||||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||||
bool matches = true;
|
bool matches = true;
|
||||||
if (metaObject) {
|
if (metaObject) {
|
||||||
const QVector<PropertyWriter>& propertyWriters = getPropertyWriters(metaObject);
|
const QVector<PropertyWriter>& propertyWriters = getPropertyWriters().value(metaObject);
|
||||||
if (propertyWriters.size() == properties.size()) {
|
if (propertyWriters.size() == properties.size()) {
|
||||||
for (int i = 0; i < propertyWriters.size(); i++) {
|
for (int i = 0; i < propertyWriters.size(); i++) {
|
||||||
const PropertyWriter& propertyWriter = propertyWriters.at(i);
|
const PropertyWriter& propertyWriter = propertyWriters.at(i);
|
||||||
|
@ -651,7 +638,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
||||||
QByteArray remoteHashResult(localHashResult.size(), 0);
|
QByteArray remoteHashResult(localHashResult.size(), 0);
|
||||||
read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE);
|
read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE);
|
||||||
if (metaObject && matches && localHashResult == remoteHashResult) {
|
if (metaObject && matches && localHashResult == remoteHashResult) {
|
||||||
objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject));
|
objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -988,31 +975,6 @@ void Bitstream::clearSharedObject(QObject* object) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVector<PropertyWriter>& Bitstream::getPropertyWriters(const QMetaObject* metaObject) {
|
|
||||||
QVector<PropertyWriter>& propertyWriters = _propertyWriters[metaObject];
|
|
||||||
if (propertyWriters.isEmpty()) {
|
|
||||||
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
|
||||||
QMetaProperty property = metaObject->property(i);
|
|
||||||
if (!property.isStored()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const TypeStreamer* streamer;
|
|
||||||
if (property.isEnumType()) {
|
|
||||||
QMetaEnum metaEnum = property.enumerator();
|
|
||||||
streamer = getEnumStreamers().value(QPair<QByteArray, QByteArray>(
|
|
||||||
QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())),
|
|
||||||
QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name()))));
|
|
||||||
} else {
|
|
||||||
streamer = getTypeStreamers().value(property.userType());
|
|
||||||
}
|
|
||||||
if (streamer) {
|
|
||||||
propertyWriters.append(PropertyWriter(property, streamer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return propertyWriters;
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<QByteArray, const QMetaObject*>& Bitstream::getMetaObjects() {
|
QHash<QByteArray, const QMetaObject*>& Bitstream::getMetaObjects() {
|
||||||
static QHash<QByteArray, const QMetaObject*> metaObjects;
|
static QHash<QByteArray, const QMetaObject*> metaObjects;
|
||||||
return metaObjects;
|
return metaObjects;
|
||||||
|
@ -1028,21 +990,47 @@ QHash<int, const TypeStreamer*>& Bitstream::getTypeStreamers() {
|
||||||
return typeStreamers;
|
return typeStreamers;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& Bitstream::getEnumStreamers() {
|
const QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& Bitstream::getEnumStreamers() {
|
||||||
static QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> enumStreamers;
|
static QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> enumStreamers = createEnumStreamers();
|
||||||
return enumStreamers;
|
return enumStreamers;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QByteArray, const TypeStreamer*>& Bitstream::getEnumStreamersByName() {
|
QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> Bitstream::createEnumStreamers() {
|
||||||
static QHash<QByteArray, const TypeStreamer*> enumStreamersByName;
|
QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> enumStreamers;
|
||||||
|
foreach (const QMetaObject* metaObject, getMetaObjects()) {
|
||||||
|
for (int i = 0; i < metaObject->enumeratorCount(); i++) {
|
||||||
|
QMetaEnum metaEnum = metaObject->enumerator(i);
|
||||||
|
const TypeStreamer*& streamer = enumStreamers[QPair<QByteArray, QByteArray>(metaEnum.scope(), metaEnum.name())];
|
||||||
|
if (!streamer) {
|
||||||
|
streamer = new EnumTypeStreamer(metaEnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return enumStreamers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QHash<QByteArray, const TypeStreamer*>& Bitstream::getEnumStreamersByName() {
|
||||||
|
static QHash<QByteArray, const TypeStreamer*> enumStreamersByName = createEnumStreamersByName();
|
||||||
return enumStreamersByName;
|
return enumStreamersByName;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<PropertyReader> Bitstream::getPropertyReaders(const QMetaObject* metaObject) {
|
QHash<QByteArray, const TypeStreamer*> Bitstream::createEnumStreamersByName() {
|
||||||
QVector<PropertyReader> propertyReaders;
|
QHash<QByteArray, const TypeStreamer*> enumStreamersByName;
|
||||||
if (!metaObject) {
|
foreach (const TypeStreamer* streamer, getEnumStreamers()) {
|
||||||
|
enumStreamersByName.insert(streamer->getName(), streamer);
|
||||||
|
}
|
||||||
|
return enumStreamersByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QHash<const QMetaObject*, QVector<PropertyReader> >& Bitstream::getPropertyReaders() {
|
||||||
|
static QHash<const QMetaObject*, QVector<PropertyReader> > propertyReaders = createPropertyReaders();
|
||||||
return propertyReaders;
|
return propertyReaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QHash<const QMetaObject*, QVector<PropertyReader> > Bitstream::createPropertyReaders() {
|
||||||
|
QHash<const QMetaObject*, QVector<PropertyReader> > propertyReaders;
|
||||||
|
foreach (const QMetaObject* metaObject, getMetaObjects()) {
|
||||||
|
QVector<PropertyReader>& readers = propertyReaders[metaObject];
|
||||||
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
||||||
QMetaProperty property = metaObject->property(i);
|
QMetaProperty property = metaObject->property(i);
|
||||||
if (!property.isStored()) {
|
if (!property.isStored()) {
|
||||||
|
@ -1058,12 +1046,44 @@ QVector<PropertyReader> Bitstream::getPropertyReaders(const QMetaObject* metaObj
|
||||||
streamer = getTypeStreamers().value(property.userType());
|
streamer = getTypeStreamers().value(property.userType());
|
||||||
}
|
}
|
||||||
if (streamer) {
|
if (streamer) {
|
||||||
propertyReaders.append(PropertyReader(TypeReader(QByteArray(), streamer), property));
|
readers.append(PropertyReader(TypeReader(QByteArray(), streamer), property));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return propertyReaders;
|
return propertyReaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QHash<const QMetaObject*, QVector<PropertyWriter> >& Bitstream::getPropertyWriters() {
|
||||||
|
static QHash<const QMetaObject*, QVector<PropertyWriter> > propertyWriters = createPropertyWriters();
|
||||||
|
return propertyWriters;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<const QMetaObject*, QVector<PropertyWriter> > Bitstream::createPropertyWriters() {
|
||||||
|
QHash<const QMetaObject*, QVector<PropertyWriter> > propertyWriters;
|
||||||
|
foreach (const QMetaObject* metaObject, getMetaObjects()) {
|
||||||
|
QVector<PropertyWriter>& writers = propertyWriters[metaObject];
|
||||||
|
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
||||||
|
QMetaProperty property = metaObject->property(i);
|
||||||
|
if (!property.isStored()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const TypeStreamer* streamer;
|
||||||
|
if (property.isEnumType()) {
|
||||||
|
QMetaEnum metaEnum = property.enumerator();
|
||||||
|
streamer = getEnumStreamers().value(QPair<QByteArray, QByteArray>(
|
||||||
|
QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())),
|
||||||
|
QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name()))));
|
||||||
|
} else {
|
||||||
|
streamer = getTypeStreamers().value(property.userType());
|
||||||
|
}
|
||||||
|
if (streamer) {
|
||||||
|
writers.append(PropertyWriter(property, streamer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return propertyWriters;
|
||||||
|
}
|
||||||
|
|
||||||
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer) :
|
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer) :
|
||||||
_typeName(typeName),
|
_typeName(typeName),
|
||||||
_streamer(streamer),
|
_streamer(streamer),
|
||||||
|
@ -1461,17 +1481,21 @@ QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) {
|
||||||
return debug << (metaObject ? metaObject->className() : "null");
|
return debug << (metaObject ? metaObject->className() : "null");
|
||||||
}
|
}
|
||||||
|
|
||||||
EnumTypeStreamer::EnumTypeStreamer(const QMetaEnum& metaEnum) :
|
EnumTypeStreamer::EnumTypeStreamer(const QMetaObject* metaObject, const char* name) :
|
||||||
_metaEnum(metaEnum),
|
_metaObject(metaObject),
|
||||||
_name(getEnumName(metaEnum)) {
|
_enumName(name),
|
||||||
|
_name(QByteArray(metaObject->className()) + "::" + name),
|
||||||
|
_bits(-1) {
|
||||||
|
|
||||||
setType(QMetaType::Int);
|
setType(QMetaType::Int);
|
||||||
|
|
||||||
int highestValue = 0;
|
|
||||||
for (int j = 0; j < metaEnum.keyCount(); j++) {
|
|
||||||
highestValue = qMax(highestValue, metaEnum.value(j));
|
|
||||||
}
|
}
|
||||||
_bits = getBitsForHighestValue(highestValue);
|
|
||||||
|
EnumTypeStreamer::EnumTypeStreamer(const QMetaEnum& metaEnum) :
|
||||||
|
_name(QByteArray(metaEnum.scope()) + "::" + metaEnum.name()),
|
||||||
|
_metaEnum(metaEnum),
|
||||||
|
_bits(-1) {
|
||||||
|
|
||||||
|
setType(QMetaType::Int);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* EnumTypeStreamer::getName() const {
|
const char* EnumTypeStreamer::getName() const {
|
||||||
|
@ -1483,10 +1507,21 @@ TypeReader::Type EnumTypeStreamer::getReaderType() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int EnumTypeStreamer::getBits() const {
|
int EnumTypeStreamer::getBits() const {
|
||||||
|
if (_bits == -1) {
|
||||||
|
int highestValue = 0;
|
||||||
|
QMetaEnum metaEnum = getMetaEnum();
|
||||||
|
for (int j = 0; j < metaEnum.keyCount(); j++) {
|
||||||
|
highestValue = qMax(highestValue, metaEnum.value(j));
|
||||||
|
}
|
||||||
|
const_cast<EnumTypeStreamer*>(this)->_bits = getBitsForHighestValue(highestValue);
|
||||||
|
}
|
||||||
return _bits;
|
return _bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMetaEnum EnumTypeStreamer::getMetaEnum() const {
|
QMetaEnum EnumTypeStreamer::getMetaEnum() const {
|
||||||
|
if (!_metaEnum.isValid()) {
|
||||||
|
const_cast<EnumTypeStreamer*>(this)->_metaEnum = _metaObject->enumerator(_metaObject->indexOfEnumerator(_enumName));
|
||||||
|
}
|
||||||
return _metaEnum;
|
return _metaEnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1496,12 +1531,12 @@ bool EnumTypeStreamer::equal(const QVariant& first, const QVariant& second) cons
|
||||||
|
|
||||||
void EnumTypeStreamer::write(Bitstream& out, const QVariant& value) const {
|
void EnumTypeStreamer::write(Bitstream& out, const QVariant& value) const {
|
||||||
int intValue = value.toInt();
|
int intValue = value.toInt();
|
||||||
out.write(&intValue, _bits);
|
out.write(&intValue, getBits());
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant EnumTypeStreamer::read(Bitstream& in) const {
|
QVariant EnumTypeStreamer::read(Bitstream& in) const {
|
||||||
int intValue = 0;
|
int intValue = 0;
|
||||||
in.read(&intValue, _bits);
|
in.read(&intValue, getBits());
|
||||||
return intValue;
|
return intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1511,7 +1546,7 @@ void EnumTypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const Q
|
||||||
out << false;
|
out << false;
|
||||||
} else {
|
} else {
|
||||||
out << true;
|
out << true;
|
||||||
out.write(&intValue, _bits);
|
out.write(&intValue, getBits());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1520,7 +1555,7 @@ void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant&
|
||||||
in >> changed;
|
in >> changed;
|
||||||
if (changed) {
|
if (changed) {
|
||||||
int intValue = 0;
|
int intValue = 0;
|
||||||
in.read(&intValue, _bits);
|
in.read(&intValue, getBits());
|
||||||
value = intValue;
|
value = intValue;
|
||||||
} else {
|
} else {
|
||||||
value = reference;
|
value = reference;
|
||||||
|
@ -1529,17 +1564,17 @@ void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant&
|
||||||
|
|
||||||
void EnumTypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const {
|
void EnumTypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const {
|
||||||
int intValue = value.toInt();
|
int intValue = value.toInt();
|
||||||
out.write(&intValue, _bits);
|
out.write(&intValue, getBits());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const {
|
void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const {
|
||||||
int intValue = 0;
|
int intValue = 0;
|
||||||
in.read(&intValue, _bits);
|
in.read(&intValue, getBits());
|
||||||
value = intValue;
|
value = intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash<int, int>& mappings) const {
|
void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash<int, int>& mappings) const {
|
||||||
if (_metaEnum.isFlag()) {
|
if (getMetaEnum().isFlag()) {
|
||||||
int combined = 0;
|
int combined = 0;
|
||||||
for (QHash<int, int>::const_iterator it = mappings.constBegin(); it != mappings.constEnd(); it++) {
|
for (QHash<int, int>::const_iterator it = mappings.constBegin(); it != mappings.constEnd(); it++) {
|
||||||
if (value & it.key()) {
|
if (value & it.key()) {
|
||||||
|
|
|
@ -400,8 +400,6 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const QVector<PropertyWriter>& getPropertyWriters(const QMetaObject* metaObject);
|
|
||||||
|
|
||||||
QDataStream& _underlying;
|
QDataStream& _underlying;
|
||||||
quint8 _byte;
|
quint8 _byte;
|
||||||
int _position;
|
int _position;
|
||||||
|
@ -421,14 +419,17 @@ private:
|
||||||
QHash<QByteArray, const QMetaObject*> _metaObjectSubstitutions;
|
QHash<QByteArray, const QMetaObject*> _metaObjectSubstitutions;
|
||||||
QHash<QByteArray, const TypeStreamer*> _typeStreamerSubstitutions;
|
QHash<QByteArray, const TypeStreamer*> _typeStreamerSubstitutions;
|
||||||
|
|
||||||
QHash<const QMetaObject*, QVector<PropertyWriter> > _propertyWriters;
|
|
||||||
|
|
||||||
static QHash<QByteArray, const QMetaObject*>& getMetaObjects();
|
static QHash<QByteArray, const QMetaObject*>& getMetaObjects();
|
||||||
static QMultiHash<const QMetaObject*, const QMetaObject*>& getMetaObjectSubClasses();
|
static QMultiHash<const QMetaObject*, const QMetaObject*>& getMetaObjectSubClasses();
|
||||||
static QHash<int, const TypeStreamer*>& getTypeStreamers();
|
static QHash<int, const TypeStreamer*>& getTypeStreamers();
|
||||||
static QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& getEnumStreamers();
|
static const QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& getEnumStreamers();
|
||||||
static QHash<QByteArray, const TypeStreamer*>& getEnumStreamersByName();
|
static QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> createEnumStreamers();
|
||||||
static QVector<PropertyReader> getPropertyReaders(const QMetaObject* metaObject);
|
static const QHash<QByteArray, const TypeStreamer*>& getEnumStreamersByName();
|
||||||
|
static QHash<QByteArray, const TypeStreamer*> createEnumStreamersByName();
|
||||||
|
static const QHash<const QMetaObject*, QVector<PropertyReader> >& getPropertyReaders();
|
||||||
|
static QHash<const QMetaObject*, QVector<PropertyReader> > createPropertyReaders();
|
||||||
|
static const QHash<const QMetaObject*, QVector<PropertyWriter> >& getPropertyWriters();
|
||||||
|
static QHash<const QMetaObject*, QVector<PropertyWriter> > createPropertyWriters();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T> inline void Bitstream::writeDelta(const T& value, const T& reference) {
|
template<class T> inline void Bitstream::writeDelta(const T& value, const T& reference) {
|
||||||
|
@ -938,6 +939,7 @@ public:
|
||||||
class EnumTypeStreamer : public TypeStreamer {
|
class EnumTypeStreamer : public TypeStreamer {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
EnumTypeStreamer(const QMetaObject* metaObject, const char* name);
|
||||||
EnumTypeStreamer(const QMetaEnum& metaEnum);
|
EnumTypeStreamer(const QMetaEnum& metaEnum);
|
||||||
|
|
||||||
virtual const char* getName() const;
|
virtual const char* getName() const;
|
||||||
|
@ -955,8 +957,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QMetaEnum _metaEnum;
|
const QMetaObject* _metaObject;
|
||||||
|
const char* _enumName;
|
||||||
QByteArray _name;
|
QByteArray _name;
|
||||||
|
QMetaEnum _metaEnum;
|
||||||
int _bits;
|
int _bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1037,12 +1041,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Macro for registering simple type streamers.
|
/// Macro for registering simple type streamers.
|
||||||
#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \
|
#define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \
|
||||||
Bitstream::registerTypeStreamer(qMetaTypeId<x>(), new SimpleTypeStreamer<x>());
|
Bitstream::registerTypeStreamer(qMetaTypeId<X>(), new SimpleTypeStreamer<X>());
|
||||||
|
|
||||||
/// Macro for registering collection type streamers.
|
/// Macro for registering collection type streamers.
|
||||||
#define REGISTER_COLLECTION_TYPE_STREAMER(x) static int x##Streamer = \
|
#define REGISTER_COLLECTION_TYPE_STREAMER(X) static int x##Streamer = \
|
||||||
Bitstream::registerTypeStreamer(qMetaTypeId<x>(), new CollectionTypeStreamer<x>());
|
Bitstream::registerTypeStreamer(qMetaTypeId<X>(), new CollectionTypeStreamer<X>());
|
||||||
|
|
||||||
/// Declares the metatype and the streaming operators. The last lines
|
/// Declares the metatype and the streaming operators. The last lines
|
||||||
/// ensure that the generated file will be included in the link phase.
|
/// ensure that the generated file will be included in the link phase.
|
||||||
|
@ -1077,14 +1081,42 @@ public:
|
||||||
_Pragma(STRINGIFY(unused(_TypePtr##X)))
|
_Pragma(STRINGIFY(unused(_TypePtr##X)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DECLARE_ENUM_METATYPE(S, N) Q_DECLARE_METATYPE(S::N) \
|
||||||
|
Bitstream& operator<<(Bitstream& out, const S::N& obj); \
|
||||||
|
Bitstream& operator>>(Bitstream& in, S::N& obj); \
|
||||||
|
template<> inline void Bitstream::writeRawDelta(const S::N& value, const S::N& reference) { *this << value; } \
|
||||||
|
template<> inline void Bitstream::readRawDelta(S::N& value, const S::N& reference) { *this >> value; }
|
||||||
|
|
||||||
|
#define IMPLEMENT_ENUM_METATYPE(S, N) \
|
||||||
|
static int S##N##MetaTypeId = registerEnumMetaType<S::N>(&S::staticMetaObject, #N); \
|
||||||
|
Bitstream& operator<<(Bitstream& out, const S::N& obj) { \
|
||||||
|
static int bits = Bitstream::getTypeStreamer(qMetaTypeId<S::N>())->getBits(); \
|
||||||
|
return out.write(&obj, bits); \
|
||||||
|
} \
|
||||||
|
Bitstream& operator>>(Bitstream& in, S::N& obj) { \
|
||||||
|
static int bits = Bitstream::getTypeStreamer(qMetaTypeId<S::N>())->getBits(); \
|
||||||
|
obj = (S::N)0; \
|
||||||
|
return in.read(&obj, bits); \
|
||||||
|
}
|
||||||
|
|
||||||
/// Registers a simple type and its streamer.
|
/// Registers a simple type and its streamer.
|
||||||
|
/// \return the metatype id
|
||||||
template<class T> int registerSimpleMetaType() {
|
template<class T> int registerSimpleMetaType() {
|
||||||
int type = qRegisterMetaType<T>();
|
int type = qRegisterMetaType<T>();
|
||||||
Bitstream::registerTypeStreamer(type, new SimpleTypeStreamer<T>());
|
Bitstream::registerTypeStreamer(type, new SimpleTypeStreamer<T>());
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers an enum type and its streamer.
|
||||||
|
/// \return the metatype id
|
||||||
|
template<class T> int registerEnumMetaType(const QMetaObject* metaObject, const char* name) {
|
||||||
|
int type = qRegisterMetaType<T>();
|
||||||
|
Bitstream::registerTypeStreamer(type, new EnumTypeStreamer(metaObject, name));
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
/// Registers a streamable type and its streamer.
|
/// Registers a streamable type and its streamer.
|
||||||
|
/// \return the metatype id
|
||||||
template<class T> int registerStreamableMetaType() {
|
template<class T> int registerStreamableMetaType() {
|
||||||
int type = qRegisterMetaType<T>();
|
int type = qRegisterMetaType<T>();
|
||||||
Bitstream::registerTypeStreamer(type, new StreamableTypeStreamer<T>());
|
Bitstream::registerTypeStreamer(type, new StreamableTypeStreamer<T>());
|
||||||
|
@ -1092,6 +1124,7 @@ template<class T> int registerStreamableMetaType() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a collection type and its streamer.
|
/// Registers a collection type and its streamer.
|
||||||
|
/// \return the metatype id
|
||||||
template<class T> int registerCollectionMetaType() {
|
template<class T> int registerCollectionMetaType() {
|
||||||
int type = qRegisterMetaType<T>();
|
int type = qRegisterMetaType<T>();
|
||||||
Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer<T>());
|
Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer<T>());
|
||||||
|
|
|
@ -20,12 +20,16 @@
|
||||||
REGISTER_META_OBJECT(TestSharedObjectA)
|
REGISTER_META_OBJECT(TestSharedObjectA)
|
||||||
REGISTER_META_OBJECT(TestSharedObjectB)
|
REGISTER_META_OBJECT(TestSharedObjectB)
|
||||||
|
|
||||||
|
IMPLEMENT_ENUM_METATYPE(TestSharedObjectA, TestEnum)
|
||||||
|
|
||||||
MetavoxelTests::MetavoxelTests(int& argc, char** argv) :
|
MetavoxelTests::MetavoxelTests(int& argc, char** argv) :
|
||||||
QCoreApplication(argc, argv) {
|
QCoreApplication(argc, argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int datagramsSent = 0;
|
static int datagramsSent = 0;
|
||||||
static int datagramsReceived = 0;
|
static int datagramsReceived = 0;
|
||||||
|
static int bytesSent = 0;
|
||||||
|
static int bytesReceived = 0;
|
||||||
static int highPriorityMessagesSent = 0;
|
static int highPriorityMessagesSent = 0;
|
||||||
static int highPriorityMessagesReceived = 0;
|
static int highPriorityMessagesReceived = 0;
|
||||||
static int unreliableMessagesSent = 0;
|
static int unreliableMessagesSent = 0;
|
||||||
|
@ -36,6 +40,7 @@ static int streamedBytesSent = 0;
|
||||||
static int streamedBytesReceived = 0;
|
static int streamedBytesReceived = 0;
|
||||||
static int sharedObjectsCreated = 0;
|
static int sharedObjectsCreated = 0;
|
||||||
static int sharedObjectsDestroyed = 0;
|
static int sharedObjectsDestroyed = 0;
|
||||||
|
static int objectMutationsPerformed = 0;
|
||||||
|
|
||||||
static QByteArray createRandomBytes(int minimumSize, int maximumSize) {
|
static QByteArray createRandomBytes(int minimumSize, int maximumSize) {
|
||||||
QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0);
|
QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0);
|
||||||
|
@ -80,6 +85,7 @@ static TestMessageC createRandomMessageC() {
|
||||||
message.bar = rand();
|
message.bar = rand();
|
||||||
message.baz = randFloat();
|
message.baz = randFloat();
|
||||||
message.bong.foo = createRandomBytes();
|
message.bong.foo = createRandomBytes();
|
||||||
|
message.bong.baz = getRandomTestEnum();
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +186,7 @@ bool MetavoxelTests::run() {
|
||||||
bob.setOther(&alice);
|
bob.setOther(&alice);
|
||||||
|
|
||||||
// perform a large number of simulation iterations
|
// perform a large number of simulation iterations
|
||||||
const int SIMULATION_ITERATIONS = 100000;
|
const int SIMULATION_ITERATIONS = 10000;
|
||||||
for (int i = 0; i < SIMULATION_ITERATIONS; i++) {
|
for (int i = 0; i < SIMULATION_ITERATIONS; i++) {
|
||||||
if (alice.simulate(i) || bob.simulate(i)) {
|
if (alice.simulate(i) || bob.simulate(i)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -191,8 +197,10 @@ bool MetavoxelTests::run() {
|
||||||
qDebug() << "Sent" << unreliableMessagesSent << "unreliable messages, received" << unreliableMessagesReceived;
|
qDebug() << "Sent" << unreliableMessagesSent << "unreliable messages, received" << unreliableMessagesReceived;
|
||||||
qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived;
|
qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived;
|
||||||
qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived;
|
qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived;
|
||||||
qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived;
|
qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" <<
|
||||||
|
datagramsReceived << "with" << bytesReceived << "bytes";
|
||||||
qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed;
|
qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed;
|
||||||
|
qDebug() << "Performed" << objectMutationsPerformed << "object mutations";
|
||||||
qDebug();
|
qDebug();
|
||||||
|
|
||||||
qDebug() << "Running serialization tests...";
|
qDebug() << "Running serialization tests...";
|
||||||
|
@ -226,6 +234,20 @@ Endpoint::Endpoint(const QByteArray& datagramHeader) :
|
||||||
connect(_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)),
|
connect(_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)),
|
||||||
SLOT(handleHighPriorityMessage(const QVariant&)));
|
SLOT(handleHighPriorityMessage(const QVariant&)));
|
||||||
|
|
||||||
|
connect(_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int)));
|
||||||
|
connect(_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int)));
|
||||||
|
|
||||||
|
// insert the baseline send record
|
||||||
|
SendRecord sendRecord = { 0 };
|
||||||
|
_sendRecords.append(sendRecord);
|
||||||
|
|
||||||
|
// insert the baseline receive record
|
||||||
|
ReceiveRecord receiveRecord = { 0 };
|
||||||
|
_receiveRecords.append(receiveRecord);
|
||||||
|
|
||||||
|
// create the object that represents out delta-encoded state
|
||||||
|
_localState = new TestSharedObjectA();
|
||||||
|
|
||||||
connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)),
|
connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)),
|
||||||
SLOT(handleReliableMessage(const QVariant&)));
|
SLOT(handleReliableMessage(const QVariant&)));
|
||||||
|
|
||||||
|
@ -252,16 +274,40 @@ static QVariant createRandomMessage() {
|
||||||
return QVariant::fromValue(message);
|
return QVariant::fromValue(message);
|
||||||
}
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
TestMessageB message = { createRandomBytes(), createRandomSharedObject() };
|
TestMessageB message = { createRandomBytes(), createRandomSharedObject(), getRandomTestEnum() };
|
||||||
return QVariant::fromValue(message);
|
return QVariant::fromValue(message);
|
||||||
}
|
}
|
||||||
case 2:
|
|
||||||
default: {
|
default: {
|
||||||
return QVariant::fromValue(createRandomMessageC());
|
return QVariant::fromValue(createRandomMessageC());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SharedObjectPointer mutate(const SharedObjectPointer& state) {
|
||||||
|
switch(randIntInRange(0, 3)) {
|
||||||
|
case 0: {
|
||||||
|
SharedObjectPointer newState = state->clone(true);
|
||||||
|
static_cast<TestSharedObjectA*>(newState.data())->setFoo(randFloat());
|
||||||
|
objectMutationsPerformed++;
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
SharedObjectPointer newState = state->clone(true);
|
||||||
|
static_cast<TestSharedObjectA*>(newState.data())->setBaz(getRandomTestEnum());
|
||||||
|
objectMutationsPerformed++;
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
SharedObjectPointer newState = state->clone(true);
|
||||||
|
static_cast<TestSharedObjectA*>(newState.data())->setBong(getRandomTestFlags());
|
||||||
|
objectMutationsPerformed++;
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMessage) {
|
static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMessage) {
|
||||||
int type = firstMessage.userType();
|
int type = firstMessage.userType();
|
||||||
if (secondMessage.userType() != type) {
|
if (secondMessage.userType() != type) {
|
||||||
|
@ -273,7 +319,7 @@ static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMe
|
||||||
} else if (type == TestMessageB::Type) {
|
} else if (type == TestMessageB::Type) {
|
||||||
TestMessageB first = firstMessage.value<TestMessageB>();
|
TestMessageB first = firstMessage.value<TestMessageB>();
|
||||||
TestMessageB second = secondMessage.value<TestMessageB>();
|
TestMessageB second = secondMessage.value<TestMessageB>();
|
||||||
return first.foo == second.foo && equals(first.bar, second.bar);
|
return first.foo == second.foo && equals(first.bar, second.bar) && first.baz == second.baz;
|
||||||
|
|
||||||
} else if (type == TestMessageC::Type) {
|
} else if (type == TestMessageC::Type) {
|
||||||
return firstMessage.value<TestMessageC>() == secondMessage.value<TestMessageC>();
|
return firstMessage.value<TestMessageC>() == secondMessage.value<TestMessageC>();
|
||||||
|
@ -320,10 +366,13 @@ bool Endpoint::simulate(int iterationNumber) {
|
||||||
_reliableMessagesToSend -= 1.0f;
|
_reliableMessagesToSend -= 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tweak the local state
|
||||||
|
_localState = mutate(_localState);
|
||||||
|
|
||||||
// send a packet
|
// send a packet
|
||||||
try {
|
try {
|
||||||
Bitstream& out = _sequencer->startPacket();
|
Bitstream& out = _sequencer->startPacket();
|
||||||
SequencedTestMessage message = { iterationNumber, createRandomMessage() };
|
SequencedTestMessage message = { iterationNumber, createRandomMessage(), _localState };
|
||||||
_unreliableMessagesSent.append(message);
|
_unreliableMessagesSent.append(message);
|
||||||
unreliableMessagesSent++;
|
unreliableMessagesSent++;
|
||||||
out << message;
|
out << message;
|
||||||
|
@ -334,11 +383,16 @@ bool Endpoint::simulate(int iterationNumber) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// record the send
|
||||||
|
SendRecord record = { _sequencer->getOutgoingPacketNumber(), _localState };
|
||||||
|
_sendRecords.append(record);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::sendDatagram(const QByteArray& datagram) {
|
void Endpoint::sendDatagram(const QByteArray& datagram) {
|
||||||
datagramsSent++;
|
datagramsSent++;
|
||||||
|
bytesSent += datagram.size();
|
||||||
|
|
||||||
// some datagrams are dropped
|
// some datagrams are dropped
|
||||||
const float DROP_PROBABILITY = 0.1f;
|
const float DROP_PROBABILITY = 0.1f;
|
||||||
|
@ -364,6 +418,7 @@ void Endpoint::sendDatagram(const QByteArray& datagram) {
|
||||||
|
|
||||||
_other->_sequencer->receivedDatagram(datagram);
|
_other->_sequencer->receivedDatagram(datagram);
|
||||||
datagramsReceived++;
|
datagramsReceived++;
|
||||||
|
bytesReceived += datagram.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Endpoint::handleHighPriorityMessage(const QVariant& message) {
|
void Endpoint::handleHighPriorityMessage(const QVariant& message) {
|
||||||
|
@ -384,12 +439,21 @@ void Endpoint::readMessage(Bitstream& in) {
|
||||||
SequencedTestMessage message;
|
SequencedTestMessage message;
|
||||||
in >> message;
|
in >> message;
|
||||||
|
|
||||||
|
_remoteState = message.state;
|
||||||
|
|
||||||
|
// record the receipt
|
||||||
|
ReceiveRecord record = { _sequencer->getIncomingPacketNumber(), message.state };
|
||||||
|
_receiveRecords.append(record);
|
||||||
|
|
||||||
for (QList<SequencedTestMessage>::iterator it = _other->_unreliableMessagesSent.begin();
|
for (QList<SequencedTestMessage>::iterator it = _other->_unreliableMessagesSent.begin();
|
||||||
it != _other->_unreliableMessagesSent.end(); it++) {
|
it != _other->_unreliableMessagesSent.end(); it++) {
|
||||||
if (it->sequenceNumber == message.sequenceNumber) {
|
if (it->sequenceNumber == message.sequenceNumber) {
|
||||||
if (!messagesEqual(it->submessage, message.submessage)) {
|
if (!messagesEqual(it->submessage, message.submessage)) {
|
||||||
throw QString("Sent/received unreliable message mismatch.");
|
throw QString("Sent/received unreliable message mismatch.");
|
||||||
}
|
}
|
||||||
|
if (!it->state->equals(message.state)) {
|
||||||
|
throw QString("Delta-encoded object mismatch.");
|
||||||
|
}
|
||||||
_other->_unreliableMessagesSent.erase(_other->_unreliableMessagesSent.begin(), it + 1);
|
_other->_unreliableMessagesSent.erase(_other->_unreliableMessagesSent.begin(), it + 1);
|
||||||
unreliableMessagesReceived++;
|
unreliableMessagesReceived++;
|
||||||
return;
|
return;
|
||||||
|
@ -427,6 +491,14 @@ void Endpoint::readReliableChannel() {
|
||||||
streamedBytesReceived += bytes.size();
|
streamedBytesReceived += bytes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Endpoint::clearSendRecordsBefore(int index) {
|
||||||
|
_sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Endpoint::clearReceiveRecordsBefore(int index) {
|
||||||
|
_receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) :
|
TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) :
|
||||||
_foo(foo),
|
_foo(foo),
|
||||||
_baz(baz),
|
_baz(baz),
|
||||||
|
|
|
@ -54,9 +54,30 @@ private slots:
|
||||||
void handleReliableMessage(const QVariant& message);
|
void handleReliableMessage(const QVariant& message);
|
||||||
void readReliableChannel();
|
void readReliableChannel();
|
||||||
|
|
||||||
|
void clearSendRecordsBefore(int index);
|
||||||
|
void clearReceiveRecordsBefore(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
class SendRecord {
|
||||||
|
public:
|
||||||
|
int packetNumber;
|
||||||
|
SharedObjectPointer localState;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ReceiveRecord {
|
||||||
|
public:
|
||||||
|
int packetNumber;
|
||||||
|
SharedObjectPointer remoteState;
|
||||||
|
};
|
||||||
|
|
||||||
DatagramSequencer* _sequencer;
|
DatagramSequencer* _sequencer;
|
||||||
|
QList<SendRecord> _sendRecords;
|
||||||
|
QList<ReceiveRecord> _receiveRecords;
|
||||||
|
|
||||||
|
SharedObjectPointer _localState;
|
||||||
|
SharedObjectPointer _remoteState;
|
||||||
|
|
||||||
Endpoint* _other;
|
Endpoint* _other;
|
||||||
QList<QPair<QByteArray, int> > _delayedDatagrams;
|
QList<QPair<QByteArray, int> > _delayedDatagrams;
|
||||||
float _highPriorityMessagesToSend;
|
float _highPriorityMessagesToSend;
|
||||||
|
@ -106,6 +127,8 @@ private:
|
||||||
TestFlags _bong;
|
TestFlags _bong;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DECLARE_ENUM_METATYPE(TestSharedObjectA, TestEnum)
|
||||||
|
|
||||||
/// Another simple shared object.
|
/// Another simple shared object.
|
||||||
class TestSharedObjectB : public SharedObject {
|
class TestSharedObjectB : public SharedObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -169,6 +192,7 @@ public:
|
||||||
|
|
||||||
STREAM QByteArray foo;
|
STREAM QByteArray foo;
|
||||||
STREAM SharedObjectPointer bar;
|
STREAM SharedObjectPointer bar;
|
||||||
|
STREAM TestSharedObjectA::TestEnum baz;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_STREAMABLE_METATYPE(TestMessageB)
|
DECLARE_STREAMABLE_METATYPE(TestMessageB)
|
||||||
|
@ -192,6 +216,7 @@ public:
|
||||||
|
|
||||||
STREAM int sequenceNumber;
|
STREAM int sequenceNumber;
|
||||||
STREAM QVariant submessage;
|
STREAM QVariant submessage;
|
||||||
|
STREAM SharedObjectPointer state;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_STREAMABLE_METATYPE(SequencedTestMessage)
|
DECLARE_STREAMABLE_METATYPE(SequencedTestMessage)
|
||||||
|
|
Loading…
Reference in a new issue