QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties) { return properties.copyToScriptValue(engine); }
bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) { // get the ids of all the zones (plus the global entity edit filter) that the position // lies within auto zoneIDs = getZonesByPosition(position); for (auto id : zoneIDs) { if (!itemID.isInvalidID() && id == itemID) { continue; } // get the filter pair, etc... _lock.lockForRead(); FilterData filterData = _filterDataMap.value(id); _lock.unlock(); if (filterData.valid()) { if (filterData.rejectAll) { return false; } // check to see if this filter wants to filter this message type if ((!filterData.wantsToFilterEdit && filterType == EntityTree::FilterType::Edit) || (!filterData.wantsToFilterPhysics && filterType == EntityTree::FilterType::Physics) || (!filterData.wantsToFilterDelete && filterType == EntityTree::FilterType::Delete) || (!filterData.wantsToFilterAdd && filterType == EntityTree::FilterType::Add)) { wasChanged = false; return true; // accept the message } auto oldProperties = propertiesIn.getDesiredProperties(); auto specifiedProperties = propertiesIn.getChangedProperties(); propertiesIn.setDesiredProperties(specifiedProperties); QScriptValue inputValues = propertiesIn.copyToScriptValue(filterData.engine, false, true, true); propertiesIn.setDesiredProperties(oldProperties); auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. QScriptValueList args; args << inputValues; args << filterType; // get the current properties for then entity and include them for the filter call if (existingEntity && filterData.wantsOriginalProperties) { auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties); QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); args << currentValues; } // get the zone properties if (filterData.wantsZoneProperties) { auto zoneEntity = _tree->findEntityByEntityItemID(id); if (zoneEntity) { auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties); QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); if (filterData.wantsZoneBoundingBox) { bool success = true; AABox aaBox = zoneEntity->getAABox(success); if (success) { QScriptValue boundingBox = filterData.engine->newObject(); QScriptValue bottomRightNear = vec3ToScriptValue(filterData.engine, aaBox.getCorner()); QScriptValue topFarLeft = vec3ToScriptValue(filterData.engine, aaBox.calcTopFarLeft()); QScriptValue center = vec3ToScriptValue(filterData.engine, aaBox.calcCenter()); QScriptValue boundingBoxDimensions = vec3ToScriptValue(filterData.engine, aaBox.getDimensions()); boundingBox.setProperty("brn", bottomRightNear); boundingBox.setProperty("tfl", topFarLeft); boundingBox.setProperty("center", center); boundingBox.setProperty("dimensions", boundingBoxDimensions); zoneValues.setProperty("boundingBox", boundingBox); } } // If this is an add or delete, or original properties weren't requested // there won't be original properties in the args, but zone properties need // to be the fourth parameter, so we need to pad the args accordingly int EXPECTED_ARGS = 3; if (args.length() < EXPECTED_ARGS) { args << QScriptValue(); } assert(args.length() == EXPECTED_ARGS); // we MUST have 3 args by now! args << zoneValues; } } QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args); if (filterData.uncaughtExceptions()) { return false; } if (result.isObject()) { // make propertiesIn reflect the changes, for next filter... propertiesIn.copyFromScriptValue(result, false); // and update propertiesOut too. TODO: this could be more efficient... propertiesOut.copyFromScriptValue(result, false); // Javascript objects are == only if they are the same object. To compare arbitrary values, we need to use JSON. auto out = QJsonValue::fromVariant(result.toVariant()); wasChanged |= (in != out); } else if (result.isBool()) { // if the filter returned false, then it's authoritative if (!result.toBool()) { return false; } // otherwise, assume it wants to pass all properties propertiesOut = propertiesIn; wasChanged = false; } else { return false; } } } // if we made it here, return true; }