mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Merge pull request #3006 from ey6es/metavoxels
Streaming/delta-streaming for script values.
This commit is contained in:
commit
49a33ff46a
6 changed files with 746 additions and 32 deletions
|
@ -14,6 +14,7 @@
|
|||
#include <QCryptographicHash>
|
||||
#include <QDataStream>
|
||||
#include <QMetaType>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QUrl>
|
||||
#include <QtDebug>
|
||||
|
||||
|
@ -30,6 +31,7 @@ REGISTER_SIMPLE_TYPE_STREAMER(uint)
|
|||
REGISTER_SIMPLE_TYPE_STREAMER(float)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QByteArray)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QColor)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QScriptValue)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QString)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QUrl)
|
||||
REGISTER_SIMPLE_TYPE_STREAMER(QVariantList)
|
||||
|
@ -285,6 +287,12 @@ void Bitstream::writeDelta(const QVariant& value, const QVariant& reference) {
|
|||
streamer->writeRawDelta(*this, value, reference);
|
||||
}
|
||||
|
||||
void Bitstream::writeRawDelta(const QVariant& value, const QVariant& reference) {
|
||||
const TypeStreamer* streamer = getTypeStreamers().value(value.userType());
|
||||
_typeStreamerStreamer << streamer;
|
||||
streamer->writeRawDelta(*this, value, reference);
|
||||
}
|
||||
|
||||
void Bitstream::readRawDelta(QVariant& value, const QVariant& reference) {
|
||||
TypeReader typeReader;
|
||||
_typeStreamerStreamer >> typeReader;
|
||||
|
@ -309,6 +317,272 @@ void Bitstream::readRawDelta(QObject*& value, const QObject* reference) {
|
|||
value = objectReader.readDelta(*this, reference);
|
||||
}
|
||||
|
||||
void Bitstream::writeRawDelta(const QScriptValue& value, const QScriptValue& reference) {
|
||||
if (reference.isUndefined() || reference.isNull()) {
|
||||
*this << value;
|
||||
|
||||
} else if (reference.isBool()) {
|
||||
if (value.isBool()) {
|
||||
*this << false;
|
||||
*this << value.toBool();
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isNumber()) {
|
||||
if (value.isNumber()) {
|
||||
*this << false;
|
||||
*this << value.toNumber();
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isString()) {
|
||||
if (value.isString()) {
|
||||
*this << false;
|
||||
*this << value.toString();
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isVariant()) {
|
||||
if (value.isVariant()) {
|
||||
*this << false;
|
||||
writeRawDelta(value.toVariant(), reference.toVariant());
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isQObject()) {
|
||||
if (value.isQObject()) {
|
||||
*this << false;
|
||||
writeRawDelta(value.toQObject(), reference.toQObject());
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isQMetaObject()) {
|
||||
if (value.isQMetaObject()) {
|
||||
*this << false;
|
||||
*this << value.toQMetaObject();
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isDate()) {
|
||||
if (value.isDate()) {
|
||||
*this << false;
|
||||
*this << value.toDateTime();
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isRegExp()) {
|
||||
if (value.isRegExp()) {
|
||||
*this << false;
|
||||
*this << value.toRegExp();
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isArray()) {
|
||||
if (value.isArray()) {
|
||||
*this << false;
|
||||
int length = value.property(ScriptCache::getInstance()->getLengthString()).toInt32();
|
||||
*this << length;
|
||||
int referenceLength = reference.property(ScriptCache::getInstance()->getLengthString()).toInt32();
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (i < referenceLength) {
|
||||
writeDelta(value.property(i), reference.property(i));
|
||||
} else {
|
||||
*this << value.property(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else if (reference.isObject()) {
|
||||
if (value.isObject() && !(value.isArray() || value.isRegExp() || value.isDate() ||
|
||||
value.isQMetaObject() || value.isQObject() || value.isVariant())) {
|
||||
*this << false;
|
||||
for (QScriptValueIterator it(value); it.hasNext(); ) {
|
||||
it.next();
|
||||
QScriptValue referenceValue = reference.property(it.scriptName());
|
||||
if (it.value() != referenceValue) {
|
||||
*this << it.scriptName();
|
||||
writeRawDelta(it.value(), referenceValue);
|
||||
}
|
||||
}
|
||||
for (QScriptValueIterator it(reference); it.hasNext(); ) {
|
||||
it.next();
|
||||
if (!value.property(it.scriptName()).isValid()) {
|
||||
*this << it.scriptName();
|
||||
writeRawDelta(QScriptValue(), it.value());
|
||||
}
|
||||
}
|
||||
*this << QScriptString();
|
||||
|
||||
} else {
|
||||
*this << true;
|
||||
*this << value;
|
||||
}
|
||||
} else {
|
||||
*this << value;
|
||||
}
|
||||
}
|
||||
|
||||
void Bitstream::readRawDelta(QScriptValue& value, const QScriptValue& reference) {
|
||||
if (reference.isUndefined() || reference.isNull()) {
|
||||
*this >> value;
|
||||
|
||||
} else if (reference.isBool()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
bool boolValue;
|
||||
*this >> boolValue;
|
||||
value = QScriptValue(boolValue);
|
||||
}
|
||||
} else if (reference.isNumber()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
qsreal numberValue;
|
||||
*this >> numberValue;
|
||||
value = QScriptValue(numberValue);
|
||||
}
|
||||
} else if (reference.isString()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
QString stringValue;
|
||||
*this >> stringValue;
|
||||
value = QScriptValue(stringValue);
|
||||
}
|
||||
} else if (reference.isVariant()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
QVariant variant;
|
||||
readRawDelta(variant, reference.toVariant());
|
||||
value = ScriptCache::getInstance()->getEngine()->newVariant(variant);
|
||||
}
|
||||
} else if (reference.isQObject()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
QObject* object;
|
||||
readRawDelta(object, reference.toQObject());
|
||||
value = ScriptCache::getInstance()->getEngine()->newQObject(object, QScriptEngine::ScriptOwnership);
|
||||
}
|
||||
} else if (reference.isQMetaObject()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
const QMetaObject* metaObject;
|
||||
*this >> metaObject;
|
||||
value = ScriptCache::getInstance()->getEngine()->newQMetaObject(metaObject);
|
||||
}
|
||||
} else if (reference.isDate()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
QDateTime dateTime;
|
||||
*this >> dateTime;
|
||||
value = ScriptCache::getInstance()->getEngine()->newDate(dateTime);
|
||||
}
|
||||
} else if (reference.isRegExp()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
QRegExp regExp;
|
||||
*this >> regExp;
|
||||
value = ScriptCache::getInstance()->getEngine()->newRegExp(regExp);
|
||||
}
|
||||
} else if (reference.isArray()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
int length;
|
||||
*this >> length;
|
||||
value = ScriptCache::getInstance()->getEngine()->newArray(length);
|
||||
int referenceLength = reference.property(ScriptCache::getInstance()->getLengthString()).toInt32();
|
||||
for (int i = 0; i < length; i++) {
|
||||
QScriptValue element;
|
||||
if (i < referenceLength) {
|
||||
readDelta(element, reference.property(i));
|
||||
} else {
|
||||
*this >> element;
|
||||
}
|
||||
value.setProperty(i, element);
|
||||
}
|
||||
}
|
||||
} else if (reference.isObject()) {
|
||||
bool typeChanged;
|
||||
*this >> typeChanged;
|
||||
if (typeChanged) {
|
||||
*this >> value;
|
||||
|
||||
} else {
|
||||
// start by shallow-copying the reference
|
||||
value = ScriptCache::getInstance()->getEngine()->newObject();
|
||||
for (QScriptValueIterator it(reference); it.hasNext(); ) {
|
||||
it.next();
|
||||
value.setProperty(it.scriptName(), it.value());
|
||||
}
|
||||
// then apply the requested changes
|
||||
forever {
|
||||
QScriptString name;
|
||||
*this >> name;
|
||||
if (!name.isValid()) {
|
||||
break;
|
||||
}
|
||||
QScriptValue scriptValue;
|
||||
readRawDelta(scriptValue, reference.property(name));
|
||||
value.setProperty(name, scriptValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*this >> value;
|
||||
}
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(bool value) {
|
||||
if (value) {
|
||||
_byte |= (1 << _position);
|
||||
|
@ -350,6 +624,14 @@ Bitstream& Bitstream::operator>>(uint& value) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(qint64 value) {
|
||||
return write(&value, 64);
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(qint64& value) {
|
||||
return read(&value, 64);
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(float value) {
|
||||
return write(&value, 32);
|
||||
}
|
||||
|
@ -358,6 +640,14 @@ Bitstream& Bitstream::operator>>(float& value) {
|
|||
return read(&value, 32);
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(double value) {
|
||||
return write(&value, 64);
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(double& value) {
|
||||
return read(&value, 64);
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const glm::vec3& value) {
|
||||
return *this << value.x << value.y << value.z;
|
||||
}
|
||||
|
@ -420,6 +710,40 @@ Bitstream& Bitstream::operator>>(QUrl& url) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const QDateTime& dateTime) {
|
||||
return *this << dateTime.toMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(QDateTime& dateTime) {
|
||||
qint64 msecsSinceEpoch;
|
||||
*this >> msecsSinceEpoch;
|
||||
dateTime = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const QRegExp& regExp) {
|
||||
*this << regExp.pattern();
|
||||
Qt::CaseSensitivity caseSensitivity = regExp.caseSensitivity();
|
||||
write(&caseSensitivity, 1);
|
||||
QRegExp::PatternSyntax syntax = regExp.patternSyntax();
|
||||
write(&syntax, 3);
|
||||
return *this << regExp.isMinimal();
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(QRegExp& regExp) {
|
||||
QString pattern;
|
||||
*this >> pattern;
|
||||
Qt::CaseSensitivity caseSensitivity = (Qt::CaseSensitivity)0;
|
||||
read(&caseSensitivity, 1);
|
||||
QRegExp::PatternSyntax syntax = (QRegExp::PatternSyntax)0;
|
||||
read(&syntax, 3);
|
||||
regExp = QRegExp(pattern, caseSensitivity, syntax);
|
||||
bool minimal;
|
||||
*this >> minimal;
|
||||
regExp.setMinimal(minimal);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const QVariant& value) {
|
||||
if (!value.isValid()) {
|
||||
_typeStreamerStreamer << NULL;
|
||||
|
@ -543,6 +867,185 @@ Bitstream& Bitstream::operator>>(QScriptString& string) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
enum ScriptValueType {
|
||||
INVALID_SCRIPT_VALUE,
|
||||
UNDEFINED_SCRIPT_VALUE,
|
||||
NULL_SCRIPT_VALUE,
|
||||
BOOL_SCRIPT_VALUE,
|
||||
NUMBER_SCRIPT_VALUE,
|
||||
STRING_SCRIPT_VALUE,
|
||||
VARIANT_SCRIPT_VALUE,
|
||||
QOBJECT_SCRIPT_VALUE,
|
||||
QMETAOBJECT_SCRIPT_VALUE,
|
||||
DATE_SCRIPT_VALUE,
|
||||
REGEXP_SCRIPT_VALUE,
|
||||
ARRAY_SCRIPT_VALUE,
|
||||
OBJECT_SCRIPT_VALUE
|
||||
};
|
||||
|
||||
const int SCRIPT_VALUE_BITS = 4;
|
||||
|
||||
static void writeScriptValueType(Bitstream& out, ScriptValueType type) {
|
||||
out.write(&type, SCRIPT_VALUE_BITS);
|
||||
}
|
||||
|
||||
static ScriptValueType readScriptValueType(Bitstream& in) {
|
||||
ScriptValueType type = (ScriptValueType)0;
|
||||
in.read(&type, SCRIPT_VALUE_BITS);
|
||||
return type;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const QScriptValue& value) {
|
||||
if (value.isUndefined()) {
|
||||
writeScriptValueType(*this, UNDEFINED_SCRIPT_VALUE);
|
||||
|
||||
} else if (value.isNull()) {
|
||||
writeScriptValueType(*this, NULL_SCRIPT_VALUE);
|
||||
|
||||
} else if (value.isBool()) {
|
||||
writeScriptValueType(*this, BOOL_SCRIPT_VALUE);
|
||||
*this << value.toBool();
|
||||
|
||||
} else if (value.isNumber()) {
|
||||
writeScriptValueType(*this, NUMBER_SCRIPT_VALUE);
|
||||
*this << value.toNumber();
|
||||
|
||||
} else if (value.isString()) {
|
||||
writeScriptValueType(*this, STRING_SCRIPT_VALUE);
|
||||
*this << value.toString();
|
||||
|
||||
} else if (value.isVariant()) {
|
||||
writeScriptValueType(*this, VARIANT_SCRIPT_VALUE);
|
||||
*this << value.toVariant();
|
||||
|
||||
} else if (value.isQObject()) {
|
||||
writeScriptValueType(*this, QOBJECT_SCRIPT_VALUE);
|
||||
*this << value.toQObject();
|
||||
|
||||
} else if (value.isQMetaObject()) {
|
||||
writeScriptValueType(*this, QMETAOBJECT_SCRIPT_VALUE);
|
||||
*this << value.toQMetaObject();
|
||||
|
||||
} else if (value.isDate()) {
|
||||
writeScriptValueType(*this, DATE_SCRIPT_VALUE);
|
||||
*this << value.toDateTime();
|
||||
|
||||
} else if (value.isRegExp()) {
|
||||
writeScriptValueType(*this, REGEXP_SCRIPT_VALUE);
|
||||
*this << value.toRegExp();
|
||||
|
||||
} else if (value.isArray()) {
|
||||
writeScriptValueType(*this, ARRAY_SCRIPT_VALUE);
|
||||
int length = value.property(ScriptCache::getInstance()->getLengthString()).toInt32();
|
||||
*this << length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
*this << value.property(i);
|
||||
}
|
||||
} else if (value.isObject()) {
|
||||
writeScriptValueType(*this, OBJECT_SCRIPT_VALUE);
|
||||
for (QScriptValueIterator it(value); it.hasNext(); ) {
|
||||
it.next();
|
||||
*this << it.scriptName();
|
||||
*this << it.value();
|
||||
}
|
||||
*this << QScriptString();
|
||||
|
||||
} else {
|
||||
writeScriptValueType(*this, INVALID_SCRIPT_VALUE);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(QScriptValue& value) {
|
||||
switch (readScriptValueType(*this)) {
|
||||
case UNDEFINED_SCRIPT_VALUE:
|
||||
value = QScriptValue(QScriptValue::UndefinedValue);
|
||||
break;
|
||||
|
||||
case NULL_SCRIPT_VALUE:
|
||||
value = QScriptValue(QScriptValue::NullValue);
|
||||
break;
|
||||
|
||||
case BOOL_SCRIPT_VALUE: {
|
||||
bool boolValue;
|
||||
*this >> boolValue;
|
||||
value = QScriptValue(boolValue);
|
||||
break;
|
||||
}
|
||||
case NUMBER_SCRIPT_VALUE: {
|
||||
qsreal numberValue;
|
||||
*this >> numberValue;
|
||||
value = QScriptValue(numberValue);
|
||||
break;
|
||||
}
|
||||
case STRING_SCRIPT_VALUE: {
|
||||
QString stringValue;
|
||||
*this >> stringValue;
|
||||
value = QScriptValue(stringValue);
|
||||
break;
|
||||
}
|
||||
case VARIANT_SCRIPT_VALUE: {
|
||||
QVariant variantValue;
|
||||
*this >> variantValue;
|
||||
value = ScriptCache::getInstance()->getEngine()->newVariant(variantValue);
|
||||
break;
|
||||
}
|
||||
case QOBJECT_SCRIPT_VALUE: {
|
||||
QObject* object;
|
||||
*this >> object;
|
||||
ScriptCache::getInstance()->getEngine()->newQObject(object, QScriptEngine::ScriptOwnership);
|
||||
break;
|
||||
}
|
||||
case QMETAOBJECT_SCRIPT_VALUE: {
|
||||
const QMetaObject* metaObject;
|
||||
*this >> metaObject;
|
||||
ScriptCache::getInstance()->getEngine()->newQMetaObject(metaObject);
|
||||
break;
|
||||
}
|
||||
case DATE_SCRIPT_VALUE: {
|
||||
QDateTime dateTime;
|
||||
*this >> dateTime;
|
||||
value = ScriptCache::getInstance()->getEngine()->newDate(dateTime);
|
||||
break;
|
||||
}
|
||||
case REGEXP_SCRIPT_VALUE: {
|
||||
QRegExp regExp;
|
||||
*this >> regExp;
|
||||
value = ScriptCache::getInstance()->getEngine()->newRegExp(regExp);
|
||||
break;
|
||||
}
|
||||
case ARRAY_SCRIPT_VALUE: {
|
||||
int length;
|
||||
*this >> length;
|
||||
value = ScriptCache::getInstance()->getEngine()->newArray(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
QScriptValue element;
|
||||
*this >> element;
|
||||
value.setProperty(i, element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OBJECT_SCRIPT_VALUE: {
|
||||
value = ScriptCache::getInstance()->getEngine()->newObject();
|
||||
forever {
|
||||
QScriptString name;
|
||||
*this >> name;
|
||||
if (!name.isValid()) {
|
||||
break;
|
||||
}
|
||||
QScriptValue scriptValue;
|
||||
*this >> scriptValue;
|
||||
value.setProperty(name, scriptValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
value = QScriptValue();
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator<<(const SharedObjectPointer& object) {
|
||||
_sharedObjectStreamer << object;
|
||||
return *this;
|
||||
|
@ -561,7 +1064,7 @@ Bitstream& Bitstream::operator<(const QMetaObject* metaObject) {
|
|||
if (_metadataType == NO_METADATA) {
|
||||
return *this;
|
||||
}
|
||||
const QVector<PropertyWriter>& propertyWriters = getPropertyWriters().value(metaObject);
|
||||
const PropertyWriterVector& propertyWriters = getPropertyWriters().value(metaObject);
|
||||
*this << propertyWriters.size();
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
foreach (const PropertyWriter& propertyWriter, propertyWriters) {
|
||||
|
@ -600,7 +1103,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
|||
}
|
||||
int storedPropertyCount;
|
||||
*this >> storedPropertyCount;
|
||||
QVector<PropertyReader> properties(storedPropertyCount);
|
||||
PropertyReaderVector properties(storedPropertyCount);
|
||||
for (int i = 0; i < storedPropertyCount; i++) {
|
||||
TypeReader typeReader;
|
||||
*this >> typeReader;
|
||||
|
@ -619,7 +1122,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
|||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
bool matches = true;
|
||||
if (metaObject) {
|
||||
const QVector<PropertyWriter>& propertyWriters = getPropertyWriters().value(metaObject);
|
||||
const PropertyWriterVector& propertyWriters = getPropertyWriters().value(metaObject);
|
||||
if (propertyWriters.size() == properties.size()) {
|
||||
for (int i = 0; i < propertyWriters.size(); i++) {
|
||||
const PropertyWriter& propertyWriter = propertyWriters.at(i);
|
||||
|
@ -899,14 +1402,17 @@ Bitstream& Bitstream::operator>(AttributePointer& attribute) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
const QString INVALID_STRING("%INVALID%");
|
||||
|
||||
Bitstream& Bitstream::operator<(const QScriptString& string) {
|
||||
return *this << string.toString();
|
||||
return *this << (string.isValid() ? string.toString() : INVALID_STRING);
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>(QScriptString& string) {
|
||||
QString rawString;
|
||||
*this >> rawString;
|
||||
string = ScriptCache::getInstance()->getEngine()->toStringHandle(rawString);
|
||||
string = (rawString == INVALID_STRING) ? QScriptString() :
|
||||
ScriptCache::getInstance()->getEngine()->toStringHandle(rawString);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -990,17 +1496,17 @@ QHash<int, const TypeStreamer*>& Bitstream::getTypeStreamers() {
|
|||
return typeStreamers;
|
||||
}
|
||||
|
||||
const QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& Bitstream::getEnumStreamers() {
|
||||
static QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> enumStreamers = createEnumStreamers();
|
||||
const QHash<ScopeNamePair, const TypeStreamer*>& Bitstream::getEnumStreamers() {
|
||||
static QHash<ScopeNamePair, const TypeStreamer*> enumStreamers = createEnumStreamers();
|
||||
return enumStreamers;
|
||||
}
|
||||
|
||||
QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> Bitstream::createEnumStreamers() {
|
||||
QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> enumStreamers;
|
||||
QHash<ScopeNamePair, const TypeStreamer*> Bitstream::createEnumStreamers() {
|
||||
QHash<ScopeNamePair, 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())];
|
||||
const TypeStreamer*& streamer = enumStreamers[ScopeNamePair(metaEnum.scope(), metaEnum.name())];
|
||||
if (!streamer) {
|
||||
streamer = new EnumTypeStreamer(metaEnum);
|
||||
}
|
||||
|
@ -1022,15 +1528,15 @@ QHash<QByteArray, const TypeStreamer*> Bitstream::createEnumStreamersByName() {
|
|||
return enumStreamersByName;
|
||||
}
|
||||
|
||||
const QHash<const QMetaObject*, QVector<PropertyReader> >& Bitstream::getPropertyReaders() {
|
||||
static QHash<const QMetaObject*, QVector<PropertyReader> > propertyReaders = createPropertyReaders();
|
||||
const QHash<const QMetaObject*, PropertyReaderVector>& Bitstream::getPropertyReaders() {
|
||||
static QHash<const QMetaObject*, PropertyReaderVector> propertyReaders = createPropertyReaders();
|
||||
return propertyReaders;
|
||||
}
|
||||
|
||||
QHash<const QMetaObject*, QVector<PropertyReader> > Bitstream::createPropertyReaders() {
|
||||
QHash<const QMetaObject*, QVector<PropertyReader> > propertyReaders;
|
||||
QHash<const QMetaObject*, PropertyReaderVector> Bitstream::createPropertyReaders() {
|
||||
QHash<const QMetaObject*, PropertyReaderVector> propertyReaders;
|
||||
foreach (const QMetaObject* metaObject, getMetaObjects()) {
|
||||
QVector<PropertyReader>& readers = propertyReaders[metaObject];
|
||||
PropertyReaderVector& readers = propertyReaders[metaObject];
|
||||
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
||||
QMetaProperty property = metaObject->property(i);
|
||||
if (!property.isStored()) {
|
||||
|
@ -1039,7 +1545,7 @@ QHash<const QMetaObject*, QVector<PropertyReader> > Bitstream::createPropertyRea
|
|||
const TypeStreamer* streamer;
|
||||
if (property.isEnumType()) {
|
||||
QMetaEnum metaEnum = property.enumerator();
|
||||
streamer = getEnumStreamers().value(QPair<QByteArray, QByteArray>(
|
||||
streamer = getEnumStreamers().value(ScopeNamePair(
|
||||
QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())),
|
||||
QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name()))));
|
||||
} else {
|
||||
|
@ -1053,15 +1559,15 @@ QHash<const QMetaObject*, QVector<PropertyReader> > Bitstream::createPropertyRea
|
|||
return propertyReaders;
|
||||
}
|
||||
|
||||
const QHash<const QMetaObject*, QVector<PropertyWriter> >& Bitstream::getPropertyWriters() {
|
||||
static QHash<const QMetaObject*, QVector<PropertyWriter> > propertyWriters = createPropertyWriters();
|
||||
const QHash<const QMetaObject*, PropertyWriterVector>& Bitstream::getPropertyWriters() {
|
||||
static QHash<const QMetaObject*, PropertyWriterVector> propertyWriters = createPropertyWriters();
|
||||
return propertyWriters;
|
||||
}
|
||||
|
||||
QHash<const QMetaObject*, QVector<PropertyWriter> > Bitstream::createPropertyWriters() {
|
||||
QHash<const QMetaObject*, QVector<PropertyWriter> > propertyWriters;
|
||||
QHash<const QMetaObject*, PropertyWriterVector> Bitstream::createPropertyWriters() {
|
||||
QHash<const QMetaObject*, PropertyWriterVector> propertyWriters;
|
||||
foreach (const QMetaObject* metaObject, getMetaObjects()) {
|
||||
QVector<PropertyWriter>& writers = propertyWriters[metaObject];
|
||||
PropertyWriterVector& writers = propertyWriters[metaObject];
|
||||
for (int i = 0; i < metaObject->propertyCount(); i++) {
|
||||
QMetaProperty property = metaObject->property(i);
|
||||
if (!property.isStored()) {
|
||||
|
@ -1070,7 +1576,7 @@ QHash<const QMetaObject*, QVector<PropertyWriter> > Bitstream::createPropertyWri
|
|||
const TypeStreamer* streamer;
|
||||
if (property.isEnumType()) {
|
||||
QMetaEnum metaEnum = property.enumerator();
|
||||
streamer = getEnumStreamers().value(QPair<QByteArray, QByteArray>(
|
||||
streamer = getEnumStreamers().value(ScopeNamePair(
|
||||
QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())),
|
||||
QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name()))));
|
||||
} else {
|
||||
|
@ -1324,7 +1830,7 @@ void FieldReader::readDelta(Bitstream& in, const TypeStreamer* streamer, QVarian
|
|||
}
|
||||
|
||||
ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject,
|
||||
const QVector<PropertyReader>& properties) :
|
||||
const PropertyReaderVector& properties) :
|
||||
_className(className),
|
||||
_metaObject(metaObject),
|
||||
_properties(properties) {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
class QByteArray;
|
||||
class QColor;
|
||||
class QDataStream;
|
||||
class QScriptValue;
|
||||
class QUrl;
|
||||
|
||||
class Attribute;
|
||||
|
@ -44,6 +45,10 @@ class TypeStreamer;
|
|||
|
||||
typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
|
||||
|
||||
typedef QPair<QByteArray, QByteArray> ScopeNamePair;
|
||||
typedef QVector<PropertyReader> PropertyReaderVector;
|
||||
typedef QVector<PropertyWriter> PropertyWriterVector;
|
||||
|
||||
/// Streams integer identifiers that conform to the following pattern: each ID encountered in the stream is either one that
|
||||
/// has been sent (received) before, or is one more than the highest previously encountered ID (starting at zero). This allows
|
||||
/// us to use the minimum number of bits to encode the IDs.
|
||||
|
@ -287,11 +292,15 @@ public:
|
|||
template<class T> void writeDelta(const T& value, const T& reference);
|
||||
template<class T> void readDelta(T& value, const T& reference);
|
||||
|
||||
void writeRawDelta(const QVariant& value, const QVariant& reference);
|
||||
void readRawDelta(QVariant& value, const QVariant& reference);
|
||||
|
||||
void writeRawDelta(const QObject* value, const QObject* reference);
|
||||
void readRawDelta(QObject*& value, const QObject* reference);
|
||||
|
||||
void writeRawDelta(const QScriptValue& value, const QScriptValue& reference);
|
||||
void readRawDelta(QScriptValue& value, const QScriptValue& reference);
|
||||
|
||||
template<class T> void writeRawDelta(const T& value, const T& reference);
|
||||
template<class T> void readRawDelta(T& value, const T& reference);
|
||||
|
||||
|
@ -316,9 +325,15 @@ public:
|
|||
Bitstream& operator<<(uint value);
|
||||
Bitstream& operator>>(uint& value);
|
||||
|
||||
Bitstream& operator<<(qint64 value);
|
||||
Bitstream& operator>>(qint64& value);
|
||||
|
||||
Bitstream& operator<<(float value);
|
||||
Bitstream& operator>>(float& value);
|
||||
|
||||
Bitstream& operator<<(double value);
|
||||
Bitstream& operator>>(double& value);
|
||||
|
||||
Bitstream& operator<<(const glm::vec3& value);
|
||||
Bitstream& operator>>(glm::vec3& value);
|
||||
|
||||
|
@ -337,6 +352,12 @@ public:
|
|||
Bitstream& operator<<(const QUrl& url);
|
||||
Bitstream& operator>>(QUrl& url);
|
||||
|
||||
Bitstream& operator<<(const QDateTime& dateTime);
|
||||
Bitstream& operator>>(QDateTime& dateTime);
|
||||
|
||||
Bitstream& operator<<(const QRegExp& regExp);
|
||||
Bitstream& operator>>(QRegExp& regExp);
|
||||
|
||||
Bitstream& operator<<(const QVariant& value);
|
||||
Bitstream& operator>>(QVariant& value);
|
||||
|
||||
|
@ -372,6 +393,9 @@ public:
|
|||
Bitstream& operator<<(const QScriptString& string);
|
||||
Bitstream& operator>>(QScriptString& string);
|
||||
|
||||
Bitstream& operator<<(const QScriptValue& value);
|
||||
Bitstream& operator>>(QScriptValue& value);
|
||||
|
||||
Bitstream& operator<<(const SharedObjectPointer& object);
|
||||
Bitstream& operator>>(SharedObjectPointer& object);
|
||||
|
||||
|
@ -422,14 +446,18 @@ private:
|
|||
static QHash<QByteArray, const QMetaObject*>& getMetaObjects();
|
||||
static QMultiHash<const QMetaObject*, const QMetaObject*>& getMetaObjectSubClasses();
|
||||
static QHash<int, const TypeStreamer*>& getTypeStreamers();
|
||||
static const QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& getEnumStreamers();
|
||||
static QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*> createEnumStreamers();
|
||||
|
||||
static const QHash<ScopeNamePair, const TypeStreamer*>& getEnumStreamers();
|
||||
static QHash<ScopeNamePair, const TypeStreamer*> createEnumStreamers();
|
||||
|
||||
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();
|
||||
|
||||
static const QHash<const QMetaObject*, PropertyReaderVector>& getPropertyReaders();
|
||||
static QHash<const QMetaObject*, PropertyReaderVector> createPropertyReaders();
|
||||
|
||||
static const QHash<const QMetaObject*, PropertyWriterVector>& getPropertyWriters();
|
||||
static QHash<const QMetaObject*, PropertyWriterVector> createPropertyWriters();
|
||||
};
|
||||
|
||||
template<class T> inline void Bitstream::writeDelta(const T& value, const T& reference) {
|
||||
|
|
|
@ -13,11 +13,95 @@
|
|||
|
||||
#include <QNetworkReply>
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "AttributeRegistry.h"
|
||||
#include "ScriptCache.h"
|
||||
|
||||
static int scriptValueMetaTypeId = qRegisterMetaType<QScriptValue>();
|
||||
static bool scriptValueComparators = QMetaType::registerComparators<QScriptValue>();
|
||||
|
||||
bool operator==(const QScriptValue& first, const QScriptValue& second) {
|
||||
if (first.isUndefined()) {
|
||||
return second.isUndefined();
|
||||
|
||||
} else if (first.isNull()) {
|
||||
return second.isNull();
|
||||
|
||||
} else if (first.isBool()) {
|
||||
return second.isBool() && first.toBool() == second.toBool();
|
||||
|
||||
} else if (first.isNumber()) {
|
||||
return second.isNumber() && first.toNumber() == second.toNumber();
|
||||
|
||||
} else if (first.isString()) {
|
||||
return second.isString() && first.toString() == second.toString();
|
||||
|
||||
} else if (first.isVariant()) {
|
||||
return second.isVariant() && first.toVariant() == second.toVariant();
|
||||
|
||||
} else if (first.isQObject()) {
|
||||
return second.isQObject() && first.toQObject() == second.toQObject();
|
||||
|
||||
} else if (first.isQMetaObject()) {
|
||||
return second.isQMetaObject() && first.toQMetaObject() == second.toQMetaObject();
|
||||
|
||||
} else if (first.isDate()) {
|
||||
return second.isDate() && first.toDateTime() == second.toDateTime();
|
||||
|
||||
} else if (first.isRegExp()) {
|
||||
return second.isRegExp() && first.toRegExp() == second.toRegExp();
|
||||
|
||||
} else if (first.isArray()) {
|
||||
if (!second.isArray()) {
|
||||
return false;
|
||||
}
|
||||
int length = first.property(ScriptCache::getInstance()->getLengthString()).toInt32();
|
||||
if (second.property(ScriptCache::getInstance()->getLengthString()).toInt32() != length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (first.property(i) != second.property(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (first.isObject()) {
|
||||
if (!second.isObject()) {
|
||||
return false;
|
||||
}
|
||||
int propertyCount = 0;
|
||||
for (QScriptValueIterator it(first); it.hasNext(); ) {
|
||||
it.next();
|
||||
if (second.property(it.scriptName()) != it.value()) {
|
||||
return false;
|
||||
}
|
||||
propertyCount++;
|
||||
}
|
||||
// make sure the second has exactly as many properties as the first
|
||||
for (QScriptValueIterator it(second); it.hasNext(); ) {
|
||||
it.next();
|
||||
if (--propertyCount < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return !second.isValid();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator!=(const QScriptValue& first, const QScriptValue& second) {
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
bool operator<(const QScriptValue& first, const QScriptValue& second) {
|
||||
return first.lessThan(second);
|
||||
}
|
||||
|
||||
ScriptCache* ScriptCache::getInstance() {
|
||||
static ScriptCache cache;
|
||||
return &cache;
|
||||
|
|
|
@ -65,6 +65,12 @@ private:
|
|||
QScriptString _generatorString;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QScriptValue)
|
||||
|
||||
bool operator==(const QScriptValue& first, const QScriptValue& second);
|
||||
bool operator!=(const QScriptValue& first, const QScriptValue& second);
|
||||
bool operator<(const QScriptValue& first, const QScriptValue& second);
|
||||
|
||||
/// A program loaded from the network.
|
||||
class NetworkProgram : public Resource {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <QScriptValueIterator>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <MetavoxelMessages.h>
|
||||
|
@ -41,6 +43,8 @@ static int streamedBytesReceived = 0;
|
|||
static int sharedObjectsCreated = 0;
|
||||
static int sharedObjectsDestroyed = 0;
|
||||
static int objectMutationsPerformed = 0;
|
||||
static int scriptObjectsCreated = 0;
|
||||
static int scriptMutationsPerformed = 0;
|
||||
|
||||
static QByteArray createRandomBytes(int minimumSize, int maximumSize) {
|
||||
QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0);
|
||||
|
@ -79,6 +83,48 @@ static TestSharedObjectA::TestFlags getRandomTestFlags() {
|
|||
return flags;
|
||||
}
|
||||
|
||||
static QScriptValue createRandomScriptValue(bool complex = false) {
|
||||
scriptObjectsCreated++;
|
||||
switch (randIntInRange(0, complex ? 5 : 3)) {
|
||||
case 0:
|
||||
return QScriptValue(QScriptValue::NullValue);
|
||||
|
||||
case 1:
|
||||
return QScriptValue(randomBoolean());
|
||||
|
||||
case 2:
|
||||
return QScriptValue(randFloat());
|
||||
|
||||
case 3:
|
||||
return QScriptValue(QString(createRandomBytes()));
|
||||
|
||||
case 4: {
|
||||
int length = randIntInRange(2, 6);
|
||||
QScriptValue value = ScriptCache::getInstance()->getEngine()->newArray(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
value.setProperty(i, createRandomScriptValue());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
default: {
|
||||
QScriptValue value = ScriptCache::getInstance()->getEngine()->newObject();
|
||||
if (randomBoolean()) {
|
||||
value.setProperty("foo", createRandomScriptValue());
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
value.setProperty("bar", createRandomScriptValue());
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
value.setProperty("baz", createRandomScriptValue());
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
value.setProperty("bong", createRandomScriptValue());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TestMessageC createRandomMessageC() {
|
||||
TestMessageC message;
|
||||
message.foo = randomBoolean();
|
||||
|
@ -86,6 +132,7 @@ static TestMessageC createRandomMessageC() {
|
|||
message.baz = randFloat();
|
||||
message.bong.foo = createRandomBytes();
|
||||
message.bong.baz = getRandomTestEnum();
|
||||
message.bizzle = createRandomScriptValue(true);
|
||||
return message;
|
||||
}
|
||||
|
||||
|
@ -201,6 +248,7 @@ bool MetavoxelTests::run() {
|
|||
datagramsReceived << "with" << bytesReceived << "bytes";
|
||||
qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed;
|
||||
qDebug() << "Performed" << objectMutationsPerformed << "object mutations";
|
||||
qDebug() << "Created" << scriptObjectsCreated << "script objects, mutated" << scriptMutationsPerformed;
|
||||
qDebug();
|
||||
|
||||
qDebug() << "Running serialization tests...";
|
||||
|
@ -284,7 +332,7 @@ static QVariant createRandomMessage() {
|
|||
}
|
||||
|
||||
static SharedObjectPointer mutate(const SharedObjectPointer& state) {
|
||||
switch(randIntInRange(0, 3)) {
|
||||
switch (randIntInRange(0, 4)) {
|
||||
case 0: {
|
||||
SharedObjectPointer newState = state->clone(true);
|
||||
static_cast<TestSharedObjectA*>(newState.data())->setFoo(randFloat());
|
||||
|
@ -303,6 +351,38 @@ static SharedObjectPointer mutate(const SharedObjectPointer& state) {
|
|||
objectMutationsPerformed++;
|
||||
return newState;
|
||||
}
|
||||
case 3: {
|
||||
SharedObjectPointer newState = state->clone(true);
|
||||
QScriptValue oldValue = static_cast<TestSharedObjectA*>(newState.data())->getBizzle();
|
||||
QScriptValue newValue = ScriptCache::getInstance()->getEngine()->newObject();
|
||||
for (QScriptValueIterator it(oldValue); it.hasNext(); ) {
|
||||
it.next();
|
||||
newValue.setProperty(it.scriptName(), it.value());
|
||||
}
|
||||
switch (randIntInRange(0, 2)) {
|
||||
case 0: {
|
||||
QScriptValue oldArray = oldValue.property("foo");
|
||||
int oldLength = oldArray.property(ScriptCache::getInstance()->getLengthString()).toInt32();
|
||||
QScriptValue newArray = ScriptCache::getInstance()->getEngine()->newArray(oldLength);
|
||||
for (int i = 0; i < oldLength; i++) {
|
||||
newArray.setProperty(i, oldArray.property(i));
|
||||
}
|
||||
newArray.setProperty(randIntInRange(0, oldLength - 1), createRandomScriptValue(true));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
newValue.setProperty("bar", QScriptValue(randFloat()));
|
||||
break;
|
||||
|
||||
default:
|
||||
newValue.setProperty("baz", createRandomScriptValue(true));
|
||||
break;
|
||||
}
|
||||
static_cast<TestSharedObjectA*>(newState.data())->setBizzle(newValue);
|
||||
scriptMutationsPerformed++;
|
||||
objectMutationsPerformed++;
|
||||
return newState;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -503,7 +583,10 @@ TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) :
|
|||
_foo(foo),
|
||||
_baz(baz),
|
||||
_bong(bong) {
|
||||
sharedObjectsCreated++;
|
||||
sharedObjectsCreated++;
|
||||
|
||||
_bizzle = ScriptCache::getInstance()->getEngine()->newObject();
|
||||
_bizzle.setProperty("foo", ScriptCache::getInstance()->getEngine()->newArray(4));
|
||||
}
|
||||
|
||||
TestSharedObjectA::~TestSharedObjectA() {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QVariantList>
|
||||
|
||||
#include <DatagramSequencer.h>
|
||||
#include <ScriptCache.h>
|
||||
|
||||
class SequencedTestMessage;
|
||||
|
||||
|
@ -96,7 +97,8 @@ class TestSharedObjectA : public SharedObject {
|
|||
Q_PROPERTY(float foo READ getFoo WRITE setFoo NOTIFY fooChanged)
|
||||
Q_PROPERTY(TestEnum baz READ getBaz WRITE setBaz)
|
||||
Q_PROPERTY(TestFlags bong READ getBong WRITE setBong)
|
||||
|
||||
Q_PROPERTY(QScriptValue bizzle READ getBizzle WRITE setBizzle)
|
||||
|
||||
public:
|
||||
|
||||
enum TestEnum { FIRST_TEST_ENUM, SECOND_TEST_ENUM, THIRD_TEST_ENUM };
|
||||
|
@ -116,6 +118,9 @@ public:
|
|||
void setBong(TestFlags bong) { _bong = bong; }
|
||||
TestFlags getBong() const { return _bong; }
|
||||
|
||||
void setBizzle(const QScriptValue& bizzle) { _bizzle = bizzle; }
|
||||
const QScriptValue& getBizzle() const { return _bizzle; }
|
||||
|
||||
signals:
|
||||
|
||||
void fooChanged(float foo);
|
||||
|
@ -125,6 +130,7 @@ private:
|
|||
float _foo;
|
||||
TestEnum _baz;
|
||||
TestFlags _bong;
|
||||
QScriptValue _bizzle;
|
||||
};
|
||||
|
||||
DECLARE_ENUM_METATYPE(TestSharedObjectA, TestEnum)
|
||||
|
@ -204,6 +210,7 @@ class TestMessageC : STREAM public TestMessageA {
|
|||
public:
|
||||
|
||||
STREAM TestMessageB bong;
|
||||
STREAM QScriptValue bizzle;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(TestMessageC)
|
||||
|
|
Loading…
Reference in a new issue