mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 22:51:20 +02:00
checkpoint on virtual entities
This commit is contained in:
parent
e800d5457b
commit
3c4f5f88d0
11 changed files with 617 additions and 71 deletions
|
@ -78,60 +78,62 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem& en
|
||||||
|
|
||||||
Model* EntityTreeRenderer::getModel(const EntityItem& entityItem) {
|
Model* EntityTreeRenderer::getModel(const EntityItem& entityItem) {
|
||||||
Model* model = NULL;
|
Model* model = NULL;
|
||||||
|
|
||||||
|
if (!entityItem.getModelURL().isEmpty()) {
|
||||||
#ifdef HIDE_SUBCLASS_METHODS
|
#ifdef HIDE_SUBCLASS_METHODS
|
||||||
if (entityItem.isKnownID()) {
|
if (entityItem.isKnownID()) {
|
||||||
if (_knownEntityItemModels.find(entityItem.getID()) != _knownEntityItemModels.end()) {
|
if (_knownEntityItemModels.find(entityItem.getID()) != _knownEntityItemModels.end()) {
|
||||||
model = _knownEntityItemModels[entityItem.getID()];
|
model = _knownEntityItemModels[entityItem.getID()];
|
||||||
if (QUrl(entityItem.getModelURL()) != model->getURL()) {
|
if (QUrl(entityItem.getModelURL()) != model->getURL()) {
|
||||||
delete model; // delete the old model...
|
delete model; // delete the old model...
|
||||||
model = NULL;
|
model = NULL;
|
||||||
_knownEntityItemModels.remove(entityItem.getID());
|
_knownEntityItemModels.remove(entityItem.getID());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if we don't have a model... but our item does have a model URL
|
|
||||||
if (!model && !entityItem.getModelURL().isEmpty()) {
|
|
||||||
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
qDebug() << "about to call QMetaObject::invokeMethod(this, 'getModel', Qt::BlockingQueuedConnection,...";
|
|
||||||
QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection,
|
|
||||||
Q_RETURN_ARG(Model*, model), Q_ARG(const EntityItem&, entityItem));
|
|
||||||
qDebug() << "got it... model=" << model;
|
|
||||||
return model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model = new Model();
|
// if we don't have a model... but our item does have a model URL
|
||||||
model->init();
|
if (!model) {
|
||||||
model->setURL(QUrl(entityItem.getModelURL()));
|
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
|
||||||
_knownEntityItemModels[entityItem.getID()] = model;
|
if (QThread::currentThread() != thread()) {
|
||||||
}
|
qDebug() << "about to call QMetaObject::invokeMethod(this, 'getModel', Qt::BlockingQueuedConnection,...";
|
||||||
|
QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(Model*, model), Q_ARG(const EntityItem&, entityItem));
|
||||||
|
qDebug() << "got it... model=" << model;
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
model = new Model();
|
||||||
|
model->init();
|
||||||
|
model->setURL(QUrl(entityItem.getModelURL()));
|
||||||
|
_knownEntityItemModels[entityItem.getID()] = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (_unknownEntityItemModels.find(entityItem.getCreatorTokenID()) != _unknownEntityItemModels.end()) {
|
||||||
|
model = _unknownEntityItemModels[entityItem.getCreatorTokenID()];
|
||||||
|
if (QUrl(entityItem.getModelURL()) != model->getURL()) {
|
||||||
|
delete model; // delete the old model...
|
||||||
|
model = NULL;
|
||||||
|
_unknownEntityItemModels.remove(entityItem.getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!model) {
|
||||||
|
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(Model*, model), Q_ARG(const EntityItem&, entityItem));
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
model = new Model();
|
||||||
if (_unknownEntityItemModels.find(entityItem.getCreatorTokenID()) != _unknownEntityItemModels.end()) {
|
model->init();
|
||||||
model = _unknownEntityItemModels[entityItem.getCreatorTokenID()];
|
model->setURL(QUrl(entityItem.getModelURL()));
|
||||||
if (QUrl(entityItem.getModelURL()) != model->getURL()) {
|
_unknownEntityItemModels[entityItem.getCreatorTokenID()] = model;
|
||||||
delete model; // delete the old model...
|
|
||||||
model = NULL;
|
|
||||||
_unknownEntityItemModels.remove(entityItem.getID());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!model) {
|
|
||||||
// Make sure we only create new models on the thread that owns the EntityTreeRenderer
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
QMetaObject::invokeMethod(this, "getModel", Qt::BlockingQueuedConnection,
|
|
||||||
Q_RETURN_ARG(Model*, model), Q_ARG(const EntityItem&, entityItem));
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
model = new Model();
|
|
||||||
model->init();
|
|
||||||
model->setURL(QUrl(entityItem.getModelURL()));
|
|
||||||
_unknownEntityItemModels[entityItem.getCreatorTokenID()] = model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ void EntityEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeCol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityEditPacketSender::queueEntityEditMessage(PacketType type, EntityItemID modelID,
|
void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemID modelID,
|
||||||
const EntityItemProperties& properties) {
|
const EntityItemProperties& properties) {
|
||||||
if (!_shouldSend) {
|
if (!_shouldSend) {
|
||||||
return; // bail early
|
return; // bail early
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
/// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in
|
/// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in
|
||||||
/// which case up to MaxPendingMessages will be buffered and processed when voxel servers are known.
|
/// which case up to MaxPendingMessages will be buffered and processed when voxel servers are known.
|
||||||
/// NOTE: EntityItemProperties assumes that all distances are in meter units
|
/// NOTE: EntityItemProperties assumes that all distances are in meter units
|
||||||
void queueEntityEditMessage(PacketType type, EntityItemID modelID, const EntityItemProperties& properties);
|
void queueEditEntityMessage(PacketType type, EntityItemID modelID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
// My server type is the model server
|
// My server type is the model server
|
||||||
virtual char getMyNodeType() const { return NodeType::EntityServer; }
|
virtual char getMyNodeType() const { return NodeType::EntityServer; }
|
||||||
|
|
|
@ -87,6 +87,13 @@ EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int byte
|
||||||
return NULL; // TODO Implement this for real!
|
return NULL; // TODO Implement this for real!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityTypes::decodEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
||||||
|
const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
|
bool valid = false;
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool registered = EntityTypes::registerEntityType(EntityTypes::Base, "Base")
|
bool registered = EntityTypes::registerEntityType(EntityTypes::Base, "Base")
|
||||||
&& EntityTypes::registerEntityType(EntityTypes::Model, "Model"); // TODO: move this to model subclass
|
&& EntityTypes::registerEntityType(EntityTypes::Model, "Model"); // TODO: move this to model subclass
|
||||||
|
|
||||||
|
@ -1018,7 +1025,7 @@ EntityItem* EntityItem::fromEditPacket(const unsigned char* data, int length, in
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::debugDump() const {
|
void EntityItem::debugDump() const {
|
||||||
qDebug("EntityItem id :%u", _id);
|
qDebug() << "EntityItem id:" << getEntityItemID();
|
||||||
qDebug(" edited ago:%f", getEditedAgo());
|
qDebug(" edited ago:%f", getEditedAgo());
|
||||||
qDebug(" should die:%s", debug::valueOf(getShouldBeDeleted()));
|
qDebug(" should die:%s", debug::valueOf(getShouldBeDeleted()));
|
||||||
qDebug(" position:%f,%f,%f", _position.x, _position.y, _position.z);
|
qDebug(" position:%f,%f,%f", _position.x, _position.y, _position.z);
|
||||||
|
@ -1026,10 +1033,401 @@ void EntityItem::debugDump() const {
|
||||||
|
|
||||||
#ifdef HIDE_SUBCLASS_METHODS
|
#ifdef HIDE_SUBCLASS_METHODS
|
||||||
qDebug(" color:%d,%d,%d", _color[0], _color[1], _color[2]);
|
qDebug(" color:%d,%d,%d", _color[0], _color[1], _color[2]);
|
||||||
qDebug() << " modelURL:" << qPrintable(getModelURL());
|
if (!getModelURL().isEmpty()) {
|
||||||
|
qDebug() << " modelURL:" << qPrintable(getModelURL());
|
||||||
|
} else {
|
||||||
|
qDebug() << " modelURL: NONE";
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
//Change this to use property flags...
|
||||||
|
//How do we also change this to support spanning multiple MTUs...
|
||||||
|
//Need to output the encode structure like handling packets over the wire...
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool EntityItem::encodeEntityEditMessageDetails(PacketType command, EntityItemID id, const EntityItemProperties& properties,
|
||||||
|
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
||||||
|
|
||||||
|
OctreePacketData packetData(false, sizeIn); // create a packetData object to add out packet details too.
|
||||||
|
|
||||||
|
bool success = true; // assume the best
|
||||||
|
OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best
|
||||||
|
sizeOut = 0;
|
||||||
|
|
||||||
|
// TODO: We need to review how jurisdictions should be handled for entities. (The old Models and Particles code
|
||||||
|
// didn't do anything special for jurisdictions, so we're keeping that same behavior here.)
|
||||||
|
//
|
||||||
|
// Always include the root octcode. This is only because the OctreeEditPacketSender will check these octcodes
|
||||||
|
// to determine which server to send the changes to in the case of multiple jurisdictions. The root will be sent
|
||||||
|
// to all servers.
|
||||||
|
glm::vec3 rootPosition(0);
|
||||||
|
float rootScale = 0.5f;
|
||||||
|
unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale);
|
||||||
|
|
||||||
|
success = packetData.startSubTree(octcode);
|
||||||
|
delete[] octcode;
|
||||||
|
|
||||||
|
// assuming we have rome to fit our octalCode, proceed...
|
||||||
|
if (success) {
|
||||||
|
|
||||||
|
// Now add our edit content details...
|
||||||
|
bool isNewEntityItem = (id.id == NEW_ENTITY);
|
||||||
|
|
||||||
|
// id
|
||||||
|
// encode our ID as a byte count coded byte stream
|
||||||
|
ByteCountCoded<quint32> idCoder = id.id;
|
||||||
|
QByteArray encodedID = idCoder;
|
||||||
|
|
||||||
|
// encode our ID as a byte count coded byte stream
|
||||||
|
ByteCountCoded<quint32> tokenCoder;
|
||||||
|
QByteArray encodedToken;
|
||||||
|
|
||||||
|
// special case for handling "new" modelItems
|
||||||
|
if (isNewEntityItem) {
|
||||||
|
// encode our creator token as a byte count coded byte stream
|
||||||
|
tokenCoder = id.creatorTokenID;
|
||||||
|
encodedToken = tokenCoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode our type as a byte count coded byte stream
|
||||||
|
ByteCountCoded<quint32> typeCoder = (quint32)properties.getType();
|
||||||
|
QByteArray encodedType = typeCoder;
|
||||||
|
|
||||||
|
quint64 updateDelta = 0; // this is an edit so by definition, it's update is in sync
|
||||||
|
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
|
||||||
|
QByteArray encodedUpdateDelta = updateDeltaCoder;
|
||||||
|
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
||||||
|
EntityPropertyFlags requestedProperties = properties.getChangedProperties();
|
||||||
|
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
||||||
|
|
||||||
|
// TODO: we need to handle the multi-pass form of this, similar to how we handle entity data
|
||||||
|
//
|
||||||
|
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
|
||||||
|
// then our modelTreeElementExtraEncodeData should include data about which properties we need to append.
|
||||||
|
//if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) {
|
||||||
|
// requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID());
|
||||||
|
//}
|
||||||
|
|
||||||
|
//qDebug() << "requestedProperties=";
|
||||||
|
//requestedProperties.debugDumpBits();
|
||||||
|
|
||||||
|
LevelDetails entityLevel = packetData.startLevel();
|
||||||
|
|
||||||
|
bool successIDFits = packetData.appendValue(encodedID);
|
||||||
|
if (isNewEntityItem && successIDFits) {
|
||||||
|
successIDFits = packetData.appendValue(encodedToken);
|
||||||
|
}
|
||||||
|
bool successTypeFits = packetData.appendValue(encodedType);
|
||||||
|
bool successLastEditedFits = packetData.appendValue(properties.getLastEdited());
|
||||||
|
bool successLastUpdatedFits = packetData.appendValue(encodedUpdateDelta);
|
||||||
|
|
||||||
|
int propertyFlagsOffset = packetData.getUncompressedByteOffset();
|
||||||
|
QByteArray encodedPropertyFlags = propertyFlags;
|
||||||
|
int oldPropertyFlagsLength = encodedPropertyFlags.length();
|
||||||
|
bool successPropertyFlagsFits = packetData.appendValue(encodedPropertyFlags);
|
||||||
|
int propertyCount = 0;
|
||||||
|
|
||||||
|
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
|
||||||
|
&& successLastUpdatedFits && successPropertyFlagsFits;
|
||||||
|
|
||||||
|
int startOfEntityItemData = packetData.getUncompressedByteOffset();
|
||||||
|
|
||||||
|
if (headerFits) {
|
||||||
|
bool successPropertyFits;
|
||||||
|
|
||||||
|
propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item
|
||||||
|
|
||||||
|
// These items would go here once supported....
|
||||||
|
// PROP_PAGED_PROPERTY,
|
||||||
|
// PROP_CUSTOM_PROPERTIES_INCLUDED,
|
||||||
|
// PROP_VISIBLE,
|
||||||
|
|
||||||
|
// PROP_POSITION
|
||||||
|
if (requestedProperties.getHasProperty(PROP_POSITION)) {
|
||||||
|
//qDebug() << "PROP_POSITION requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendPosition(properties.getPosition());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_POSITION;
|
||||||
|
propertiesDidntFit -= PROP_POSITION;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_POSITION didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_POSITION NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_POSITION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_RADIUS
|
||||||
|
if (requestedProperties.getHasProperty(PROP_RADIUS)) {
|
||||||
|
//qDebug() << "PROP_RADIUS requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getRadius());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_RADIUS;
|
||||||
|
propertiesDidntFit -= PROP_RADIUS;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_RADIUS didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_RADIUS NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_RADIUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_ROTATION
|
||||||
|
if (requestedProperties.getHasProperty(PROP_ROTATION)) {
|
||||||
|
//qDebug() << "PROP_ROTATION requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getRotation());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_ROTATION;
|
||||||
|
propertiesDidntFit -= PROP_ROTATION;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ROTATION didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ROTATION NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_ROTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_SHOULD_BE_DELETED
|
||||||
|
if (requestedProperties.getHasProperty(PROP_SHOULD_BE_DELETED)) {
|
||||||
|
//qDebug() << "PROP_SHOULD_BE_DELETED requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getShouldBeDeleted());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_SHOULD_BE_DELETED;
|
||||||
|
propertiesDidntFit -= PROP_SHOULD_BE_DELETED;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_SHOULD_BE_DELETED didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_SHOULD_BE_DELETED NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_SHOULD_BE_DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_SCRIPT
|
||||||
|
// script would go here...
|
||||||
|
|
||||||
|
|
||||||
|
#if 0 // def HIDE_SUBCLASS_METHODS
|
||||||
|
// PROP_COLOR
|
||||||
|
if (requestedProperties.getHasProperty(PROP_COLOR)) {
|
||||||
|
//qDebug() << "PROP_COLOR requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendColor(properties.getColor());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_COLOR;
|
||||||
|
propertiesDidntFit -= PROP_COLOR;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_COLOR didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_COLOR NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_MODEL_URL
|
||||||
|
if (requestedProperties.getHasProperty(PROP_MODEL_URL)) {
|
||||||
|
//qDebug() << "PROP_MODEL_URL requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getModelURL());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_MODEL_URL;
|
||||||
|
propertiesDidntFit -= PROP_MODEL_URL;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_MODEL_URL didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_MODEL_URL NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_MODEL_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_ANIMATION_URL
|
||||||
|
if (requestedProperties.getHasProperty(PROP_ANIMATION_URL)) {
|
||||||
|
//qDebug() << "PROP_ANIMATION_URL requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getAnimationURL());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_ANIMATION_URL;
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_URL;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_URL didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_URL NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_ANIMATION_FPS
|
||||||
|
if (requestedProperties.getHasProperty(PROP_ANIMATION_FPS)) {
|
||||||
|
//qDebug() << "PROP_ANIMATION_FPS requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getAnimationFPS());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_ANIMATION_FPS;
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_FPS;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_FPS didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_FPS NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_FPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_ANIMATION_FRAME_INDEX
|
||||||
|
if (requestedProperties.getHasProperty(PROP_ANIMATION_FRAME_INDEX)) {
|
||||||
|
//qDebug() << "PROP_ANIMATION_FRAME_INDEX requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getAnimationFrameIndex());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_ANIMATION_FRAME_INDEX;
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_FRAME_INDEX;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_FRAME_INDEX didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_FRAME_INDEX NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_FRAME_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROP_ANIMATION_PLAYING
|
||||||
|
if (requestedProperties.getHasProperty(PROP_ANIMATION_PLAYING)) {
|
||||||
|
//qDebug() << "PROP_ANIMATION_PLAYING requested...";
|
||||||
|
LevelDetails propertyLevel = packetData.startLevel();
|
||||||
|
successPropertyFits = packetData.appendValue(properties.getAnimationIsPlaying());
|
||||||
|
if (successPropertyFits) {
|
||||||
|
propertyFlags |= PROP_ANIMATION_PLAYING;
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_PLAYING;
|
||||||
|
propertyCount++;
|
||||||
|
packetData.endLevel(propertyLevel);
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_PLAYING didn't fit...";
|
||||||
|
packetData.discardLevel(propertyLevel);
|
||||||
|
appendState = OctreeElement::PARTIAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//qDebug() << "PROP_ANIMATION_PLAYING NOT requested...";
|
||||||
|
propertiesDidntFit -= PROP_ANIMATION_PLAYING;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //def HIDE_SUBCLASS_METHODS
|
||||||
|
|
||||||
|
}
|
||||||
|
if (propertyCount > 0) {
|
||||||
|
int endOfEntityItemData = packetData.getUncompressedByteOffset();
|
||||||
|
|
||||||
|
encodedPropertyFlags = propertyFlags;
|
||||||
|
int newPropertyFlagsLength = encodedPropertyFlags.length();
|
||||||
|
packetData.updatePriorBytes(propertyFlagsOffset,
|
||||||
|
(const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
|
||||||
|
|
||||||
|
// if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
|
||||||
|
if (newPropertyFlagsLength < oldPropertyFlagsLength) {
|
||||||
|
int oldSize = packetData.getUncompressedSize();
|
||||||
|
|
||||||
|
const unsigned char* modelItemData = packetData.getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
|
||||||
|
int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
|
||||||
|
int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength;
|
||||||
|
packetData.updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength);
|
||||||
|
|
||||||
|
int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength);
|
||||||
|
packetData.setUncompressedSize(newSize);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown
|
||||||
|
}
|
||||||
|
|
||||||
|
packetData.endLevel(entityLevel);
|
||||||
|
} else {
|
||||||
|
packetData.discardLevel(entityLevel);
|
||||||
|
appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
|
||||||
|
}
|
||||||
|
|
||||||
|
//qDebug() << "propertyFlags=";
|
||||||
|
//propertyFlags.debugDumpBits();
|
||||||
|
|
||||||
|
//qDebug() << "propertiesDidntFit=";
|
||||||
|
//propertiesDidntFit.debugDumpBits();
|
||||||
|
|
||||||
|
// If any part of the model items didn't fit, then the element is considered partial
|
||||||
|
if (appendState != OctreeElement::COMPLETED) {
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: handle mechanism for handling partial fitting data!
|
||||||
|
// add this item into our list for the next appendElementData() pass
|
||||||
|
//modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit);
|
||||||
|
|
||||||
|
// for now, if it's not complete, it's not successful
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
packetData.endSubTree();
|
||||||
|
const unsigned char* finalizedData = packetData.getFinalizedData();
|
||||||
|
int finalizedSize = packetData.getFinalizedSize();
|
||||||
|
memcpy(bufferOut, finalizedData, finalizedSize);
|
||||||
|
sizeOut = finalizedSize;
|
||||||
|
|
||||||
|
qDebug() << "encodeEntityEditMessageDetails().... ";
|
||||||
|
outputBufferBits(finalizedData, finalizedSize);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
packetData.discardSubTree();
|
||||||
|
sizeOut = 0;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 /// OLD VERSION
|
||||||
bool EntityItem::encodeEntityEditMessageDetails(PacketType command, EntityItemID id, const EntityItemProperties& properties,
|
bool EntityItem::encodeEntityEditMessageDetails(PacketType command, EntityItemID id, const EntityItemProperties& properties,
|
||||||
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
||||||
|
|
||||||
|
@ -1196,6 +1594,7 @@ bool EntityItem::encodeEntityEditMessageDetails(PacketType command, EntityItemID
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// adjust any internal timestamps to fix clock skew for this server
|
// adjust any internal timestamps to fix clock skew for this server
|
||||||
void EntityItem::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {
|
void EntityItem::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {
|
||||||
|
@ -1554,13 +1953,61 @@ uint16_t EntityItemProperties::getChangedBits() const {
|
||||||
return changedBits;
|
return changedBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
|
EntityPropertyFlags changedProperties;
|
||||||
|
if (_radiusChanged) {
|
||||||
|
changedProperties += PROP_RADIUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_positionChanged) {
|
||||||
|
changedProperties += PROP_POSITION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_rotationChanged) {
|
||||||
|
changedProperties += PROP_ROTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_shouldBeDeletedChanged) {
|
||||||
|
changedProperties += PROP_SHOULD_BE_DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 //def HIDE_SUBCLASS_METHODS
|
||||||
|
if (_colorChanged) {
|
||||||
|
changedProperties += PROP_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modelURLChanged) {
|
||||||
|
changedProperties += PROP_MODEL_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_animationURLChanged) {
|
||||||
|
changedProperties += PROP_ANIMATION_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_animationIsPlayingChanged) {
|
||||||
|
changedProperties += PROP_ANIMATION_PLAYING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_animationFrameIndexChanged) {
|
||||||
|
changedProperties += PROP_ANIMATION_FRAME_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_animationFPSChanged) {
|
||||||
|
changedProperties += PROP_ANIMATION_FPS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return changedProperties;
|
||||||
|
}
|
||||||
|
|
||||||
QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) const {
|
QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) const {
|
||||||
QScriptValue properties = engine->newObject();
|
QScriptValue properties = engine->newObject();
|
||||||
|
|
||||||
if (_idSet) {
|
if (_idSet) {
|
||||||
properties.setProperty("id", _id);
|
properties.setProperty("id", _id);
|
||||||
properties.setProperty("isKnownID", (_id != UNKNOWN_ENTITY_ID));
|
bool isKnownID = (_id != UNKNOWN_ENTITY_ID);
|
||||||
|
properties.setProperty("isKnownID", isKnownID);
|
||||||
|
qDebug() << "EntityItemProperties::copyToScriptValue()... isKnownID=" << isKnownID << "id=" << _id;
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue position = vec3toScriptValue(engine, _position);
|
QScriptValue position = vec3toScriptValue(engine, _position);
|
||||||
|
@ -1752,6 +2199,7 @@ QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID
|
||||||
obj.setProperty("id", id.id);
|
obj.setProperty("id", id.id);
|
||||||
obj.setProperty("creatorTokenID", id.creatorTokenID);
|
obj.setProperty("creatorTokenID", id.creatorTokenID);
|
||||||
obj.setProperty("isKnownID", id.isKnownID);
|
obj.setProperty("isKnownID", id.isKnownID);
|
||||||
|
qDebug() << "EntityItemIDtoScriptValue()... isKnownID=" << id.isKnownID << "id=" << id.id << "creatorTokenID=" << id.creatorTokenID;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ public:
|
||||||
|
|
||||||
static EntityItem* constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
|
static EntityItem* constructEntityItem(EntityType_t entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
static EntityItem* constructEntityItem(const unsigned char* data, int bytesToRead);
|
static EntityItem* constructEntityItem(const unsigned char* data, int bytesToRead);
|
||||||
|
static bool decodEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
||||||
|
const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
private:
|
private:
|
||||||
static QHash<EntityType_t, QString> _typeNameHash;
|
static QHash<EntityType_t, QString> _typeNameHash;
|
||||||
};
|
};
|
||||||
|
@ -125,6 +127,7 @@ public:
|
||||||
// editing related features supported by all entities
|
// editing related features supported by all entities
|
||||||
quint64 getLastEdited() const { return _lastEdited; }
|
quint64 getLastEdited() const { return _lastEdited; }
|
||||||
uint16_t getChangedBits() const;
|
uint16_t getChangedBits() const;
|
||||||
|
EntityPropertyFlags getChangedProperties() const;
|
||||||
|
|
||||||
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
|
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
|
||||||
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
|
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
|
||||||
|
@ -224,13 +227,19 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
|
||||||
class EntityItemID {
|
class EntityItemID {
|
||||||
public:
|
public:
|
||||||
EntityItemID() :
|
EntityItemID() :
|
||||||
id(NEW_ENTITY), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(false) { };
|
id(NEW_ENTITY), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(false) {
|
||||||
|
//qDebug() << "EntityItemID::EntityItemID()... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
|
||||||
|
};
|
||||||
|
|
||||||
EntityItemID(uint32_t id, uint32_t creatorTokenID, bool isKnownID) :
|
EntityItemID(uint32_t id, uint32_t creatorTokenID, bool isKnownID) :
|
||||||
id(id), creatorTokenID(creatorTokenID), isKnownID(isKnownID) { };
|
id(id), creatorTokenID(creatorTokenID), isKnownID(isKnownID) {
|
||||||
|
//qDebug() << "EntityItemID::EntityItemID(uint32_t id, uint32_t creatorTokenID, bool isKnownID)... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
|
||||||
|
};
|
||||||
|
|
||||||
EntityItemID(uint32_t id) :
|
EntityItemID(uint32_t id) :
|
||||||
id(id), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(true) { };
|
id(id), creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(true) {
|
||||||
|
//qDebug() << "EntityItemID::EntityItemID(uint32_t id)... isKnownID=" << isKnownID << "id=" << id << "creatorTokenID=" << creatorTokenID;
|
||||||
|
};
|
||||||
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t creatorTokenID;
|
uint32_t creatorTokenID;
|
||||||
|
@ -259,7 +268,7 @@ inline uint qHash(const EntityItemID& a, uint seed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
|
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
|
||||||
debug << "[ id:" << id.id << ", creatorTokenID:" << id.creatorTokenID << "]";
|
debug << "[ id:" << id.id << ", creatorTokenID:" << id.creatorTokenID << ", isKnownID:" << id.isKnownID << "]";
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ EntityScriptingInterface::EntityScriptingInterface() :
|
||||||
|
|
||||||
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
|
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
|
||||||
EntityItemID entityID, const EntityItemProperties& properties) {
|
EntityItemID entityID, const EntityItemProperties& properties) {
|
||||||
getEntityPacketSender()->queueEntityEditMessage(packetType, entityID, properties);
|
getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
|
EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
|
||||||
|
@ -56,6 +56,7 @@ EntityItemID EntityScriptingInterface::identifyEntity(EntityItemID entityID) {
|
||||||
// found it!
|
// found it!
|
||||||
entityID.id = actualID;
|
entityID.id = actualID;
|
||||||
entityID.isKnownID = true;
|
entityID.isKnownID = true;
|
||||||
|
qDebug() << "EntityScriptingInterface::identifyEntity() ...found it... isKnownID=" << entityID.isKnownID << "id=" << entityID.id << "creatorTokenID=" << entityID.creatorTokenID;
|
||||||
}
|
}
|
||||||
return entityID;
|
return entityID;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +96,7 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E
|
||||||
if (actualID != UNKNOWN_ENTITY_ID) {
|
if (actualID != UNKNOWN_ENTITY_ID) {
|
||||||
entityID.id = actualID;
|
entityID.id = actualID;
|
||||||
entityID.isKnownID = true;
|
entityID.isKnownID = true;
|
||||||
|
qDebug() << "EntityScriptingInterface::editEntity()... isKnownID=" << entityID.isKnownID << "id=" << entityID.id << "creatorTokenID=" << entityID.creatorTokenID;
|
||||||
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
|
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +132,7 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) {
|
||||||
if (actualID != UNKNOWN_ENTITY_ID) {
|
if (actualID != UNKNOWN_ENTITY_ID) {
|
||||||
entityID.id = actualID;
|
entityID.id = actualID;
|
||||||
entityID.isKnownID = true;
|
entityID.isKnownID = true;
|
||||||
|
qDebug() << "EntityScriptingInterface::deleteEntity()... isKnownID=" << entityID.isKnownID << "id=" << entityID.id << "creatorTokenID=" << entityID.creatorTokenID;
|
||||||
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
|
queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,12 +154,21 @@ EntityItemID EntityScriptingInterface::findClosestEntity(const glm::vec3& center
|
||||||
if (closestEntity) {
|
if (closestEntity) {
|
||||||
result.id = closestEntity->getID();
|
result.id = closestEntity->getID();
|
||||||
result.isKnownID = true;
|
result.isKnownID = true;
|
||||||
|
qDebug() << "EntityScriptingInterface::findClosestEntity()... isKnownID=" << result.isKnownID << "id=" << result.id << "creatorTokenID=" << result.creatorTokenID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EntityScriptingInterface::dumpTree() const {
|
||||||
|
if (_entityTree) {
|
||||||
|
_entityTree->lockForRead();
|
||||||
|
_entityTree->dumpTree();
|
||||||
|
_entityTree->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVector<EntityItemID> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const {
|
QVector<EntityItemID> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const {
|
||||||
QVector<EntityItemID> result;
|
QVector<EntityItemID> result;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
|
@ -186,10 +198,14 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke
|
||||||
RayToEntityIntersectionResult result;
|
RayToEntityIntersectionResult result;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
OctreeElement* element;
|
OctreeElement* element;
|
||||||
EntityItem* intersectedEntity;
|
EntityItem* intersectedEntity = NULL;
|
||||||
result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
|
result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
|
||||||
(void**)&intersectedEntity, lockType, &result.accurate);
|
(void**)&intersectedEntity, lockType, &result.accurate);
|
||||||
if (result.intersects && intersectedEntity) {
|
if (result.intersects && intersectedEntity) {
|
||||||
|
|
||||||
|
qDebug() << "findRayIntersectionWorker().... intersectedEntity=" << intersectedEntity;
|
||||||
|
intersectedEntity->debugDump();
|
||||||
|
|
||||||
result.entityID = intersectedEntity->getEntityItemID();
|
result.entityID = intersectedEntity->getEntityItemID();
|
||||||
result.properties = intersectedEntity->getProperties();
|
result.properties = intersectedEntity->getProperties();
|
||||||
result.intersection = ray.origin + (ray.direction * result.distance);
|
result.intersection = ray.origin + (ray.direction * result.distance);
|
||||||
|
|
|
@ -54,30 +54,30 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// adds a model with the specific properties
|
/// adds a model with the specific properties
|
||||||
EntityItemID addEntity(const EntityItemProperties& properties);
|
Q_INVOKABLE EntityItemID addEntity(const EntityItemProperties& properties);
|
||||||
|
|
||||||
/// identify a recently created model to determine its true ID
|
/// identify a recently created model to determine its true ID
|
||||||
EntityItemID identifyEntity(EntityItemID entityID);
|
Q_INVOKABLE EntityItemID identifyEntity(EntityItemID entityID);
|
||||||
|
|
||||||
/// gets the current model properties for a specific model
|
/// gets the current model properties for a specific model
|
||||||
/// this function will not find return results in script engine contexts which don't have access to models
|
/// this function will not find return results in script engine contexts which don't have access to models
|
||||||
EntityItemProperties getEntityProperties(EntityItemID entityID);
|
Q_INVOKABLE EntityItemProperties getEntityProperties(EntityItemID entityID);
|
||||||
|
|
||||||
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
|
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
|
||||||
/// successful edit, if the input entityID is for an unknown model this function will have no effect
|
/// successful edit, if the input entityID is for an unknown model this function will have no effect
|
||||||
EntityItemID editEntity(EntityItemID entityID, const EntityItemProperties& properties);
|
Q_INVOKABLE EntityItemID editEntity(EntityItemID entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
/// deletes a model
|
/// deletes a model
|
||||||
void deleteEntity(EntityItemID entityID);
|
Q_INVOKABLE void deleteEntity(EntityItemID entityID);
|
||||||
|
|
||||||
/// finds the closest model to the center point, within the radius
|
/// finds the closest model to the center point, within the radius
|
||||||
/// will return a EntityItemID.isKnownID = false if no models are in the radius
|
/// will return a EntityItemID.isKnownID = false if no models are in the radius
|
||||||
/// this function will not find any models in script engine contexts which don't have access to models
|
/// this function will not find any models in script engine contexts which don't have access to models
|
||||||
EntityItemID findClosestEntity(const glm::vec3& center, float radius) const;
|
Q_INVOKABLE EntityItemID findClosestEntity(const glm::vec3& center, float radius) const;
|
||||||
|
|
||||||
/// finds models within the search sphere specified by the center point and radius
|
/// finds models within the search sphere specified by the center point and radius
|
||||||
/// this function will not find any models in script engine contexts which don't have access to models
|
/// this function will not find any models in script engine contexts which don't have access to models
|
||||||
QVector<EntityItemID> findEntities(const glm::vec3& center, float radius) const;
|
Q_INVOKABLE QVector<EntityItemID> findEntities(const glm::vec3& center, float radius) const;
|
||||||
|
|
||||||
/// If the scripting context has visible voxels, this will determine a ray intersection, the results
|
/// If the scripting context has visible voxels, this will determine a ray intersection, the results
|
||||||
/// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate
|
/// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate
|
||||||
|
@ -89,6 +89,8 @@ public slots:
|
||||||
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray);
|
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray);
|
||||||
|
|
||||||
|
|
||||||
|
Q_INVOKABLE void dumpTree() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void modelCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const CollisionInfo& collision);
|
void modelCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const CollisionInfo& collision);
|
||||||
void modelCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& collision);
|
void modelCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& collision);
|
||||||
|
|
|
@ -349,6 +349,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
|
|
||||||
|
qDebug() << "EntityTree::addEntity()... entityID=" << entityID;
|
||||||
|
|
||||||
EntityItem* result = NULL;
|
EntityItem* result = NULL;
|
||||||
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
||||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||||
|
@ -360,6 +363,9 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
|
||||||
// construct the instance of the entity
|
// construct the instance of the entity
|
||||||
EntityTypes::EntityType_t type = properties.getType();
|
EntityTypes::EntityType_t type = properties.getType();
|
||||||
result = EntityTypes::constructEntityItem(type, entityID, properties);
|
result = EntityTypes::constructEntityItem(type, entityID, properties);
|
||||||
|
|
||||||
|
qDebug() << "EntityTree::addEntity()... result = EntityTypes::constructEntityItem(type, entityID, properties)... result->getEntityItemID()=" << result->getEntityItemID();
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
// this does the actual adding of the entity
|
// this does the actual adding of the entity
|
||||||
addEntityItem(result);
|
addEntityItem(result);
|
||||||
|
@ -760,10 +766,33 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
|
||||||
// we handle these types of "edit" packets
|
// we handle these types of "edit" packets
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
case PacketTypeEntityAddOrEdit: {
|
case PacketTypeEntityAddOrEdit: {
|
||||||
// TODO: need to do this
|
qDebug() << "EntityTree::processEditPacketData()....";
|
||||||
|
|
||||||
|
EntityItemID entityItemID;
|
||||||
|
EntityItemProperties properties;
|
||||||
|
|
||||||
|
bool validEditPacket = EntityTypes::decodEntityEditPacket(editData, maxLength,
|
||||||
|
processedBytes, entityItemID, properties);
|
||||||
|
|
||||||
|
// If we got a valid edit packet, then it could be a new entity or it could be an update to
|
||||||
|
// an existing entity... handle appropriately
|
||||||
|
if (validEditPacket) {
|
||||||
|
// search for the entity by EntityItemID
|
||||||
|
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
|
||||||
|
|
||||||
|
// if the entityItem exists, then update it
|
||||||
|
if (existingEntity) {
|
||||||
|
updateEntity(entityItemID, properties);
|
||||||
|
} else {
|
||||||
|
EntityItem* newEntity = addEntity(entityItemID, properties);
|
||||||
|
if (newEntity) {
|
||||||
|
notifyNewlyCreatedEntity(*newEntity, senderNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
qDebug() << "EntityTree::processEditPacketData().... NOT YET IMPLEMENTED!!!";
|
#if 0 ////// OLD CODE...
|
||||||
#if 0
|
|
||||||
bool isValid = false;
|
bool isValid = false;
|
||||||
EntityItem* newEntity = NULL; // EntityItem::fromEditPacket(editData, maxLength, processedBytes, this, isValid);
|
EntityItem* newEntity = NULL; // EntityItem::fromEditPacket(editData, maxLength, processedBytes, this, isValid);
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
|
@ -1062,11 +1091,32 @@ void EntityTree::debugDumpMap() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DebugOperator : public RecurseOctreeOperator {
|
||||||
|
public:
|
||||||
|
virtual bool PreRecursion(OctreeElement* element);
|
||||||
|
virtual bool PostRecursion(OctreeElement* element) { return true; };
|
||||||
|
virtual OctreeElement* PossiblyCreateChildAt(OctreeElement* element, int childIndex) { return NULL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool DebugOperator::PreRecursion(OctreeElement* element) {
|
||||||
|
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||||
|
entityTreeElement->debugDump();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityTree::dumpTree() {
|
||||||
|
// First, look for the existing model in the tree..
|
||||||
|
DebugOperator theOperator;
|
||||||
|
recurseTreeWithOperator(&theOperator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EntityTree::rememberDirtyCube(const AACube& cube) {
|
void EntityTree::rememberDirtyCube(const AACube& cube) {
|
||||||
// TODO: do something here
|
// TODO: do something here
|
||||||
|
qDebug() << "void EntityTree::rememberDirtyCube(const AACube& cube) CALLED BUT NOT IMPLEMENTED!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::rememberEntityToMove(const EntityItem* entity) {
|
void EntityTree::rememberEntityToMove(const EntityItem* entity) {
|
||||||
// TODO: do something here
|
// TODO: do something here
|
||||||
|
qDebug() << "void EntityTree::rememberEntityToMove() CALLED BUT NOT IMPLEMENTED!";
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) const;
|
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) const;
|
||||||
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
||||||
void debugDumpMap();
|
void debugDumpMap();
|
||||||
|
void dumpTree();
|
||||||
|
|
||||||
void rememberDirtyCube(const AACube& cube);
|
void rememberDirtyCube(const AACube& cube);
|
||||||
void rememberEntityToMove(const EntityItem* entity);
|
void rememberEntityToMove(const EntityItem* entity);
|
||||||
|
|
|
@ -333,7 +333,11 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
|
||||||
if (localDistance < distance) {
|
if (localDistance < distance) {
|
||||||
distance = localDistance;
|
distance = localDistance;
|
||||||
face = localFace;
|
face = localFace;
|
||||||
*intersectedObject = (void*)(&entity);
|
|
||||||
|
qDebug() << "about to set intersectedObject=" << entity;
|
||||||
|
entity->debugDump();
|
||||||
|
|
||||||
|
*intersectedObject = (void*)entity;
|
||||||
somethingIntersected = true;
|
somethingIntersected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,7 +345,11 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
|
||||||
} else if (localDistance < distance) {
|
} else if (localDistance < distance) {
|
||||||
distance = localDistance;
|
distance = localDistance;
|
||||||
face = localFace;
|
face = localFace;
|
||||||
*intersectedObject = (void*)(&entity);
|
|
||||||
|
qDebug() << "about to set intersectedObject=" << entity;
|
||||||
|
entity->debugDump();
|
||||||
|
|
||||||
|
*intersectedObject = (void*)entity;
|
||||||
somethingIntersected = true;
|
somethingIntersected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -672,3 +680,12 @@ bool EntityTreeElement::collapseChildren() {
|
||||||
// nothing to do here yet...
|
// nothing to do here yet...
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EntityTreeElement::debugDump() {
|
||||||
|
for (uint16_t i = 0; i < _entityItems->size(); i++) {
|
||||||
|
EntityItem* entity = (*_entityItems)[i];
|
||||||
|
entity->debugDump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -161,6 +161,8 @@ public:
|
||||||
bool containsBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; // NOTE: units in tree units
|
bool containsBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; // NOTE: units in tree units
|
||||||
bool bestFitBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; // NOTE: units in tree units
|
bool bestFitBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; // NOTE: units in tree units
|
||||||
|
|
||||||
|
void debugDump();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void init(unsigned char * octalCode);
|
virtual void init(unsigned char * octalCode);
|
||||||
EntityTree* _myTree;
|
EntityTree* _myTree;
|
||||||
|
|
Loading…
Reference in a new issue