first cut at using partial property info in particle edits

This commit is contained in:
Brad Hefta-Gaub 2014-01-20 16:34:45 -08:00
parent b4b3720fcf
commit d831f9df5e
11 changed files with 439 additions and 293 deletions

View file

@ -21,14 +21,14 @@ EditPacketBuffer::EditPacketBuffer(PACKET_TYPE type, unsigned char* buffer, ssiz
_nodeUUID = nodeUUID;
_currentType = type;
_currentSize = length;
memcpy(_currentBuffer, buffer, length);
memcpy(_currentBuffer, buffer, length);
};
const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::DEFAULT_PACKETS_PER_SECOND;
const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::DEFAULT_PACKETS_PER_SECOND;
OctreeEditPacketSender::OctreeEditPacketSender(PacketSenderNotify* notify) :
PacketSender(notify),
OctreeEditPacketSender::OctreeEditPacketSender(PacketSenderNotify* notify) :
PacketSender(notify),
_shouldSend(true),
_maxPendingMessages(DEFAULT_MAX_PENDING_MESSAGES),
_releaseQueuedMessagesPending(false),
@ -57,7 +57,7 @@ bool OctreeEditPacketSender::serversExist() const {
bool hasServers = false;
bool atLeastOnJurisdictionMissing = false; // assume the best
NodeList* nodeList = NodeList::getInstance();
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
// only send to the NodeTypes that are getMyNodeType()
if (node->getType() == getMyNodeType()) {
@ -78,15 +78,15 @@ bool OctreeEditPacketSender::serversExist() const {
break; // no point in looking further...
}
}
return (hasServers && !atLeastOnJurisdictionMissing);
}
// This method is called when the edit packet layer has determined that it has a fully formed packet destined for
// a known nodeID.
// a known nodeID.
void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) {
NodeList* nodeList = NodeList::getInstance();
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
// only send to the NodeTypes that are getMyNodeType()
if (node->getType() == getMyNodeType() &&
@ -94,7 +94,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c
if (nodeList->getNodeActiveSocketOrPing(node.data())) {
const HifiSockAddr* nodeAddress = node->getActiveSocket();
queuePacketForSending(*nodeAddress, buffer, length);
// debugging output...
bool wantDebugging = false;
if (wantDebugging) {
@ -103,10 +103,10 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c
uint64_t createdAt = (*((uint64_t*)(buffer + numBytesPacketHeader + sizeof(sequence))));
uint64_t queuedAt = usecTimestampNow();
uint64_t transitTime = queuedAt - createdAt;
qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] <<
" - command to node bytes=" << length <<
" sequence=" << sequence <<
qDebug() << "OctreeEditPacketSender::queuePacketToNode() queued " << buffer[0] <<
" - command to node bytes=" << length <<
" sequence=" << sequence <<
" transitTimeSoFar=" << transitTime << " usecs";
}
}
@ -116,7 +116,7 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned c
void OctreeEditPacketSender::processPreServerExistsPackets() {
assert(serversExist()); // we should only be here if we have jurisdictions
// First send out all the single message packets...
while (!_preServerSingleMessagePackets.empty()) {
EditPacketBuffer* packet = _preServerSingleMessagePackets.front();
@ -133,7 +133,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() {
_preServerPackets.erase(_preServerPackets.begin());
}
// if while waiting for the jurisdictions the caller called releaseQueuedMessages()
// if while waiting for the jurisdictions the caller called releaseQueuedMessages()
// then we want to honor that request now.
if (_releaseQueuedMessagesPending) {
releaseQueuedMessages();
@ -160,17 +160,17 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l
if (!_shouldSend) {
return; // bail early
}
assert(serversExist()); // we must have jurisdictions to be here!!
int headerBytes = numBytesForPacketHeader(buffer) + sizeof(short) + sizeof(uint64_t);
unsigned char* octCode = buffer + headerBytes; // skip the packet header to get to the octcode
// We want to filter out edit messages for servers based on the server's Jurisdiction
// But we can't really do that with a packed message, since each edit message could be destined
// But we can't really do that with a packed message, since each edit message could be destined
// for a different server... So we need to actually manage multiple queued packets... one
// for each server
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
// only send to the NodeTypes that are getMyNodeType()
if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) {
@ -181,7 +181,12 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l
const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID];
isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
if (isMyJurisdiction) {
qDebug() << "calling queuePacketToNode(nodeUUID, buffer, length); nodeUUID=" << nodeUUID << " length=" << length;
queuePacketToNode(nodeUUID, buffer, length);
} else {
qDebug() << "not my jurisdiction skipping queuePacketToNode(nodeUUID, buffer, length); nodeUUID=" << nodeUUID << " length=" << length;
}
}
}
@ -190,10 +195,14 @@ void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t l
// NOTE: codeColorBuffer - is JUST the octcode/color and does not contain the packet header!
void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length) {
qDebug() << "queueOctreeEditMessage() line:" << __LINE__;
if (!_shouldSend) {
return; // bail early
}
qDebug() << "queueOctreeEditMessage() line:" << __LINE__;
// If we don't have jurisdictions, then we will simply queue up all of these packets and wait till we have
// jurisdictions for processing
if (!serversExist()) {
@ -211,52 +220,61 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c
}
return; // bail early
}
qDebug() << "queueOctreeEditMessage() line:" << __LINE__;
// We want to filter out edit messages for servers based on the server's Jurisdiction
// But we can't really do that with a packed message, since each edit message could be destined
// But we can't really do that with a packed message, since each edit message could be destined
// for a different server... So we need to actually manage multiple queued packets... one
// for each server
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
// only send to the NodeTypes that are getMyNodeType()
if (node->getActiveSocket() != NULL && node->getType() == getMyNodeType()) {
QUuid nodeUUID = node->getUUID();
bool isMyJurisdiction = true;
if (_serverJurisdictions) {
// we need to get the jurisdiction for this
// here we need to get the "pending packet" for this server
if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) {
const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID];
isMyJurisdiction = (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
qDebug() << "queueOctreeEditMessage() line:" << __LINE__ << " isMyJurisdiction=" << isMyJurisdiction;
} else {
isMyJurisdiction = false;
qDebug() << "queueOctreeEditMessage() line:" << __LINE__;
}
}
if (isMyJurisdiction) {
EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID];
packetBuffer._nodeUUID = nodeUUID;
qDebug() << "queueOctreeEditMessage() line:" << __LINE__;
// If we're switching type, then we send the last one and start over
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
(packetBuffer._currentSize + length >= _maxPacketSize)) {
releaseQueuedPacket(packetBuffer);
initializePacket(packetBuffer, type);
}
// If the buffer is empty and not correctly initialized for our type...
if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) {
initializePacket(packetBuffer, type);
}
// This is really the first time we know which server/node this particular edit message
// is going to, so we couldn't adjust for clock skew till now. But here's our chance.
// We call this virtual function that allows our specific type of EditPacketSender to
// fixup the buffer for any clock skew
if (node->getClockSkewUsec() != 0) {
adjustEditPacketForClockSkew(codeColorBuffer, length, node->getClockSkewUsec());
qDebug() << "queueOctreeEditMessage() line:" << __LINE__;
}
qDebug() << "queueOctreeEditMessage() line:" << __LINE__;
memcpy(&packetBuffer._currentBuffer[packetBuffer._currentSize], codeColorBuffer, length);
packetBuffer._currentSize += length;
}
@ -265,7 +283,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PACKET_TYPE type, unsigned c
}
void OctreeEditPacketSender::releaseQueuedMessages() {
// if we don't yet have jurisdictions then we can't actually release messages yet because we don't
// if we don't yet have jurisdictions then we can't actually release messages yet because we don't
// know where to send them to. Instead, just remember this request and when we eventually get jurisdictions
// call release again at that time.
if (!serversExist()) {
@ -273,12 +291,14 @@ void OctreeEditPacketSender::releaseQueuedMessages() {
} else {
for (std::map<QUuid, EditPacketBuffer>::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) {
releaseQueuedPacket(i->second);
qDebug() << "releaseQueuedMessages() line:" << __LINE__;
}
}
}
void OctreeEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) {
if (packetBuffer._currentSize > 0 && packetBuffer._currentType != PACKET_TYPE_UNKNOWN) {
qDebug() << "OctreeEditPacketSender::releaseQueuedPacket() line:" << __LINE__;
queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize);
}
packetBuffer._currentSize = 0;

