diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3d8669eb4c..cdf917e73b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4178,8 +4178,12 @@ void Application::processDatagrams() { break; case PACKET_TYPE_PARTICLE_ADD_RESPONSE: - // look up our ParticleEditHanders.... + + // This will make sure our local ParticleEditHandle are handles correctly ParticleEditHandle::handleAddResponse(_incomingPacket, bytesReceived); + + // this will keep creatorTokenIDs to IDs mapped correctly + Particle::handleAddParticleResponse(_incomingPacket, bytesReceived); break; case PACKET_TYPE_PARTICLE_DATA: diff --git a/libraries/particles/src/Particle.cpp b/libraries/particles/src/Particle.cpp index 188c506006..dbf6fde300 100644 --- a/libraries/particles/src/Particle.cpp +++ b/libraries/particles/src/Particle.cpp @@ -27,6 +27,41 @@ uint32_t Particle::_nextID = 0; VoxelEditPacketSender* Particle::_voxelEditSender = NULL; ParticleEditPacketSender* Particle::_particleEditSender = NULL; +// for locally created particles +std::map Particle::_tokenIDsToIDs; +uint32_t Particle::_nextCreatorTokenID = 0; + +uint32_t Particle::getIDfromCreatorTokenID(uint32_t creatorTokenID) { + if (_tokenIDsToIDs.find(creatorTokenID) != _tokenIDsToIDs.end()) { + return _tokenIDsToIDs[creatorTokenID]; + } + return UNKNOWN_PARTICLE_ID; +} + +uint32_t Particle::getNextCreatorTokenID() { + uint32_t creatorTokenID = _nextCreatorTokenID; + _nextCreatorTokenID++; + return creatorTokenID; +} + +void Particle::handleAddParticleResponse(unsigned char* packetData , int packetLength) { + unsigned char* dataAt = packetData; + int numBytesPacketHeader = numBytesForPacketHeader(packetData); + dataAt += numBytesPacketHeader; + + uint32_t creatorTokenID; + memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID)); + dataAt += sizeof(creatorTokenID); + + uint32_t particleID; + memcpy(&particleID, dataAt, sizeof(particleID)); + dataAt += sizeof(particleID); + + // add our token to id mapping + _tokenIDsToIDs[creatorTokenID] = particleID; +} + + Particle::Particle(glm::vec3 position, float radius, rgbColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript, uint32_t id) { @@ -335,10 +370,11 @@ Particle Particle::fromEditPacket(unsigned char* data, int length, int& processe dataAt += scriptLength; processedBytes += scriptLength; - const bool wantDebugging = false; + const bool wantDebugging = true; if (wantDebugging) { - printf("Particle::fromEditPacket()...\n"); - printf(" Particle id in packet:%u\n", editID); + qDebug("Particle::fromEditPacket()..."); + qDebug(" Particle id in packet:%u", editID); + //qDebug() << " position: " << newParticle._position; newParticle.debugDump(); } @@ -660,7 +696,7 @@ void Particle::setProperties(const ParticleProperties& properties) { ParticleProperties::ParticleProperties() : _position(0), _color(), - _radius(0), + _radius(DEFAULT_RADIUS), _velocity(0), _gravity(DEFAULT_GRAVITY), _damping(DEFAULT_DAMPING), diff --git a/libraries/particles/src/Particle.h b/libraries/particles/src/Particle.h index d7be4f29b4..e52cfd90a5 100644 --- a/libraries/particles/src/Particle.h +++ b/libraries/particles/src/Particle.h @@ -28,6 +28,7 @@ class Particle; const uint32_t NEW_PARTICLE = 0xFFFFFFFF; const uint32_t UNKNOWN_TOKEN = 0xFFFFFFFF; +const uint32_t UNKNOWN_PARTICLE_ID = 0xFFFFFFFF; class ParticleDetail { public: @@ -47,12 +48,15 @@ public: const float DEFAULT_LIFETIME = 60.0f * 60.0f * 24.0f; // particles live for 1 day by default const float DEFAULT_DAMPING = 0.99f; +const float DEFAULT_RADIUS = 0.1f / TREE_SCALE; // really shouldn't be a default? const glm::vec3 DEFAULT_GRAVITY(0, (-9.8f / TREE_SCALE), 0); const QString DEFAULT_SCRIPT(""); const bool IN_HAND = true; // it's in a hand const bool NOT_IN_HAND = !IN_HAND; // it's not in a hand -/// Used in scripting to set/get the complete set of particle properties via JavaScript hashes/QScriptValues +/// A collection of properties of a particle used in the scripting API. Translates between the actual properties of a particle +/// and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete set of +/// particle properties via JavaScript hashes/QScriptValues class ParticleProperties { public: ParticleProperties(); @@ -102,7 +106,9 @@ QScriptValue ParticlePropertiesToScriptValue(QScriptEngine* engine, const Partic void ParticlePropertiesFromScriptValue(const QScriptValue &object, ParticleProperties& properties); -/// used in Particle JS API +/// Abstract ID for editing particles. Used in Particle JS API - When particles are created in the JS api, they are given a +/// local creatorTokenID, the actual id for the particle is not known until the server responds to the creator with the +/// correct mapping. This class works with the scripting API an allows the developer to edit particles they created. class ParticleID { public: ParticleID() : @@ -122,6 +128,7 @@ void ParticleIDfromScriptValue(const QScriptValue &object, ParticleID& propertie +/// Particle class - this is the actual particle class. class Particle { public: @@ -213,6 +220,11 @@ public: { _particleEditSender = senderInterface; } + // these methods allow you to create particles, and later edit them. + static uint32_t getIDfromCreatorTokenID(uint32_t creatorTokenID); + static uint32_t getNextCreatorTokenID(); + static void handleAddParticleResponse(unsigned char* packetData , int packetLength); + protected: static VoxelEditPacketSender* _voxelEditSender; static ParticleEditPacketSender* _particleEditSender; @@ -247,8 +259,14 @@ protected: // this doesn't go on the wire, we send it as lifetime uint64_t _created; + + // used by the static interfaces for creator token ids + static uint32_t _nextCreatorTokenID; + static std::map _tokenIDsToIDs; }; +/// Scriptable interface to a single Particle object. Used exclusively in the JavaScript API for interacting with single +/// Particles. class ParticleScriptObject : public QObject { Q_OBJECT public: diff --git a/libraries/particles/src/ParticleEditHandle.cpp b/libraries/particles/src/ParticleEditHandle.cpp index d3a8dd56be..80dcff7e85 100644 --- a/libraries/particles/src/ParticleEditHandle.cpp +++ b/libraries/particles/src/ParticleEditHandle.cpp @@ -17,20 +17,19 @@ uint32_t ParticleEditHandle::_nextCreatorTokenID = 0; ParticleEditHandle::ParticleEditHandle(ParticleEditPacketSender* packetSender, ParticleTree* localTree, uint32_t id) { if (id == NEW_PARTICLE) { - _creatorTokenID = _nextCreatorTokenID; - _nextCreatorTokenID++; + _creatorTokenID = Particle::getNextCreatorTokenID(); _id = NEW_PARTICLE; _isKnownID = false; _allHandles[_creatorTokenID] = this; } else { - _creatorTokenID = UNKNOWN_TOKEN; + _creatorTokenID = UNKNOWN_TOKEN; _id = id; _isKnownID = true; // don't add to _allHandles because we already know it... } _packetSender = packetSender; _localTree = localTree; - + } ParticleEditHandle::~ParticleEditHandle() { @@ -40,21 +39,21 @@ ParticleEditHandle::~ParticleEditHandle() { } } -void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, +void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, 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 }, + 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); - + // release them _packetSender->releaseQueuedMessages(); - + // if we have a local tree, also update it... if (_localTree) { // we can't really do this here, because if we create a particle locally, we'll get a ghost particle @@ -62,22 +61,22 @@ void ParticleEditHandle::createParticle(glm::vec3 position, float radius, xColor } } -bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, +bool ParticleEditHandle::updateParticle(glm::vec3 position, float radius, xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString updateScript) { if (!isKnownID()) { return false; // not allowed until we know the id } - + // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); ParticleDetail newParticleDetail = { _id, now, - position, radius, {color.red, color.green, color.blue }, + 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, &newParticleDetail); - + // release them _packetSender->releaseQueuedMessages(); @@ -87,7 +86,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; } @@ -95,7 +94,7 @@ void ParticleEditHandle::handleAddResponse(unsigned char* packetData , int packe unsigned char* dataAt = packetData; int numBytesPacketHeader = numBytesForPacketHeader(packetData); dataAt += numBytesPacketHeader; - + uint32_t creatorTokenID; memcpy(&creatorTokenID, dataAt, sizeof(creatorTokenID)); dataAt += sizeof(creatorTokenID); diff --git a/libraries/particles/src/ParticlesScriptingInterface.cpp b/libraries/particles/src/ParticlesScriptingInterface.cpp index 7466370df8..7828a9d4a7 100644 --- a/libraries/particles/src/ParticlesScriptingInterface.cpp +++ b/libraries/particles/src/ParticlesScriptingInterface.cpp @@ -18,8 +18,7 @@ ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float ra xColor color, glm::vec3 velocity, glm::vec3 gravity, float damping, float lifetime, bool inHand, QString script) { // The application will keep track of creatorTokenID - uint32_t creatorTokenID = _nextCreatorTokenID; - _nextCreatorTokenID++; + uint32_t creatorTokenID = Particle::getNextCreatorTokenID(); // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); @@ -30,7 +29,7 @@ ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float ra // queue the packet queueParticleMessage(PACKET_TYPE_PARTICLE_ADD_OR_EDIT, addParticleDetail); - ParticleID id(NEW_PARTICLE, creatorTokenID, false ); + ParticleID id(NEW_PARTICLE, creatorTokenID, false); return id; } @@ -38,9 +37,21 @@ ParticleID ParticlesScriptingInterface::addParticle(glm::vec3 position, float ra 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 = { particleID.id , now, + ParticleDetail editParticleDetail = { actualID , now, position, radius, {color.red, color.green, color.blue }, velocity, gravity, damping, lifetime, inHand, script, UNKNOWN_TOKEN }; @@ -49,9 +60,9 @@ void ParticlesScriptingInterface::editParticle(ParticleID particleID, glm::vec3 } ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& properties) { + // The application will keep track of creatorTokenID - uint32_t creatorTokenID = _nextCreatorTokenID; - _nextCreatorTokenID++; + uint32_t creatorTokenID = Particle::getNextCreatorTokenID(); // setup a ParticleDetail struct with the data uint64_t now = usecTimestampNow(); @@ -71,18 +82,26 @@ ParticleID ParticlesScriptingInterface::addParticle(const ParticleProperties& pr } void ParticlesScriptingInterface::editParticle(ParticleID particleID, const ParticleProperties& properties) { - // expected behavior... - // - // if !particleID.isKnownID - // try to lookup the particle - // do nothing + 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); + + qDebug() << "ParticlesScriptingInterface::editParticle()... actualID: " << actualID; + + // 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(); xColor color = properties.getColor(); - ParticleDetail editParticleDetail = { particleID.id, now, + ParticleDetail editParticleDetail = { actualID, now, properties.getPosition(), properties.getRadius(), {color.red, color.green, color.blue }, properties.getVelocity(), properties.getGravity(), properties.getDamping(), properties.getLifetime(),