mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 06:17:38 +02:00
Ported over fixes that I made when working on delta-encoding for avatars.
This commit is contained in:
parent
6f5d2ba233
commit
6db385de7a
5 changed files with 184 additions and 32 deletions
|
@ -193,7 +193,7 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) {
|
|||
continue;
|
||||
}
|
||||
connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*)));
|
||||
QPointer<SharedObject>& reference = _sharedObjectReferences[it.key()->getID()];
|
||||
QPointer<SharedObject>& reference = _sharedObjectReferences[it.key()->getOriginID()];
|
||||
if (reference) {
|
||||
_sharedObjectStreamer.removePersistentID(reference);
|
||||
reference->disconnect(this);
|
||||
|
@ -227,7 +227,7 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) {
|
|||
if (!it.value()) {
|
||||
continue;
|
||||
}
|
||||
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteID()];
|
||||
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()];
|
||||
if (reference) {
|
||||
_sharedObjectStreamer.removePersistentValue(reference.data());
|
||||
}
|
||||
|
@ -411,6 +411,10 @@ Bitstream& Bitstream::operator>>(QUrl& url) {
|
|||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const QVariant& value) {
|
||||
if (!value.isValid()) {
|
||||
_typeStreamerStreamer << NULL;
|
||||
return *this;
|
||||
}
|
||||
const TypeStreamer* streamer = getTypeStreamers().value(value.userType());
|
||||
if (streamer) {
|
||||
_typeStreamerStreamer << streamer;
|
||||
|
@ -424,7 +428,11 @@ Bitstream& Bitstream::operator<<(const QVariant& value) {
|
|||
Bitstream& Bitstream::operator>>(QVariant& value) {
|
||||
TypeReader reader;
|
||||
_typeStreamerStreamer >> reader;
|
||||
value = reader.read(*this);
|
||||
if (reader.getTypeName().isEmpty()) {
|
||||
value = QVariant();
|
||||
} else {
|
||||
value = reader.read(*this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -656,6 +664,10 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
|||
}
|
||||
|
||||
Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
|
||||
if (!streamer) {
|
||||
*this << QByteArray();
|
||||
return *this;
|
||||
}
|
||||
const char* typeName = QMetaType::typeName(streamer->getType());
|
||||
*this << QByteArray::fromRawData(typeName, strlen(typeName));
|
||||
if (_metadataType == NO_METADATA) {
|
||||
|
@ -702,6 +714,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
|
|||
Bitstream& Bitstream::operator>(TypeReader& reader) {
|
||||
QByteArray typeName;
|
||||
*this >> typeName;
|
||||
if (typeName.isEmpty()) {
|
||||
reader = TypeReader();
|
||||
return *this;
|
||||
}
|
||||
const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName);
|
||||
if (!streamer) {
|
||||
streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
|
||||
|
@ -847,9 +863,10 @@ Bitstream& Bitstream::operator<(const SharedObjectPointer& object) {
|
|||
return *this << (int)0;
|
||||
}
|
||||
*this << object->getID();
|
||||
QPointer<SharedObject> reference = _sharedObjectReferences.value(object->getID());
|
||||
*this << object->getOriginID();
|
||||
QPointer<SharedObject> reference = _sharedObjectReferences.value(object->getOriginID());
|
||||
if (reference) {
|
||||
writeRawDelta((QObject*)object.data(), (QObject*)reference.data());
|
||||
writeRawDelta((const QObject*)object.data(), (const QObject*)reference.data());
|
||||
} else {
|
||||
*this << (QObject*)object.data();
|
||||
}
|
||||
|
@ -863,7 +880,9 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
|
|||
object = SharedObjectPointer();
|
||||
return *this;
|
||||
}
|
||||
QPointer<SharedObject> reference = _sharedObjectReferences.value(id);
|
||||
int originID;
|
||||
*this >> originID;
|
||||
QPointer<SharedObject> reference = _sharedObjectReferences.value(originID);
|
||||
QPointer<SharedObject>& pointer = _weakSharedObjectHash[id];
|
||||
if (pointer) {
|
||||
ObjectReader objectReader;
|
||||
|
@ -876,15 +895,19 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
|
|||
} else {
|
||||
QObject* rawObject;
|
||||
if (reference) {
|
||||
readRawDelta(rawObject, (QObject*)reference.data());
|
||||
readRawDelta(rawObject, (const QObject*)reference.data());
|
||||
} else {
|
||||
*this >> rawObject;
|
||||
}
|
||||
pointer = static_cast<SharedObject*>(rawObject);
|
||||
if (pointer) {
|
||||
if (reference) {
|
||||
pointer->setOriginID(reference->getOriginID());
|
||||
}
|
||||
pointer->setRemoteID(id);
|
||||
pointer->setRemoteOriginID(originID);
|
||||
} else {
|
||||
qDebug() << "Null object" << pointer << reference;
|
||||
qDebug() << "Null object" << pointer << reference << id;
|
||||
}
|
||||
}
|
||||
object = static_cast<SharedObject*>(pointer.data());
|
||||
|
@ -893,7 +916,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
|
|||
|
||||
void Bitstream::clearSharedObject(QObject* object) {
|
||||
SharedObject* sharedObject = static_cast<SharedObject*>(object);
|
||||
_sharedObjectReferences.remove(sharedObject->getID());
|
||||
_sharedObjectReferences.remove(sharedObject->getOriginID());
|
||||
int id = _sharedObjectStreamer.takePersistentID(sharedObject);
|
||||
if (id != 0) {
|
||||
emit sharedObjectCleared(id);
|
||||
|
@ -1099,6 +1122,10 @@ uint qHash(const TypeReader& typeReader, uint seed) {
|
|||
return qHash(typeReader.getTypeName(), seed);
|
||||
}
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const TypeReader& typeReader) {
|
||||
return debug << typeReader.getTypeName();
|
||||
}
|
||||
|
||||
FieldReader::FieldReader(const TypeReader& reader, int index) :
|
||||
_reader(reader),
|
||||
_index(index) {
|
||||
|
@ -1152,6 +1179,10 @@ uint qHash(const ObjectReader& objectReader, uint seed) {
|
|||
return qHash(objectReader.getClassName(), seed);
|
||||
}
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader) {
|
||||
return debug << objectReader.getClassName();
|
||||
}
|
||||
|
||||
PropertyReader::PropertyReader(const TypeReader& reader, const QMetaProperty& property) :
|
||||
_reader(reader),
|
||||
_property(property) {
|
||||
|
@ -1236,3 +1267,12 @@ QVariant TypeStreamer::getValue(const QVariant& object, int index) const {
|
|||
void TypeStreamer::setValue(QVariant& object, int index, const QVariant& value) const {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer) {
|
||||
return debug << (typeStreamer ? QMetaType::typeName(typeStreamer->getType()) : "null");
|
||||
}
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) {
|
||||
return debug << (metaObject ? metaObject->className() : "null");
|
||||
}
|
||||
|
||||
|
|
|
@ -294,6 +294,9 @@ public:
|
|||
template<class T> void writeRawDelta(const QList<T>& value, const QList<T>& reference);
|
||||
template<class T> void readRawDelta(QList<T>& value, const QList<T>& reference);
|
||||
|
||||
template<class T> void writeRawDelta(const QVector<T>& value, const QVector<T>& reference);
|
||||
template<class T> void readRawDelta(QVector<T>& value, const QVector<T>& reference);
|
||||
|
||||
template<class T> void writeRawDelta(const QSet<T>& value, const QSet<T>& reference);
|
||||
template<class T> void readRawDelta(QSet<T>& value, const QSet<T>& reference);
|
||||
|
||||
|
@ -339,6 +342,9 @@ public:
|
|||
template<class T> Bitstream& operator<<(const QList<T>& list);
|
||||
template<class T> Bitstream& operator>>(QList<T>& list);
|
||||
|
||||
template<class T> Bitstream& operator<<(const QVector<T>& list);
|
||||
template<class T> Bitstream& operator>>(QVector<T>& list);
|
||||
|
||||
template<class T> Bitstream& operator<<(const QSet<T>& set);
|
||||
template<class T> Bitstream& operator>>(QSet<T>& set);
|
||||
|
||||
|
@ -472,6 +478,36 @@ template<class T> inline void Bitstream::readRawDelta(QList<T>& value, const QLi
|
|||
}
|
||||
}
|
||||
|
||||
template<class T> inline void Bitstream::writeRawDelta(const QVector<T>& value, const QVector<T>& reference) {
|
||||
*this << value.size();
|
||||
*this << reference.size();
|
||||
for (int i = 0; i < value.size(); i++) {
|
||||
if (i < reference.size()) {
|
||||
writeDelta(value.at(i), reference.at(i));
|
||||
} else {
|
||||
*this << value.at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> inline void Bitstream::readRawDelta(QVector<T>& value, const QVector<T>& reference) {
|
||||
value = reference;
|
||||
int size, referenceSize;
|
||||
*this >> size >> referenceSize;
|
||||
if (size < value.size()) {
|
||||
value.erase(value.begin() + size, value.end());
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i < referenceSize) {
|
||||
readDelta(value[i], reference.at(i));
|
||||
} else {
|
||||
T element;
|
||||
*this >> element;
|
||||
value.append(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> inline void Bitstream::writeRawDelta(const QSet<T>& value, const QSet<T>& reference) {
|
||||
int addedOrRemoved = 0;
|
||||
foreach (const T& element, value) {
|
||||
|
@ -600,6 +636,27 @@ template<class T> inline Bitstream& Bitstream::operator>>(QList<T>& list) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
template<class T> inline Bitstream& Bitstream::operator<<(const QVector<T>& vector) {
|
||||
*this << vector.size();
|
||||
foreach (const T& entry, vector) {
|
||||
*this << entry;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T> inline Bitstream& Bitstream::operator>>(QVector<T>& vector) {
|
||||
int size;
|
||||
*this >> size;
|
||||
vector.clear();
|
||||
vector.reserve(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
T entry;
|
||||
*this >> entry;
|
||||
vector.append(entry);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T> inline Bitstream& Bitstream::operator<<(const QSet<T>& set) {
|
||||
*this << set.size();
|
||||
foreach (const T& entry, set) {
|
||||
|
@ -683,6 +740,8 @@ private:
|
|||
|
||||
uint qHash(const TypeReader& typeReader, uint seed = 0);
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const TypeReader& typeReader);
|
||||
|
||||
/// Contains the information required to read a metatype field from the stream and apply it.
|
||||
class FieldReader {
|
||||
public:
|
||||
|
@ -726,6 +785,8 @@ private:
|
|||
|
||||
uint qHash(const ObjectReader& objectReader, uint seed = 0);
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader);
|
||||
|
||||
/// Contains the information required to read an object property from the stream and apply it.
|
||||
class PropertyReader {
|
||||
public:
|
||||
|
@ -808,6 +869,10 @@ private:
|
|||
int _type;
|
||||
};
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer);
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject);
|
||||
|
||||
/// A streamer that works with Bitstream's operators.
|
||||
template<class T> class SimpleTypeStreamer : public TypeStreamer {
|
||||
public:
|
||||
|
@ -818,11 +883,11 @@ public:
|
|||
virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const {
|
||||
out.writeDelta(value.value<T>(), reference.value<T>()); }
|
||||
virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const {
|
||||
in.readDelta(*static_cast<T*>(value.data()), reference.value<T>()); }
|
||||
T rawValue; in.readDelta(rawValue, reference.value<T>()); value = QVariant::fromValue(rawValue); }
|
||||
virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const {
|
||||
out.writeRawDelta(value.value<T>(), reference.value<T>()); }
|
||||
virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const {
|
||||
in.readRawDelta(*static_cast<T*>(value.data()), reference.value<T>()); }
|
||||
T rawValue; in.readRawDelta(rawValue, reference.value<T>()); value = QVariant::fromValue(rawValue); }
|
||||
};
|
||||
|
||||
/// A streamer for types compiled by mtc.
|
||||
|
@ -858,6 +923,22 @@ public:
|
|||
static_cast<QList<T>*>(object.data())->replace(index, value.value<T>()); }
|
||||
};
|
||||
|
||||
/// A streamer for vector types.
|
||||
template<class T> class CollectionTypeStreamer<QVector<T> > : public SimpleTypeStreamer<QVector<T> > {
|
||||
public:
|
||||
|
||||
virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; }
|
||||
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
|
||||
virtual void insert(QVariant& object, const QVariant& value) const {
|
||||
static_cast<QVector<T>*>(object.data())->append(value.value<T>()); }
|
||||
virtual void prune(QVariant& object, int size) const {
|
||||
QVector<T>* list = static_cast<QVector<T>*>(object.data()); list->erase(list->begin() + size, list->end()); }
|
||||
virtual QVariant getValue(const QVariant& object, int index) const {
|
||||
return QVariant::fromValue(static_cast<const QVector<T>*>(object.constData())->at(index)); }
|
||||
virtual void setValue(QVariant& object, int index, const QVariant& value) const {
|
||||
static_cast<QVector<T>*>(object.data())->replace(index, value.value<T>()); }
|
||||
};
|
||||
|
||||
/// A streamer for set types.
|
||||
template<class T> class CollectionTypeStreamer<QSet<T> > : public SimpleTypeStreamer<QSet<T> > {
|
||||
public:
|
||||
|
@ -940,6 +1021,13 @@ template<class T> int registerStreamableMetaType() {
|
|||
return type;
|
||||
}
|
||||
|
||||
/// Registers a collection type and its streamer.
|
||||
template<class T> int registerCollectionMetaType() {
|
||||
int type = qRegisterMetaType<T>();
|
||||
Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer<T>());
|
||||
return type;
|
||||
}
|
||||
|
||||
/// Flags a class as streamable (use as you would Q_OBJECT).
|
||||
#define STREAMABLE public: \
|
||||
static const int Type; \
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <QSet>
|
||||
#include <QVector>
|
||||
|
||||
#include "Bitstream.h"
|
||||
#include "AttributeRegistry.h"
|
||||
|
||||
class ReliableChannel;
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ REGISTER_META_OBJECT(SharedObject)
|
|||
|
||||
SharedObject::SharedObject() :
|
||||
_id(++_lastID),
|
||||
_remoteID(0) {
|
||||
_originID(_id),
|
||||
_remoteID(0),
|
||||
_remoteOriginID(0) {
|
||||
|
||||
_weakHash.insert(_id, this);
|
||||
}
|
||||
|
@ -39,26 +41,33 @@ void SharedObject::decrementReferenceCount() {
|
|||
}
|
||||
}
|
||||
|
||||
SharedObject* SharedObject::clone(bool withID) const {
|
||||
SharedObject* SharedObject::clone(bool withID, SharedObject* target) const {
|
||||
// default behavior is to make a copy using the no-arg constructor and copy the stored properties
|
||||
const QMetaObject* metaObject = this->metaObject();
|
||||
SharedObject* newObject = static_cast<SharedObject*>(metaObject->newInstance());
|
||||
if (!target) {
|
||||
target = static_cast<SharedObject*>(metaObject->newInstance());
|
||||
}
|
||||
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
||||
QMetaProperty property = metaObject->property(i);
|
||||
if (property.isStored()) {
|
||||
property.write(newObject, property.read(this));
|
||||
if (property.userType() == qMetaTypeId<SharedObjectPointer>()) {
|
||||
SharedObject* value = property.read(this).value<SharedObjectPointer>().data();
|
||||
property.write(target, QVariant::fromValue(value ? value->clone(withID) : value));
|
||||
} else {
|
||||
property.write(target, property.read(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (const QByteArray& propertyName, dynamicPropertyNames()) {
|
||||
newObject->setProperty(propertyName, property(propertyName));
|
||||
target->setProperty(propertyName, property(propertyName));
|
||||
}
|
||||
if (withID) {
|
||||
newObject->setID(_id);
|
||||
target->setOriginID(_originID);
|
||||
}
|
||||
return newObject;
|
||||
return target;
|
||||
}
|
||||
|
||||
bool SharedObject::equals(const SharedObject* other) const {
|
||||
bool SharedObject::equals(const SharedObject* other, bool sharedAncestry) const {
|
||||
if (!other) {
|
||||
return false;
|
||||
}
|
||||
|
@ -67,7 +76,7 @@ bool SharedObject::equals(const SharedObject* other) const {
|
|||
}
|
||||
// default behavior is to compare the properties
|
||||
const QMetaObject* metaObject = this->metaObject();
|
||||
if (metaObject != other->metaObject()) {
|
||||
if (metaObject != other->metaObject() && !sharedAncestry) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
||||
|
@ -92,13 +101,15 @@ void SharedObject::dump(QDebug debug) const {
|
|||
debug << this;
|
||||
const QMetaObject* metaObject = this->metaObject();
|
||||
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
||||
debug << metaObject->property(i).name() << metaObject->property(i).read(this);
|
||||
QMetaProperty property = metaObject->property(i);
|
||||
if (property.isStored()) {
|
||||
debug << property.name() << property.read(this);
|
||||
}
|
||||
}
|
||||
QList<QByteArray> dynamicPropertyNames = this->dynamicPropertyNames();
|
||||
foreach (const QByteArray& propertyName, dynamicPropertyNames) {
|
||||
debug << propertyName << property(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
void SharedObject::setID(int id) {
|
||||
_weakHash.remove(_id);
|
||||
_weakHash.insert(_id = id, this);
|
||||
}
|
||||
|
||||
int SharedObject::_lastID = 0;
|
||||
|
|
|
@ -41,31 +41,44 @@ public:
|
|||
/// Returns the unique local ID for this object.
|
||||
int getID() const { return _id; }
|
||||
|
||||
/// Returns the local origin ID for this object.
|
||||
int getOriginID() const { return _originID; }
|
||||
|
||||
void setOriginID(int originID) { _originID = originID; }
|
||||
|
||||
/// Returns the unique remote ID for this object, or zero if this is a local object.
|
||||
int getRemoteID() const { return _remoteID; }
|
||||
|
||||
void setRemoteID(int remoteID) { _remoteID = remoteID; }
|
||||
|
||||
/// Returns the remote origin ID for this object, or zero if this is a local object.
|
||||
int getRemoteOriginID() const { return _remoteOriginID; }
|
||||
|
||||
void setRemoteOriginID(int remoteOriginID) { _remoteOriginID = remoteOriginID; }
|
||||
|
||||
int getReferenceCount() const { return _referenceCount.load(); }
|
||||
void incrementReferenceCount();
|
||||
void decrementReferenceCount();
|
||||
|
||||
/// Creates a new clone of this object.
|
||||
/// \param withID if true, give the clone the same ID as this object
|
||||
virtual SharedObject* clone(bool withID = false) const;
|
||||
/// \param withID if true, give the clone the same origin ID as this object
|
||||
/// \target if non-NULL, a target object to populate (as opposed to creating a new instance of this object's class)
|
||||
virtual SharedObject* clone(bool withID = false, SharedObject* target = NULL) const;
|
||||
|
||||
/// Tests this object for equality with another.
|
||||
virtual bool equals(const SharedObject* other) const;
|
||||
/// \param sharedAncestry if true and the classes of the objects differ, compare their shared ancestry (assuming that
|
||||
/// this is an instance of a superclass of the other object's class) rather than simply returning false.
|
||||
virtual bool equals(const SharedObject* other, bool sharedAncestry = false) const;
|
||||
|
||||
// Dumps the contents of this object to the debug output.
|
||||
virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const;
|
||||
|
||||
private:
|
||||
|
||||
void setID(int id);
|
||||
|
||||
int _id;
|
||||
int _originID;
|
||||
int _remoteID;
|
||||
int _remoteOriginID;
|
||||
QAtomicInt _referenceCount;
|
||||
|
||||
static int _lastID;
|
||||
|
|
Loading…
Reference in a new issue