View file

@ -22,6 +22,7 @@
#include "ParticlesScriptingInterface.h"
#include "Particle.h"
#include "ParticleTree.h"
uint32_t Particle::_nextID = 0;
VoxelEditPacketSender* Particle::_voxelEditSender = NULL;
@ -57,6 +58,8 @@ void Particle::handleAddParticleResponse(unsigned char* packetData , int packetL
memcpy(&particleID, dataAt, sizeof(particleID));
dataAt += sizeof(particleID);
qDebug() << "handleAddParticleResponse()... particleID=" << particleID << " creatorTokenID=" << creatorTokenID;
// add our token to id mapping
_tokenIDsToIDs[creatorTokenID] = particleID;
}
@ -278,7 +281,7 @@ int Particle::readParticleDataFromBuffer(const unsigned char* data, int bytesLef
}
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes) {
Particle Particle::fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree) {
Particle newParticle; // id and _lastUpdated will get set here...
unsigned char* dataAt = data;
processedBytes = 0;
@ -309,10 +312,30 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
newParticle._newlyCreated = true;
newParticle.setAge(0); // this guy is new!
qDebug() << "fromEditPacket() NEW_PARTICLE";
} else {
qDebug() << "fromEditPacket() existingParticle id=" << editID;
// look up the existing particle
qDebug() << "fromEditPacket() existingParticle id=" << editID << "calling tree->findParticleByID(editID)";
const Particle* existingParticle = tree->findParticleByID(editID, true);
qDebug() << "fromEditPacket() existingParticle id=" << editID << "DONE tree->findParticleByID(editID)";
// copy existing properties before over-writing with new properties
if (existingParticle) {
newParticle = *existingParticle;
qDebug() << "found it...";
existingParticle->debugDump();
} else {
qDebug() << "WHOA! Didn't find it...";
}
newParticle._id = editID;
newParticle._newlyCreated = false;
}
// lastEdited
@ -320,55 +343,92 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe
dataAt += sizeof(newParticle._lastEdited);
processedBytes += sizeof(newParticle._lastEdited);
// All of the remaining items are optional, and may or may not be included based on their included values in the
// properties included bits
uint16_t packetContainsBits = 0;
memcpy(&packetContainsBits, dataAt, sizeof(packetContainsBits));
dataAt += sizeof(packetContainsBits);
processedBytes += sizeof(packetContainsBits);
qDebug() << "fromEditPacket() packetContainsBits=" << packetContainsBits;
// radius
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
dataAt += sizeof(newParticle._radius);
processedBytes += sizeof(newParticle._radius);
if ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_RADIUS";
memcpy(&newParticle._radius, dataAt, sizeof(newParticle._radius));
dataAt += sizeof(newParticle._radius);
processedBytes += sizeof(newParticle._radius);
}
// position
memcpy(&newParticle._position, dataAt, sizeof(newParticle._position));
dataAt += sizeof(newParticle._position);
processedBytes += sizeof(newParticle._position);
if ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_POSITION";
memcpy(&newParticle._position, dataAt, sizeof(newParticle._position));
dataAt += sizeof(newParticle._position);
processedBytes += sizeof(newParticle._position);
}
// color
memcpy(newParticle._color, dataAt, sizeof(newParticle._color));
dataAt += sizeof(newParticle._color);
processedBytes += sizeof(newParticle._color);
if ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_COLOR";
memcpy(newParticle._color, dataAt, sizeof(newParticle._color));
dataAt += sizeof(newParticle._color);
processedBytes += sizeof(newParticle._color);
}
// velocity
memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity));
dataAt += sizeof(newParticle._velocity);
processedBytes += sizeof(newParticle._velocity);
if ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_VELOCITY";
memcpy(&newParticle._velocity, dataAt, sizeof(newParticle._velocity));
dataAt += sizeof(newParticle._velocity);
processedBytes += sizeof(newParticle._velocity);
}
// gravity
memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity));
dataAt += sizeof(newParticle._gravity);
processedBytes += sizeof(newParticle._gravity);
if ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_GRAVITY";
memcpy(&newParticle._gravity, dataAt, sizeof(newParticle._gravity));
dataAt += sizeof(newParticle._gravity);
processedBytes += sizeof(newParticle._gravity);
}
// damping
memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping));
dataAt += sizeof(newParticle._damping);
processedBytes += sizeof(newParticle._damping);
if ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_DAMPING";
memcpy(&newParticle._damping, dataAt, sizeof(newParticle._damping));
dataAt += sizeof(newParticle._damping);
processedBytes += sizeof(newParticle._damping);
}
// lifetime
memcpy(&newParticle._lifetime, dataAt, sizeof(newParticle._lifetime));
dataAt += sizeof(newParticle._lifetime);
processedBytes += sizeof(newParticle._lifetime);
if ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_LIFETIME";
memcpy(&newParticle._lifetime, dataAt, sizeof(newParticle._lifetime));
dataAt += sizeof(newParticle._lifetime);
processedBytes += sizeof(newParticle._lifetime);
}
// inHand
memcpy(&newParticle._inHand, dataAt, sizeof(newParticle._inHand));
dataAt += sizeof(newParticle._inHand);
processedBytes += sizeof(newParticle._inHand);
if ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_INHAND";
memcpy(&newParticle._inHand, dataAt, sizeof(newParticle._inHand));
dataAt += sizeof(newParticle._inHand);
processedBytes += sizeof(newParticle._inHand);
}
// script
uint16_t scriptLength;
memcpy(&scriptLength, dataAt, sizeof(scriptLength));
dataAt += sizeof(scriptLength);
processedBytes += sizeof(scriptLength);
QString tempString((const char*)dataAt);
newParticle._script = tempString;
dataAt += scriptLength;
processedBytes += scriptLength;
if ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT) {
qDebug() << "fromEditPacket() PACKET_CONTAINS_SCRIPT";
uint16_t scriptLength;
memcpy(&scriptLength, dataAt, sizeof(scriptLength));
dataAt += sizeof(scriptLength);
processedBytes += sizeof(scriptLength);
QString tempString((const char*)dataAt);
newParticle._script = tempString;
dataAt += scriptLength;
processedBytes += scriptLength;
}
const bool wantDebugging = true;
if (wantDebugging) {
@ -386,116 +446,168 @@ void Particle::debugDump() const {
printf(" age:%f\n", getAge());
printf(" edited ago:%f\n", getEditedAgo());
printf(" position:%f,%f,%f\n", _position.x, _position.y, _position.z);
printf(" radius:%f\n", getRadius());
printf(" velocity:%f,%f,%f\n", _velocity.x, _velocity.y, _velocity.z);
printf(" gravity:%f,%f,%f\n", _gravity.x, _gravity.y, _gravity.z);
printf(" color:%d,%d,%d\n", _color[0], _color[1], _color[2]);
}
bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
bool Particle::encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID id, const ParticleProperties& properties,
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
bool success = true; // assume the best
unsigned char* copyAt = bufferOut;
sizeOut = 0;
for (int i = 0; i < count && success; i++) {
// get the octal code for the particle
unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y,
details[i].position.z, details[i].radius);
// get the octal code for the particle
int octets = numberOfThreeBitSectionsInCode(octcode);
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes();
// this could be a problem if the caller doesn't include position....
glm::vec3 rootPosition(0);
float rootScale = 0.5f;
unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale);
// make sure we have room to copy this particle
if (sizeOut + lenfthOfEditData > sizeIn) {
success = false;
} else {
// add it to our message
memcpy(copyAt, octcode, lengthOfOctcode);
copyAt += lengthOfOctcode;
sizeOut += lengthOfOctcode;
// old code... this matters for particle servers with different jurisdictions, but for now, we'll send
// everything to the root, since the tree does the right thing...
//
//unsigned char* octcode = pointToOctalCode(details[i].position.x, details[i].position.y,
// details[i].position.z, details[i].radius);
// Now add our edit content details...
int octets = numberOfThreeBitSectionsInCode(octcode);
int lengthOfOctcode = bytesRequiredForCodeLength(octets);
int lenfthOfEditData = lengthOfOctcode + expectedEditMessageBytes();
// id
memcpy(copyAt, &details[i].id, sizeof(details[i].id));
copyAt += sizeof(details[i].id);
sizeOut += sizeof(details[i].id);
// special case for handling "new" particles
if (details[i].id == NEW_PARTICLE) {
// If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that
// we want to send back to the creator as an map to the actual id
memcpy(copyAt, &details[i].creatorTokenID, sizeof(details[i].creatorTokenID));
copyAt += sizeof(details[i].creatorTokenID);
sizeOut += sizeof(details[i].creatorTokenID);
}
// make sure we have room to copy this particle
if (sizeOut + lenfthOfEditData > sizeIn) {
success = false;
} else {
// add it to our message
memcpy(copyAt, octcode, lengthOfOctcode);
copyAt += lengthOfOctcode;
sizeOut += lengthOfOctcode;
// lastEdited
memcpy(copyAt, &details[i].lastEdited, sizeof(details[i].lastEdited));
copyAt += sizeof(details[i].lastEdited);
sizeOut += sizeof(details[i].lastEdited);
// Now add our edit content details...
// radius
memcpy(copyAt, &details[i].radius, sizeof(details[i].radius));
copyAt += sizeof(details[i].radius);
sizeOut += sizeof(details[i].radius);
// id
memcpy(copyAt, &id.id, sizeof(id.id));
copyAt += sizeof(id.id);
sizeOut += sizeof(id.id);
// special case for handling "new" particles
if (id.id == NEW_PARTICLE) {
// If this is a NEW_PARTICLE, then we assume that there's an additional uint32_t creatorToken, that
// we want to send back to the creator as an map to the actual id
memcpy(copyAt, &id.creatorTokenID, sizeof(id.creatorTokenID));
copyAt += sizeof(id.creatorTokenID);
sizeOut += sizeof(id.creatorTokenID);
}
// position
memcpy(copyAt, &details[i].position, sizeof(details[i].position));
copyAt += sizeof(details[i].position);
sizeOut += sizeof(details[i].position);
// lastEdited
uint64_t lastEdited = properties.getLastEdited();
memcpy(copyAt, &lastEdited, sizeof(lastEdited));
copyAt += sizeof(lastEdited);
sizeOut += sizeof(lastEdited);
// color
memcpy(copyAt, details[i].color, sizeof(details[i].color));
copyAt += sizeof(details[i].color);
sizeOut += sizeof(details[i].color);
// All of the remaining items are optional, and may or may not be included based on their included values in the
// properties included bits
uint16_t packetContainsBits = properties.getChangedBits();
memcpy(copyAt, &packetContainsBits, sizeof(packetContainsBits));
copyAt += sizeof(packetContainsBits);
sizeOut += sizeof(packetContainsBits);
// velocity
memcpy(copyAt, &details[i].velocity, sizeof(details[i].velocity));
copyAt += sizeof(details[i].velocity);
sizeOut += sizeof(details[i].velocity);
qDebug() << " packetContainsBits = " << packetContainsBits;
// gravity
memcpy(copyAt, &details[i].gravity, sizeof(details[i].gravity));
copyAt += sizeof(details[i].gravity);
sizeOut += sizeof(details[i].gravity);
// radius
if ((packetContainsBits & PACKET_CONTAINS_RADIUS) == PACKET_CONTAINS_RADIUS) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_RADIUS\n");
float radius = properties.getRadius();
memcpy(copyAt, &radius, sizeof(radius));
copyAt += sizeof(radius);
sizeOut += sizeof(radius);
}
// damping
memcpy(copyAt, &details[i].damping, sizeof(details[i].damping));
copyAt += sizeof(details[i].damping);
sizeOut += sizeof(details[i].damping);
// position
if ((packetContainsBits & PACKET_CONTAINS_POSITION) == PACKET_CONTAINS_POSITION) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_POSITION\n");
memcpy(copyAt, &properties.getPosition(), sizeof(properties.getPosition()));
copyAt += sizeof(properties.getPosition());
sizeOut += sizeof(properties.getPosition());
}
// damping
memcpy(copyAt, &details[i].lifetime, sizeof(details[i].lifetime));
copyAt += sizeof(details[i].lifetime);
sizeOut += sizeof(details[i].lifetime);
// color
if ((packetContainsBits & PACKET_CONTAINS_COLOR) == PACKET_CONTAINS_COLOR) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_COLOR\n");
rgbColor color = { properties.getColor().red, properties.getColor().green, properties.getColor().blue };
memcpy(copyAt, color, sizeof(color));
copyAt += sizeof(color);
sizeOut += sizeof(color);
}
// inHand
memcpy(copyAt, &details[i].inHand, sizeof(details[i].inHand));
copyAt += sizeof(details[i].inHand);
sizeOut += sizeof(details[i].inHand);
// velocity
if ((packetContainsBits & PACKET_CONTAINS_VELOCITY) == PACKET_CONTAINS_VELOCITY) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_VELOCITY\n");
memcpy(copyAt, &properties.getVelocity(), sizeof(properties.getVelocity()));
copyAt += sizeof(properties.getVelocity());
sizeOut += sizeof(properties.getVelocity());
}
// script
uint16_t scriptLength = details[i].updateScript.size() + 1;
// gravity
if ((packetContainsBits & PACKET_CONTAINS_GRAVITY) == PACKET_CONTAINS_GRAVITY) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_GRAVITY\n");
memcpy(copyAt, &properties.getGravity(), sizeof(properties.getGravity()));
copyAt += sizeof(properties.getGravity());
sizeOut += sizeof(properties.getGravity());
}
// damping
if ((packetContainsBits & PACKET_CONTAINS_DAMPING) == PACKET_CONTAINS_DAMPING) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_DAMPING\n");
float damping = properties.getDamping();
memcpy(copyAt, &damping, sizeof(damping));
copyAt += sizeof(damping);
sizeOut += sizeof(damping);
}
// lifetime
if ((packetContainsBits & PACKET_CONTAINS_LIFETIME) == PACKET_CONTAINS_LIFETIME) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_LIFETIME\n");
float lifetime = properties.getLifetime();
memcpy(copyAt, &lifetime, sizeof(lifetime));
copyAt += sizeof(lifetime);
sizeOut += sizeof(lifetime);
}
// inHand
if ((packetContainsBits & PACKET_CONTAINS_INHAND) == PACKET_CONTAINS_INHAND) {
printf("encodeParticleEditMessageDetails() including PACKET_CONTAINS_INHAND\n");
bool inHand = properties.getInHand();
memcpy(copyAt, &inHand, sizeof(inHand));
copyAt += sizeof(inHand);
sizeOut += sizeof(inHand);
}
// script
if ((packetContainsBits & PACKET_CONTAINS_SCRIPT) == PACKET_CONTAINS_SCRIPT) {
printf("encodeParticleEditMessageDetails() including SCRIPT\n");
uint16_t scriptLength = properties.getScript().size() + 1;
memcpy(copyAt, &scriptLength, sizeof(scriptLength));
copyAt += sizeof(scriptLength);
sizeOut += sizeof(scriptLength);
memcpy(copyAt, qPrintable(details[i].updateScript), scriptLength);
memcpy(copyAt, qPrintable(properties.getScript()), scriptLength);
copyAt += scriptLength;
sizeOut += scriptLength;
bool wantDebugging = false;
if (wantDebugging) {
printf("encodeParticleEditMessageDetails()....\n");
printf("Particle id :%u\n", details[i].id);
printf(" nextID:%u\n", _nextID);
}
}
// cleanup
delete[] octcode;
bool wantDebugging = false;
if (wantDebugging) {
printf("encodeParticleEditMessageDetails()....\n");
printf("Particle id :%u\n", id.id);
printf(" nextID:%u\n", _nextID);
}
}
// cleanup
delete[] octcode;
return success;
}
@ -696,7 +808,7 @@ void Particle::setProperties(const ParticleProperties& properties) {
ParticleProperties::ParticleProperties() :
_position(0),
_color(),
_radius(DEFAULT_RADIUS),
_radius(0),
_velocity(0),
_gravity(DEFAULT_GRAVITY),
_damping(DEFAULT_DAMPING),
@ -705,6 +817,7 @@ ParticleProperties::ParticleProperties() :
_inHand(false),
_shouldDie(false),
_lastEdited(usecTimestampNow()),
_positionChanged(false),
_colorChanged(false),
_radiusChanged(false),
@ -718,6 +831,55 @@ ParticleProperties::ParticleProperties() :
{
}
uint16_t ParticleProperties::getChangedBits() const {
uint16_t changedBits = 0;
if (_radiusChanged) {
changedBits += PACKET_CONTAINS_RADIUS;
}
if (_positionChanged) {
changedBits += PACKET_CONTAINS_POSITION;
}
if (_colorChanged) {
changedBits += PACKET_CONTAINS_COLOR;
}
if (_velocityChanged) {
changedBits += PACKET_CONTAINS_VELOCITY;
}
if (_gravityChanged) {
changedBits += PACKET_CONTAINS_GRAVITY;
}
if (_dampingChanged) {
changedBits += PACKET_CONTAINS_DAMPING;
}
if (_lifetimeChanged) {
changedBits += PACKET_CONTAINS_LIFETIME;
}
if (_inHandChanged) {
changedBits += PACKET_CONTAINS_INHAND;
}
if (_scriptChanged) {
changedBits += PACKET_CONTAINS_SCRIPT;
}
// how do we want to handle this?
//if (_shouldDieChanged) {
// changedBits += PACKET_CONTAINS_SHOULDDIE;
//}
return changedBits;
}
QScriptValue ParticleProperties::copyToScriptValue(QScriptEngine* engine) const {
QScriptValue properties = engine->newObject();
@ -783,13 +945,18 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) {
}
QScriptValue radius = object.property("radius");
qDebug() << "copyFromScriptValue() line:" << __LINE__;
if (radius.isValid()) {
qDebug() << "copyFromScriptValue() line:" << __LINE__;
float newRadius;
newRadius = radius.toVariant().toFloat();
qDebug() << "copyFromScriptValue() line:" << __LINE__ << " newRadius=" << newRadius;
qDebug() << "copyFromScriptValue() line:" << __LINE__ << " _radius=" << _radius;
if (newRadius != _radius) {
_radius = newRadius;
_radiusChanged = true;
}
qDebug() << "copyFromScriptValue() line:" << __LINE__ << " _radiusChanged=" << _radiusChanged;
}
QScriptValue velocity = object.property("velocity");
@ -875,6 +1042,8 @@ void ParticleProperties::copyFromScriptValue(const QScriptValue &object) {
_shouldDieChanged = true;
}
}
_lastEdited = usecTimestampNow();
}
void ParticleProperties::copyToParticle(Particle& particle) const {

View file

@ -25,26 +25,21 @@ class VoxelEditPacketSender;
class ParticleEditPacketSender;
class ParticleProperties;
class Particle;
class ParticleTree;
const uint32_t NEW_PARTICLE = 0xFFFFFFFF;
const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF;
const uint32_t UNKNOWN_PARTICLE_ID = 0xFFFFFFFF;
class ParticleDetail {
public:
uint32_t id;
uint64_t lastEdited;
glm::vec3 position;
float radius;
rgbColor color;
glm::vec3 velocity;
glm::vec3 gravity;
float damping;
float lifetime;
bool inHand;
QString updateScript;
uint32_t creatorTokenID;
};
const uint16_t PACKET_CONTAINS_RADIUS = 1;
const uint16_t PACKET_CONTAINS_POSITION = 2;
const uint16_t PACKET_CONTAINS_COLOR = 4;
const uint16_t PACKET_CONTAINS_VELOCITY = 8;
const uint16_t PACKET_CONTAINS_GRAVITY = 16;
const uint16_t PACKET_CONTAINS_DAMPING = 32;
const uint16_t PACKET_CONTAINS_LIFETIME = 64;
const uint16_t PACKET_CONTAINS_INHAND = 128;
const uint16_t PACKET_CONTAINS_SCRIPT = 256;
const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default
const float DEFAULT_DAMPING = 0.99f;
@ -74,10 +69,13 @@ public:
const glm::vec3& getGravity() const { return _gravity; }
float getDamping() const { return _damping; }
float getLifetime() const { return _lifetime; }
QString getScript() const { return _script; }
const QString& getScript() const { return _script; }
bool getInHand() const { return _inHand; }
bool getShouldDie() const { return _shouldDie; }
uint64_t getLastEdited() const { return _lastEdited; }
uint16_t getChangedBits() const;
private:
glm::vec3 _position;
xColor _color;
@ -90,6 +88,7 @@ private:
bool _inHand;
bool _shouldDie;
uint64_t _lastEdited;
bool _positionChanged;
bool _colorChanged;
bool _radiusChanged;
@ -138,7 +137,7 @@ public:
bool inHand = NOT_IN_HAND, QString updateScript = DEFAULT_SCRIPT, uint32_t id = NEW_PARTICLE);
/// creates an NEW particle from an PACKET_TYPE_PARTICLE_ADD_OR_EDIT edit data buffer
static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes);
static Particle fromEditPacket(unsigned char* data, int length, int& processedBytes, ParticleTree* tree);
virtual ~Particle();
virtual void init(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity,
@ -196,7 +195,7 @@ public:
static int expectedBytes();
static int expectedEditMessageBytes();
static bool encodeParticleEditMessageDetails(PACKET_TYPE command, int count, const ParticleDetail* details,
static bool encodeParticleEditMessageDetails(PACKET_TYPE command, ParticleID id, const ParticleProperties& details,
unsigned char* bufferOut, int sizeIn, int& sizeOut);
static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew);

View file

@ -13,7 +13,6 @@
#include "ParticleTree.h"
std::map<uint32_t,ParticleEditHandle*> ParticleEditHandle::_allHandles;
uint32_t ParticleEditHandle::_nextCreatorTokenID = 0;
ParticleEditHandle::ParticleEditHandle(ParticleEditPacketSender* packetSender, ParticleTree* localTree, uint32_t id) {
if (id == NEW_PARTICLE) {
@ -43,13 +42,14 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor
glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) {
// setup a ParticleDetail struct with the data
/****
uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now,
position, radius, {color.red, color.green, color.blue },
velocity, gravity, damping, lifetime, inHand, updateScript, _creatorTokenID };
// queue the packet
_packetSender->queueParticleEditMessages(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &addParticleDetail);
_packetSender->queueParticleEditMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, 1, &addParticleDetail);
// release them
_packetSender->releaseQueuedMessages();
@ -59,6 +59,8 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor
// we can't really do this here, because if we create a particle locally, we'll get a ghost particle
// because we can't really handle updating/deleting it locally
}
****/
}
bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity,
@ -69,6 +71,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor
}
// setup a ParticleDetail struct with the data
/****
uint64_t now = usecTimestampNow();
ParticleDetail newParticleDetail = { _id, now,
position, radius, {color.red, color.green, color.blue },
@ -86,6 +89,7 @@ bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor
Particle tempParticle(position, radius, rcolor, velocity, gravity, damping, lifetime, inHand, updateScript, _id);
_localTree->storeParticle(tempParticle);
}
***/
return true;
}

View file

@ -45,7 +45,6 @@ private:
uint32_t _creatorTokenID;
uint32_t _id;
bool _isKnownID;
static uint32_t _nextCreatorTokenID;
static std::map<uint32_t,ParticleEditHandle*> _allHandles;
ParticleEditPacketSender* _packetSender;
ParticleTree* _localTree;

View file

@ -16,7 +16,7 @@
#include "Particle.h"
void ParticleEditPacketSender::sendEditParticleMessage(PACKET_TYPE type, const ParticleDetail& detail) {
void ParticleEditPacketSender::sendEditParticleMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties) {
// allows app to disable sending if for example voxels have been disabled
if (!_shouldSend) {
return; // bail early
@ -26,35 +26,42 @@ void ParticleEditPacketSender::sendEditParticleMessage(PACKET_TYPE type, const P
int sizeOut = 0;
// This encodes the voxel edit message into a buffer...
if (Particle::encodeParticleEditMessageDetails(type, 1, &detail, &bufferOut[0], _maxPacketSize, sizeOut)){
if (Particle::encodeParticleEditMessageDetails(type, particleID, properties, &bufferOut[0], _maxPacketSize, sizeOut)){
// If we don't have voxel jurisdictions, then we will simply queue up these packets and wait till we have
// jurisdictions for processing
if (!serversExist()) {
queuePendingPacketToNodes(type, bufferOut, sizeOut);
} else {
qDebug("calling queuePacketToNodes(bufferOut, sizeOut=%d)... ", sizeOut);
queuePacketToNodes(bufferOut, sizeOut);
}
}
}
void ParticleEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {
void ParticleEditPacketSender::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) {
Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew);
}
}
void ParticleEditPacketSender::queueParticleEditMessages(PACKET_TYPE type, int numberOfDetails, ParticleDetail* details) {
void ParticleEditPacketSender::queueParticleEditMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties) {
qDebug() << "ParticleEditPacketSender::queueParticleEditMessage() id.id=" << particleID.id << " id.creatorTokenID=" << particleID.creatorTokenID;
if (!_shouldSend) {
return; // bail early
}
for (int i = 0; i < numberOfDetails; i++) {
// use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize
static unsigned char bufferOut[MAX_PACKET_SIZE];
int sizeOut = 0;
if (Particle::encodeParticleEditMessageDetails(type, 1, &details[i], &bufferOut[0], _maxPacketSize, sizeOut)) {
queueOctreeEditMessage(type, bufferOut, sizeOut);
}
}
// use MAX_PACKET_SIZE since it's static and guaranteed to be larger than _maxPacketSize
static unsigned char bufferOut[MAX_PACKET_SIZE];
int sizeOut = 0;
if (Particle::encodeParticleEditMessageDetails(type, particleID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) {
qDebug("calling queueOctreeEditMessage(bufferOut, sizeOut=%d)... ", sizeOut);
queueOctreeEditMessage(type, bufferOut, sizeOut);
}
}

View file

@ -19,14 +19,14 @@ class ParticleEditPacketSender : public OctreeEditPacketSender {
public:
ParticleEditPacketSender(PacketSenderNotify* notify = NULL) : OctreeEditPacketSender(notify) { }
~ParticleEditPacketSender() { }
/// Send particle add message immediately
void sendEditParticleMessage(PACKET_TYPE type, const ParticleDetail& detail);
/// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines
/// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in
/// Send particle add message immediately
void sendEditParticleMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties);
/// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines
/// 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.
void queueParticleEditMessages(PACKET_TYPE type, int numberOfDetails, ParticleDetail* details);
void queueParticleEditMessage(PACKET_TYPE type, ParticleID particleID, const ParticleProperties& properties);
// My server type is the particle server
virtual unsigned char getMyNodeType() const { return NODE_TYPE_PARTICLE_SERVER; }

View file

@ -15,7 +15,7 @@ ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
}
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) const {
ParticleTreeElement* newElement = new ParticleTreeElement(octalCode);
ParticleTreeElement* newElement = new ParticleTreeElement(octalCode);
return newElement;
}
@ -35,7 +35,7 @@ public:
const Particle& searchParticle;
bool found;
};
bool ParticleTree::findAndUpdateOperation(OctreeElement* element, void* extraData) {
FindAndUpdateParticleArgs* args = static_cast<FindAndUpdateParticleArgs*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
@ -51,7 +51,7 @@ void ParticleTree::storeParticle(const Particle& particle, Node* senderNode) {
// First, look for the existing particle in the tree..
FindAndUpdateParticleArgs args = { particle, false };
recurseTreeWithOperation(findAndUpdateOperation, &args);
// if we didn't find it in the tree, then store it...
if (!args.found) {
glm::vec3 position = particle.getPosition();
@ -59,7 +59,7 @@ void ParticleTree::storeParticle(const Particle& particle, Node* senderNode) {
ParticleTreeElement* element = (ParticleTreeElement*)getOrCreateChildElementAt(position.x, position.y, position.z, size);
element->storeParticle(particle, senderNode);
}
}
// what else do we need to do here to get reaveraging to work
_isDirty = true;
}
@ -72,25 +72,25 @@ public:
const Particle* closestParticle;
float closestParticleDistance;
};
bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraData) {
FindNearPointArgs* args = static_cast<FindNearPointArgs*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
glm::vec3 penetration;
bool sphereIntersection = particleTreeElement->getAABox().findSpherePenetration(args->position,
bool sphereIntersection = particleTreeElement->getAABox().findSpherePenetration(args->position,
args->targetRadius, penetration);
// If this particleTreeElement contains the point, then search it...
if (sphereIntersection) {
const Particle* thisClosestParticle = particleTreeElement->getClosestParticle(args->position);
// we may have gotten NULL back, meaning no particle was available
if (thisClosestParticle) {
glm::vec3 particlePosition = thisClosestParticle->getPosition();
float distanceFromPointToParticle = glm::distance(particlePosition, args->position);
// If we're within our target radius
if (distanceFromPointToParticle <= args->targetRadius) {
// we are closer than anything else we've found
@ -101,11 +101,11 @@ bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraDat
}
}
}
// we should be able to optimize this...
return true; // keep searching in case children have closer particles
}
// if this element doesn't contain the point, then none of it's children can contain the point, so stop searching
return false;
}
@ -124,9 +124,11 @@ public:
bool found;
const Particle* foundParticle;
};
bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) {
qDebug() << "ParticleTree::findByIDOperation()....";
FindByIDArgs* args = static_cast<FindByIDArgs*>(extraData);
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
@ -134,7 +136,7 @@ bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) {
if (args->found) {
return false;
}
// as the tree element if it has this particle
const Particle* foundParticle = particleTreeElement->getParticleWithID(args->id);
if (foundParticle) {
@ -142,17 +144,23 @@ bool ParticleTree::findByIDOperation(OctreeElement* element, void* extraData) {
args->found = true;
return false;
}
// keep looking
return true;
}
const Particle* ParticleTree::findParticleByID(uint32_t id) {
const Particle* ParticleTree::findParticleByID(uint32_t id, bool alreadyLocked) {
FindByIDArgs args = { id, false, NULL };
lockForRead();
if (!alreadyLocked) {
qDebug() << "ParticleTree::findParticleByID().... about to call lockForRead()....";
lockForRead();
qDebug() << "ParticleTree::findParticleByID().... after call lockForRead()....";
}
recurseTreeWithOperation(findByIDOperation, &args);
unlock();
if (!alreadyLocked) {
unlock();
}
return args.foundParticle;
}
@ -164,13 +172,21 @@ int ParticleTree::processEditPacketData(PACKET_TYPE packetType, unsigned char* p
// we handle these types of "edit" packets
switch (packetType) {
case PACKET_TYPE_PARTICLE_ADD_OR_EDIT: {
Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes);
qDebug() << " got PACKET_TYPE_PARTICLE_ADD_OR_EDIT... ";
Particle newParticle = Particle::fromEditPacket(editData, maxLength, processedBytes, this);
qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling storeParticle() ";
storeParticle(newParticle, senderNode);
qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER storeParticle() ";
if (newParticle.isNewlyCreated()) {
qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... calling notifyNewlyCreatedParticle() ";
notifyNewlyCreatedParticle(newParticle, senderNode);
qDebug() << "PACKET_TYPE_PARTICLE_ADD_OR_EDIT... AFTER notifyNewlyCreatedParticle() ";
}
qDebug() << " DONE... PACKET_TYPE_PARTICLE_ADD_OR_EDIT... ";
} break;
case PACKET_TYPE_PARTICLE_ERASE: {
processedBytes = 0;
} break;
@ -227,7 +243,7 @@ void ParticleTree::update() {
ParticleTreeUpdateArgs args = { };
recurseTreeWithOperation(updateOperation, &args);
// now add back any of the particles that moved elements....
int movingParticles = args._movingParticles.size();
for (int i = 0; i < movingParticles; i++) {
@ -235,12 +251,12 @@ void ParticleTree::update() {
// if the particle is still inside our total bounds, then re-add it
AABox treeBounds = getRoot()->getAABox();
if (!shouldDie && treeBounds.contains(args._movingParticles[i].getPosition())) {
storeParticle(args._movingParticles[i]);
}
}
// prune the tree...
recurseTreeWithOperation(pruneOperation, NULL);
}

View file

@ -21,14 +21,14 @@ class ParticleTree : public Octree {
Q_OBJECT
public:
ParticleTree(bool shouldReaverage = false);
/// Implements our type specific root element factory
virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL) const;
/// Type safe version of getRoot()
ParticleTreeElement* getRoot() { return (ParticleTreeElement*)_rootNode; }
// These methods will allow the OctreeServer to send your tree inbound edit packets of your
// own definition. Implement these to allow your octree based server to support editing
virtual bool getWantSVOfileVersions() const { return true; }
@ -37,11 +37,11 @@ public:
virtual int processEditPacketData(PACKET_TYPE packetType, unsigned char* packetData, int packetLength,
unsigned char* editData, int maxLength, Node* senderNode);
virtual void update();
virtual void update();
void storeParticle(const Particle& particle, Node* senderNode = NULL);
const Particle* findClosestParticle(glm::vec3 position, float targetRadius);
const Particle* findParticleByID(uint32_t id);
const Particle* findParticleByID(uint32_t id, bool alreadyLocked = false);
void addNewlyCreatedHook(NewlyCreatedParticleHook* hook);
void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook);
@ -53,9 +53,9 @@ private:
static bool findNearPointOperation(OctreeElement* element, void* extraData);
static bool pruneOperation(OctreeElement* element, void* extraData);
static bool findByIDOperation(OctreeElement* element, void* extraData);
void notifyNewlyCreatedParticle(const Particle& newParticle, Node* senderNode);
QReadWriteLock _newlyCreatedHooksLock;
std::vector<NewlyCreatedParticleHook*> _newlyCreatedHooks;
};

View file

@ -10,53 +10,12 @@
void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails) {
getParticlePacketSender()->queueParticleEditMessages(packetType, 1, &particleDetails);
}
void ParticlesScriptingInterface::queueParticleMessage(PACKET_TYPE packetType,
ParticleID particleID, const ParticleProperties& properties) {
ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) {
qDebug() << "ParticlesScriptingInterface::queueParticleMessage()...";
// The application will keep track of creatorTokenID
uint32_t creatorTokenID = Particle::getNextCreatorTokenID();
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now,
position, radius, {color.red, color.green, color.blue }, velocity,
gravity, damping, lifetime, inHand, script, creatorTokenID };
// queue the packet
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail);
ParticleID id(NEW_PARTICLE, creatorTokenID, false);
return id;
}
void ParticlesScriptingInterface::editParticle(ParticleID particleID, glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) {
uint32_t actualID = particleID.id; // may not be valid... will check below..
// if we don't know the actual id, look it up
if (!particleID.isKnownID) {
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
// if we couldn't fine it, then bail without changing anything...
if (actualID == UNKNOWN_PARTICLE_ID) {
return; // no changes...
}
}
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
ParticleDetail editParticleDetail = { actualID , now,
position, radius, {color.red, color.green, color.blue }, velocity,
gravity, damping, lifetime, inHand, script, UNKNOWN_TOKEN };
// queue the packet
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail);
getParticlePacketSender()->queueParticleEditMessage(packetType, particleID, properties);
}
ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& properties) {
@ -64,53 +23,33 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr
// The application will keep track of creatorTokenID
uint32_t creatorTokenID = Particle::getNextCreatorTokenID();
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
xColor color = properties.getColor();
ParticleDetail addParticleDetail = { NEW_PARTICLE, now,
properties.getPosition(), properties.getRadius(),
{color.red, color.green, color.blue }, properties.getVelocity(),
properties.getGravity(), properties.getDamping(), properties.getLifetime(),
properties.getInHand(), properties.getScript(),
creatorTokenID };
ParticleID id(NEW_PARTICLE, creatorTokenID, false );
// queue the packet
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail);
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, id, properties);
ParticleID id(NEW_PARTICLE, creatorTokenID, false );
return id;
}
void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) {
uint32_t actualID = particleID.id; // may not be valid... will check below..
qDebug() << "ParticlesScriptingInterface::editParticle() id.id=" << particleID.id << " id.creatorTokenID=" << particleID.creatorTokenID;
// if we don't know the actual id, look it up
uint32_t actualID = particleID.id;
if (!particleID.isKnownID) {
actualID = Particle::getIDfromCreatorTokenID(particleID.creatorTokenID);
qDebug() << "ParticlesScriptingInterface::editParticle()... actualID: " << actualID;
// if we couldn't fine it, then bail without changing anything...
// hmmm... we kind of want to bail if someone attempts to edit an unknown
if (actualID == UNKNOWN_PARTICLE_ID) {
return; // no changes...
return; // bailing early
}
qDebug() << "ParticlesScriptingInterface::editParticle() actualID=" << actualID;
}
// setup a ParticleDetail struct with the data
uint64_t now = usecTimestampNow();
particleID.id = actualID;
particleID.isKnownID = true;
xColor color = properties.getColor();
ParticleDetail editParticleDetail = { actualID, now,
properties.getPosition(), properties.getRadius(),
{color.red, color.green, color.blue }, properties.getVelocity(),
properties.getGravity(), properties.getDamping(), properties.getLifetime(),
properties.getInHand(), properties.getScript(),
UNKNOWN_TOKEN };
// queue the packet
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, editParticleDetail);
queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, particleID, properties);
}

View file

@ -24,19 +24,12 @@ public:
virtual OctreeEditPacketSender* createPacketSender() { return new ParticleEditPacketSender(); }
public slots:
ParticleID addParticle(glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script);
void editParticle(ParticleID particleID, glm::vec3 position, float radius,
xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script);
ParticleID addParticle(const ParticleProperties& properties);
void editParticle(ParticleID particleID, const ParticleProperties& properties);
void deleteParticle(ParticleID particleID);
private:
void queueParticleMessage(PACKET_TYPE packetType, ParticleDetail& particleDetails);
void queueParticleMessage(PACKET_TYPE packetType, ParticleID particleID, const ParticleProperties& properties);
uint32_t _nextCreatorTokenID;
};