diff --git a/src/esp/metadata/CMakeLists.txt b/src/esp/metadata/CMakeLists.txt index 7e768099d0..4f797c36f1 100644 --- a/src/esp/metadata/CMakeLists.txt +++ b/src/esp/metadata/CMakeLists.txt @@ -31,6 +31,8 @@ set( attributes/SemanticAttributes.cpp attributes/StageAttributes.h attributes/StageAttributes.cpp + diagnostics/DatasetDiagnosticsTool.h + diagnostics/DatasetDiagnosticsTool.cpp managers/AbstractAttributesManager.h managers/AbstractObjectAttributesManager.h managers/AOAttributesManager.h diff --git a/src/esp/metadata/diagnostics/DatasetDiagnosticsTool.cpp b/src/esp/metadata/diagnostics/DatasetDiagnosticsTool.cpp new file mode 100644 index 0000000000..2df59221c7 --- /dev/null +++ b/src/esp/metadata/diagnostics/DatasetDiagnosticsTool.cpp @@ -0,0 +1,79 @@ + +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "DatasetDiagnosticsTool.h" +#include "esp/core/Check.h" + +namespace esp { +namespace metadata { +namespace diagnostics { + +const std::map DSDiagnosticTypeMap = { + {"savecorrected", DSDiagnosticType::SaveCorrected}, + {"sceneinstanceduplicates", DSDiagnosticType::TestForDuplicateInstances}, + {"semanticregionduplicates", DSDiagnosticType::TestForDuplicateRegions}, + // Future diagnostics should be listed here, before "all" + {"all", DSDiagnosticType::AllDiagnostics}, + {"allsavecorrected", DSDiagnosticType::AllDiagnosticsSaveCorrected}, +}; + +bool DatasetDiagnosticsTool::setDiagnosticesFromJSON( + const io::JsonGenericValue& jsonObj, + const std::string& msgStr) { + if (jsonObj.IsString()) { + // Single diagnostic string specified. + return setNamedDiagnostic(jsonObj.GetString(), true, true); + } + if (jsonObj.IsArray()) { + bool success = false; + for (rapidjson::SizeType i = 0; i < jsonObj.Size(); ++i) { + if (jsonObj[i].IsString()) { + success = setNamedDiagnostic(jsonObj[i].GetString(), true, true); + } else { + ESP_ERROR(Mn::Debug::Flag::NoSpace) + << msgStr + << " configuration specifies `request_diagnostics` array with a " + "non-string element @idx " + << i << ". Skipping unknown element."; + } + } + return success; + } + // else json object support? tag->boolean map in json? + // Tag present but referneces neither a string nor an array + ESP_ERROR(Mn::Debug::Flag::NoSpace) + << msgStr + << " configuration specifies `request_diagnostics` but specification " + "is unable to be parsed, so diagnostics request is ignored."; + return false; +} // DatasetDiagnosticsTool::setDiagnosticesFromJSON + +bool DatasetDiagnosticsTool::setNamedDiagnostic(const std::string& diagnostic, + bool val, + bool abortOnFail) { + const std::string diagnosticLC = Cr::Utility::String::lowercase(diagnostic); + + auto mapIter = DSDiagnosticTypeMap.find(diagnosticLC); + if (abortOnFail) { + // If not found then abort. + ESP_CHECK(mapIter != DSDiagnosticTypeMap.end(), + "Unknown Diagnostic Test requested to be " + << (val ? "Enabled" : "Disabled") << " :" << diagnostic + << ". Aborting."); + } else { + if (mapIter == DSDiagnosticTypeMap.end()) { + ESP_ERROR() << "Unknown Diagnostic Test requested to be " + << (val ? "Enabled" : "Disabled") << " :" << diagnostic + << " so ignoring request."; + return false; + } + } + setFlags(mapIter->second, val); + return true; +} // DatasetDiagnosticsTool::setNamedDiagnostic + +} // namespace diagnostics +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/diagnostics/DatasetDiagnosticsTool.h b/src/esp/metadata/diagnostics/DatasetDiagnosticsTool.h new file mode 100644 index 0000000000..4d17f7c64a --- /dev/null +++ b/src/esp/metadata/diagnostics/DatasetDiagnosticsTool.h @@ -0,0 +1,288 @@ + +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_DIAGNOSTICS_DATASETDIAGNOSTICSTOOL_H_ +#define ESP_METADATA_DIAGNOSTICS_DATASETDIAGNOSTICSTOOL_H_ + +#include "esp/core/Esp.h" +#include "esp/io/Json.h" +#include "esp/metadata/attributes/AbstractAttributes.h" + +namespace esp { +namespace metadata { +namespace diagnostics { + +/** + * @brief This enum class defines the various dataset diagnostics and remedies + * that Habitat-Sim can accept and process. These flags will be specified in + * config files and consumed by the config's manager. + */ +enum class DSDiagnosticType : uint32_t { + /** + * @brief Save any dataset configurations that fail a requested diagnostic + * and are consequently corrected. Ignored if no diagnostics are specified. If + * diagnostics are specified but this flag is not set then the corrections + * will only persist during current execution. + */ + SaveCorrected = 1U, + + /** + * @brief Test each @ref SceneInstanceAttributes file as it is loaded for + * duplicate rigid and articulated object instances. Duplicates will have all + * non-hidden fields equal. This would result in 2 identical objects being + * instantiated in the same location with the same initial state. + */ + TestForDuplicateInstances = (1U << 1), + + /** + * @brief Test each @ref SemanticAttributes file as it is loaded for + * duplicate region instances. Duplicates will have all non-hidden fields + * equal. This would result in multiple semantic regions being defined for the + * same area in the scene. + */ + TestForDuplicateRegions = (1U << 2), + + /** + * @brief Shortcut to perform all diagnostics but do not save corrected + * results. + */ + AllDiagnostics = ~SaveCorrected, + + /** + * @brief Shortcut to perform all diagnostics and save corrected results. + */ + AllDiagnosticsSaveCorrected = ~0U +}; + +/** + * @brief Construct to record the results of a series of diagnostics against a + * single attributes. + */ +template +class DSDiagnosticRecord { + public: + static_assert( + std::is_base_of::value, + "AbstractManagedPhysicsObject :: Managed physics object type must be " + "derived from esp::physics::PhysicsObjectBase"); + + typedef std::weak_ptr WeakObjRef; + + explicit DSDiagnosticRecord(uint32_t diagnosticsFlags) + : _diagnosticsFlags(diagnosticsFlags) {} + + /** + * @brief set the reference to this diagnostic record's subject + */ + void setObjectRef(const std::shared_ptr& objRef) { weakObjRef_ = objRef; } + + inline void setFlags(DSDiagnosticType _flag, bool _val) { + if (_val) { + _diagnosticsFlags |= static_cast(_flag); + } else { + _diagnosticsFlags &= ~static_cast(_flag); + } + } + + inline bool getFlags(DSDiagnosticType _flag) const { + return (_diagnosticsFlags & static_cast(_flag)) == + static_cast(_flag); + } + + protected: + /** + * @brief This function accesses the underlying shared pointer of this + * object's @p weakObjRef_ if it exists; if not, it provides a message. + * @return Either a shared pointer of this record's object, or nullptr if + * dne. + */ + std::shared_ptr inline getObjectReference() const { + std::shared_ptr sp = weakObjRef_.lock(); + if (!sp) { + ESP_ERROR() + << "This attributes no longer exists. Please delete any variable " + "references."; + } + return sp; + } // getObjectReference + + // Non-owning reference to attributes this record pertains to. + WeakObjRef weakObjRef_; + + private: + uint32_t _diagnosticsFlags = 0u; + + public: + ESP_SMART_POINTERS(DSDiagnosticRecord) + +}; // struct DSDiagnosticRecord + +/** + * @brief Constant map to provide mappings from string tags to @ref + * DSDiagnosticType values. This will be used to match values set + * in json for requested dataset diagnostics to @ref DSDiagnosticType values. + */ +const extern std::map DSDiagnosticTypeMap; + +/** + * @brief This class will track requested diagnostics for specific config + * files/attributes. It is intended that each @ref AbstractAttributesManager + * would instantiate one of these objects and use it to determine various + * diagnostic behavior. + */ +class DatasetDiagnosticsTool { + public: + DatasetDiagnosticsTool() = default; + + /** + * @brief Set diagnostic values based on specifications in passed @p jsonObj. + * @param jsonObj The json object referenced by the appropriate diagnostics + * tag. + * @param msgStr A string containing the type of manager and the name of the + * attributes/config responsible for this call, for use in debug messages. + * @return Whether the diagnostic values were set successfully or not. + */ + bool setDiagnosticesFromJSON(const io::JsonGenericValue& jsonObj, + const std::string& msgStr); + + /** + * @brief Merge the passed @ref DatasetDiagnosticsTool's @p _diagnosticsFlag + * settings into this one's, preserving this one's diagnostic requests as + * well. + */ + void mergeDiagnosticsTool(const DatasetDiagnosticsTool& tool) { + _diagnosticsFlags |= tool._diagnosticsFlags; + } + + /** + * @brief Take a list of string tags that are defined as keys in + * @ref DSDiagnosticTypeMap and set their corresponding flag values to true. + * @param keyMappings A list of diagnostics to enable. + * @param abortOnFail Whether or not to abort the program if a diagnostic + * string in + * @p keyMappings is unable to be mapped (not found in DSDiagnosticType). + * Otherwise the erroneous value will produce an error message but otherwise + * will be ignored. + */ + void enableDiagnostics(const std::vector& keyMappings, + bool abortOnFail) { + for (const auto& key : keyMappings) { + setNamedDiagnostic(key, true, abortOnFail); + } + } // enableDiagnostics + + /** + * @brief Enable/disable the diagnostic given by @p diagnostic based on + * @p val. + * + * @param diagnostic The string name of the diagnostic. This must be mappable + * to a @ref DSDiagnosticType via @p DSDiagnosticTypeMap . + * @param val Whether to enable or disable the given diagnostic + * @param abortOnFail Whether or not to abort the program if the + * @p diagnostic requeseted is not found in @ref DSDiagnosticType. If false, + * will print an error message and skip the unknown request. + * @return Whether the passed string successfully mapped to a known diagnostic + */ + bool setNamedDiagnostic(const std::string& diagnostic, + bool val, + bool abortOnFail = false); + + /** + * @brief Specify whether or not we should save any corrected dataset + * components if they received correction + */ + void setShouldSaveCorrected(bool val) { + setFlags(DSDiagnosticType::SaveCorrected, val); + } + /** + * @brief Query whether or not we should save any corrected dataset components + * if they received correction + */ + bool shouldSaveCorrected() const { + return getFlags(DSDiagnosticType::SaveCorrected); + } + + /** + * @brief Set that a save is required. This is to bridge from reading the json + * file into the attributes and registering the attributes to the + * post-registration code. + */ + void setSaveRequired(bool saveRequired) { + _requiresCorrectedSave = saveRequired; + } + + /** + * @brief Clear any flags set due to specific diagnostics + */ + void clearSaveRequired() { _requiresCorrectedSave = false; } + + /** + * @brief Get whether a save is required. This is to bridge from reading the + * json file into the attributes and registering the attributes to the + * post-registration code. + */ + bool saveRequired() const { return _requiresCorrectedSave; } + + /** + * @brief Specify whether or not to test for duplicate scene object instances + * in loaded @ref SceneInstanceAttributes and not process the duplicates if found. + */ + void setTestDuplicateSceneInstances(bool val) { + setFlags(DSDiagnosticType::TestForDuplicateInstances, val); + } + /** + * @brief Query whether or not to test for duplicate scene object instances + * in loaded @ref SceneInstanceAttributes and not process the duplicates if found. + */ + bool testDuplicateSceneInstances() const { + return getFlags(DSDiagnosticType::TestForDuplicateInstances); + } + + /** + * @brief Specify whether or not to test for duplicate semantic region + * specifications + * in loaded @ref SemanticAttributes and not process the duplicates if found. + */ + void setTestDuplicateSemanticRegions(bool val) { + setFlags(DSDiagnosticType::TestForDuplicateRegions, val); + } + /** + * @brief Query whether or not to test for duplicate semantic region + * specifications in loaded @ref SemanticAttributes and not process the duplicates if found. + */ + bool testDuplicateSemanticRegions() const { + return getFlags(DSDiagnosticType::TestForDuplicateRegions); + } + + private: + inline void setFlags(DSDiagnosticType _flag, bool _val) { + if (_val) { + _diagnosticsFlags |= static_cast(_flag); + } else { + _diagnosticsFlags &= ~static_cast(_flag); + } + } + + inline bool getFlags(DSDiagnosticType _flag) const { + return (_diagnosticsFlags & static_cast(_flag)) == + static_cast(_flag); + } + uint32_t _diagnosticsFlags = 0u; + + /** + * @brief Save the attributes current being processed. This flag is only so + */ + bool _requiresCorrectedSave = false; + + public: + ESP_SMART_POINTERS(DatasetDiagnosticsTool) + +}; // class DatasetDiagnosticsTool + +} // namespace diagnostics +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_DIAGNOSTICS_DATASETDIAGNOSTICSTOOL_H_ diff --git a/src/esp/metadata/managers/AOAttributesManager.cpp b/src/esp/metadata/managers/AOAttributesManager.cpp index 5b047ef636..e7dcb1c4e8 100644 --- a/src/esp/metadata/managers/AOAttributesManager.cpp +++ b/src/esp/metadata/managers/AOAttributesManager.cpp @@ -28,7 +28,7 @@ ArticulatedObjectAttributes::ptr AOAttributesManager::createObject( return attrs; } // AOAttributesManager::createObject -void AOAttributesManager::setValsFromJSONDoc( +void AOAttributesManager::setValsFromJSONDocInternal( ArticulatedObjectAttributes::ptr aoAttr, const io::JsonGenericValue& jsonConfig) { std::string urdf_filepath = ""; diff --git a/src/esp/metadata/managers/AOAttributesManager.h b/src/esp/metadata/managers/AOAttributesManager.h index b545718d75..2326924010 100644 --- a/src/esp/metadata/managers/AOAttributesManager.h +++ b/src/esp/metadata/managers/AOAttributesManager.h @@ -55,15 +55,6 @@ class AOAttributesManager const std::string& aoConfigFilename, bool registerTemplate = true) override; - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::ArticulatedObjectAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief This is to be deprecated. Provide a map of the articulated object * model filenames (.urdf) that have been referenced in the Scene Dataset via @@ -84,6 +75,16 @@ class AOAttributesManager const override; protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::ArticulatedObjectAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief Parse Marker_sets object in json, if present. * @param attribs (out) an existing attributes to be modified. @@ -156,19 +157,21 @@ class AOAttributesManager CORRADE_UNUSED bool) override; /** - * @brief Not required for this manager. - * - * This method will perform any final manager-related handling after - * successfully registering an object. + * @brief This method will perform any final manager-related handling after + * successfully registering an object, specifically saving the attributes back + * to file if it was found to be necessary due to user-specified diagnostics. * * See @ref esp::attributes::managers::ObjectAttributesManager for an example. * * @param objectID the ID of the successfully registered managed object * @param objectHandle The name of the managed object */ - void postRegisterObjectHandling( - CORRADE_UNUSED int objectID, - CORRADE_UNUSED const std::string& objectHandle) override {} + void postRegisterObjectHandling(CORRADE_UNUSED int objectID, + const std::string& objectHandle) override { + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectHandle, true); + } + } /** * @brief Any articulated-object-attributes-specific resetting that needs to diff --git a/src/esp/metadata/managers/AbstractAttributesManager.h b/src/esp/metadata/managers/AbstractAttributesManager.h index 2ecd33b76f..43f9f1cf5d 100644 --- a/src/esp/metadata/managers/AbstractAttributesManager.h +++ b/src/esp/metadata/managers/AbstractAttributesManager.h @@ -10,6 +10,7 @@ */ #include "esp/metadata/attributes/AbstractAttributes.h" +#include "esp/metadata/diagnostics/DatasetDiagnosticsTool.h" #include "esp/core/managedContainers/ManagedFileBasedContainer.h" #include "esp/io/Io.h" @@ -30,6 +31,7 @@ namespace managers { using core::config::Configuration; using core::managedContainers::ManagedFileBasedContainer; using core::managedContainers::ManagedObjectAccess; +using diagnostics::DatasetDiagnosticsTool; /** * @brief Class template defining responsibilities and functionality for @@ -64,7 +66,8 @@ class AbstractAttributesManager : public ManagedFileBasedContainer { const std::string& JSONTypeExt) : ManagedFileBasedContainer::ManagedFileBasedContainer( attrType, - JSONTypeExt) {} + JSONTypeExt), + datasetDiagnostics_(DatasetDiagnosticsTool::create_unique()) {} ~AbstractAttributesManager() override = default; /** @@ -180,12 +183,52 @@ class AbstractAttributesManager : public ManagedFileBasedContainer { /** * @brief Method to take an existing attributes and set its values from passed - * json config file. + * json config file. The JSON functionality is encapsulated with diagnostic + * preparation and reporting. * @param attribs (out) an existing attributes to be modified. * @param jsonConfig json document to parse */ - virtual void setValsFromJSONDoc(AttribsPtr attribs, - const io::JsonGenericValue& jsonConfig) = 0; + + void setValsFromJSONDoc(AttribsPtr attribs, + const io::JsonGenericValue& jsonConfig) { + // Clear diagnostic flags from previous run + this->datasetDiagnostics_->clearSaveRequired(); + this->setValsFromJSONDocInternal(attribs, jsonConfig); + if (this->datasetDiagnostics_->saveRequired()) { + ESP_WARNING(Mn::Debug::Flag::NoSpace) + << "<" << this->objectType_ + << "> : Diagnostics exposed issues in loaded attributes : `" + << attribs->getSimplifiedHandle() + << "` and the user has requested that the corrected attributes will " + "be saved."; + } + } // setValsFromJSONDoc + + /** + * @brief Configure @ref datasetDiagnostics_ tool based on if passsed jsonConfig + * requests them. + */ + bool setDSDiagnostics(AttribsPtr attribs, + const io::JsonGenericValue& jsonConfig) { + io::JsonGenericValue::ConstMemberIterator jsonIter = + jsonConfig.FindMember("request_diagnostics"); + if (jsonIter == jsonConfig.MemberEnd()) { + return false; + } + return this->datasetDiagnostics_->setDiagnosticesFromJSON( + jsonIter->value, Cr::Utility::formatString( + "(setDSDiagnostics) <{}> : {}", this->objectType_, + attribs->getSimplifiedHandle())); + } // setDSDiagnostics + + /** + * @brief Merge the passed DatasetDiagnosticsTool settings into + * @p datasetDiagnostics_ nondestructively (i.e. retaining this one's enabled + * diagnostics) + */ + void mergeDSDiagnosticsTool(const DatasetDiagnosticsTool& _tool) { + this->datasetDiagnostics_->mergeDiagnosticsTool(_tool); + } /** * @brief This function takes the json block specifying user-defined values @@ -249,6 +292,16 @@ class AbstractAttributesManager : public ManagedFileBasedContainer { const AttribsPtr& attributes) const = 0; protected: + /** + * @brief Internally called only. Method to take an existing attributes and + * set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + virtual void setValsFromJSONDocInternal( + AttribsPtr attribs, + const io::JsonGenericValue& jsonConfig) = 0; + /** * @brief Called internally right before attribute registration. Filepaths * in the json configs for Habitat SceneDatasets are specified relative to @@ -396,6 +449,12 @@ class AbstractAttributesManager : public ManagedFileBasedContainer { const std::string& srcAssetHandle, const std::function& handleSetter); + /** + * @brief Diagnostics tool that governs whether certain diagnostic operations + * should occur. + */ + DatasetDiagnosticsTool::uptr datasetDiagnostics_; + public: ESP_SMART_POINTERS(AbstractAttributesManager) diff --git a/src/esp/metadata/managers/AssetAttributesManager.cpp b/src/esp/metadata/managers/AssetAttributesManager.cpp index 0302915ef4..7377b1f8a5 100644 --- a/src/esp/metadata/managers/AssetAttributesManager.cpp +++ b/src/esp/metadata/managers/AssetAttributesManager.cpp @@ -249,7 +249,7 @@ AbstractPrimitiveAttributes::ptr AssetAttributesManager::buildObjectFromJSONDoc( return primAssetAttributes; } // AssetAttributesManager::buildObjectFromJSONDoc -void AssetAttributesManager::setValsFromJSONDoc( +void AssetAttributesManager::setValsFromJSONDocInternal( AttribsPtr attribs, const io::JsonGenericValue& jsonConfig) { // TODO support loading values from JSON docs diff --git a/src/esp/metadata/managers/AssetAttributesManager.h b/src/esp/metadata/managers/AssetAttributesManager.h index 75bd106828..8e86d0539f 100644 --- a/src/esp/metadata/managers/AssetAttributesManager.h +++ b/src/esp/metadata/managers/AssetAttributesManager.h @@ -137,15 +137,6 @@ class AssetAttributesManager CORRADE_UNUSED const attributes::AbstractPrimitiveAttributes::ptr& attributes) const override {} - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(AttribsPtr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief Creates a template based on the provided template handle. Since the * primitive asset attributes templates encode their structure in their @@ -455,6 +446,16 @@ class AssetAttributesManager } protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + AttribsPtr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief This method will perform any necessary updating that is * AbstractAttributesManager-specific upon template removal, such as removing diff --git a/src/esp/metadata/managers/LightLayoutAttributesManager.cpp b/src/esp/metadata/managers/LightLayoutAttributesManager.cpp index 0240274d5f..270db022f8 100644 --- a/src/esp/metadata/managers/LightLayoutAttributesManager.cpp +++ b/src/esp/metadata/managers/LightLayoutAttributesManager.cpp @@ -42,7 +42,7 @@ LightLayoutAttributes::ptr LightLayoutAttributesManager::createObject( return attrs; } // PhysicsAttributesManager::createObject -void LightLayoutAttributesManager::setValsFromJSONDoc( +void LightLayoutAttributesManager::setValsFromJSONDocInternal( attributes::LightLayoutAttributes::ptr lightAttribs, const io::JsonGenericValue& jsonConfig) { const std::string layoutNameAndPath = lightAttribs->getHandle(); diff --git a/src/esp/metadata/managers/LightLayoutAttributesManager.h b/src/esp/metadata/managers/LightLayoutAttributesManager.h index ef3ca652ff..2f070483fa 100644 --- a/src/esp/metadata/managers/LightLayoutAttributesManager.h +++ b/src/esp/metadata/managers/LightLayoutAttributesManager.h @@ -52,15 +52,6 @@ class LightLayoutAttributesManager const std::string& lightConfigName, bool registerTemplate = false) override; - /** - * @brief Function to take an existing LightLayoutAttributes and set its - * values from passed json config file. - * @param lightAttribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::LightLayoutAttributes::ptr lightAttribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief Function to take an existing LightInstanceAttributes and set its * values from passed json config file @@ -95,6 +86,16 @@ class LightLayoutAttributesManager const override {} protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing LightLayoutAttributes and set its values from passed json + * config file. + * @param lightAttribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::LightLayoutAttributes::ptr lightAttribs, + const io::JsonGenericValue& jsonConfig) override; /** * @brief Used Internally. Create and configure newly-created attributes * with any default values, before any specific values are set. @@ -147,19 +148,21 @@ class LightLayoutAttributesManager } /** - * @brief Not required for this manager. - * - * This method will perform any final manager-related handling after - * successfully registering an object. + * @brief This method will perform any final manager-related handling after + * successfully registering an object, specifically saving the attributes back + * to file if it was found to be necessary due to user-specified diagnostics. * * See @ref esp::attributes::managers::ObjectAttributesManager for an example. * * @param objectID the ID of the successfully registered managed object * @param objectHandle The name of the managed object */ - void postRegisterObjectHandling( - CORRADE_UNUSED int objectID, - CORRADE_UNUSED const std::string& objectHandle) override {} + void postRegisterObjectHandling(CORRADE_UNUSED int objectID, + const std::string& objectHandle) override { + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectHandle, true); + } + } /** * @brief Any lights-attributes-specific resetting that needs to happen on diff --git a/src/esp/metadata/managers/ObjectAttributesManager.cpp b/src/esp/metadata/managers/ObjectAttributesManager.cpp index fc374553bd..700592e5d2 100644 --- a/src/esp/metadata/managers/ObjectAttributesManager.cpp +++ b/src/esp/metadata/managers/ObjectAttributesManager.cpp @@ -71,7 +71,7 @@ void ObjectAttributesManager::createDefaultPrimBasedAttributesTemplates() { } } // ObjectAttributesManager::createDefaultPrimBasedAttributesTemplates -void ObjectAttributesManager::setValsFromJSONDoc( +void ObjectAttributesManager::setValsFromJSONDocInternal( attributes::ObjectAttributes::ptr objAttributes, const io::JsonGenericValue& jsonConfig) { this->setAbstractObjectAttributesFromJson(objAttributes, jsonConfig); @@ -362,6 +362,9 @@ void ObjectAttributesManager::postRegisterObjectHandling( if (mapToAddTo_ != nullptr) { mapToAddTo_->emplace(objectTemplateID, objectTemplateHandle); } + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectTemplateHandle, true); + } } // ObjectAttributesManager::postRegisterObjectHandling } // namespace managers diff --git a/src/esp/metadata/managers/ObjectAttributesManager.h b/src/esp/metadata/managers/ObjectAttributesManager.h index de49f52ee7..a857b63ce3 100644 --- a/src/esp/metadata/managers/ObjectAttributesManager.h +++ b/src/esp/metadata/managers/ObjectAttributesManager.h @@ -50,15 +50,6 @@ class ObjectAttributesManager const std::string& primAttrTemplateHandle, bool registerTemplate = true) override; - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::ObjectAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - // ======== File-based and primitive-based partition functions ======== /** @@ -158,6 +149,16 @@ class ObjectAttributesManager // ======== End File-based and primitive-based partition functions ======== protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::ObjectAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief Create and save default primitive asset-based object templates, * saving their handles as non-deletable default handles. diff --git a/src/esp/metadata/managers/PbrShaderAttributesManager.cpp b/src/esp/metadata/managers/PbrShaderAttributesManager.cpp index 8bbcf939ec..52b00db6d9 100644 --- a/src/esp/metadata/managers/PbrShaderAttributesManager.cpp +++ b/src/esp/metadata/managers/PbrShaderAttributesManager.cpp @@ -29,7 +29,7 @@ PbrShaderAttributes::ptr PbrShaderAttributesManager::createObject( return attrs; } // PbrShaderAttributesManager::createObject -void PbrShaderAttributesManager::setValsFromJSONDoc( +void PbrShaderAttributesManager::setValsFromJSONDocInternal( PbrShaderAttributes::ptr pbrShaderAttribs, const io::JsonGenericValue& jsonConfig) { //////////////////////////// diff --git a/src/esp/metadata/managers/PbrShaderAttributesManager.h b/src/esp/metadata/managers/PbrShaderAttributesManager.h index 2512bc8e2b..58403b30db 100644 --- a/src/esp/metadata/managers/PbrShaderAttributesManager.h +++ b/src/esp/metadata/managers/PbrShaderAttributesManager.h @@ -56,15 +56,6 @@ class PbrShaderAttributesManager ESP_DEFAULT_PBRSHADER_CONFIG_REL_PATH, bool registerTemplate = true) override; - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::PbrShaderAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief This will set all the @ref metadata::attributes::PbrShaderAttributes * to have IBL either on or off. @@ -115,6 +106,16 @@ class PbrShaderAttributesManager pbrShaderAttribs) const override; protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::PbrShaderAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief Used Internally. Create and configure newly-created attributes with * any default values, before any specific values are set. @@ -163,19 +164,21 @@ class PbrShaderAttributesManager CORRADE_UNUSED bool forceRegistration) override; /** - * @brief Not required for this manager. - * - * This method will perform any final manager-related handling after - * successfully registering an object. + * @brief This method will perform any final manager-related handling after + * successfully registering an object, specifically saving the attributes back + * to file if it was found to be necessary due to user-specified diagnostics. * * See @ref esp::attributes::managers::ObjectAttributesManager for an example. * * @param objectID the ID of the successfully registered managed object * @param objectHandle The name of the managed object */ - void postRegisterObjectHandling( - CORRADE_UNUSED int objectID, - CORRADE_UNUSED const std::string& objectHandle) override {} + void postRegisterObjectHandling(CORRADE_UNUSED int objectID, + const std::string& objectHandle) override { + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectHandle, true); + } + } /** * @brief Any physics-attributes-specific resetting that needs to happen on diff --git a/src/esp/metadata/managers/PhysicsAttributesManager.cpp b/src/esp/metadata/managers/PhysicsAttributesManager.cpp index 306c1ad979..3eef6de906 100644 --- a/src/esp/metadata/managers/PhysicsAttributesManager.cpp +++ b/src/esp/metadata/managers/PhysicsAttributesManager.cpp @@ -30,7 +30,7 @@ PhysicsManagerAttributes::ptr PhysicsAttributesManager::createObject( return attrs; } // PhysicsAttributesManager::createObject -void PhysicsAttributesManager::setValsFromJSONDoc( +void PhysicsAttributesManager::setValsFromJSONDocInternal( PhysicsManagerAttributes::ptr physicsManagerAttributes, const io::JsonGenericValue& jsonConfig) { // load the simulator preference - default is "none" diff --git a/src/esp/metadata/managers/PhysicsAttributesManager.h b/src/esp/metadata/managers/PhysicsAttributesManager.h index e418fcee84..336aa99d49 100644 --- a/src/esp/metadata/managers/PhysicsAttributesManager.h +++ b/src/esp/metadata/managers/PhysicsAttributesManager.h @@ -55,15 +55,6 @@ class PhysicsAttributesManager const std::string& physicsFilename = ESP_DEFAULT_PHYSICS_CONFIG_REL_PATH, bool registerTemplate = true) override; - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::PhysicsManagerAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief This function will be called to finalize attributes' paths before * registration, moving fully qualified paths to the appropriate hidden @@ -76,6 +67,16 @@ class PhysicsAttributesManager attributes) const override {} protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::PhysicsManagerAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief Used Internally. Create and configure newly-created attributes with * any default values, before any specific values are set. @@ -137,19 +138,21 @@ class PhysicsAttributesManager } /** - * @brief Not required for this manager. - * - * This method will perform any final manager-related handling after - * successfully registering an object. + * @brief This method will perform any final manager-related handling after + * successfully registering an object, specifically saving the attributes back + * to file if it was found to be necessary due to user-specified diagnostics. * * See @ref esp::attributes::managers::ObjectAttributesManager for an example. * * @param objectID the ID of the successfully registered managed object * @param objectHandle The name of the managed object */ - void postRegisterObjectHandling( - CORRADE_UNUSED int objectID, - CORRADE_UNUSED const std::string& objectHandle) override {} + void postRegisterObjectHandling(CORRADE_UNUSED int objectID, + const std::string& objectHandle) override { + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectHandle, true); + } + } /** * @brief Any physics-attributes-specific resetting that needs to happen on diff --git a/src/esp/metadata/managers/SceneDatasetAttributesManager.cpp b/src/esp/metadata/managers/SceneDatasetAttributesManager.cpp index 5d2932804c..3ea2c3e50b 100644 --- a/src/esp/metadata/managers/SceneDatasetAttributesManager.cpp +++ b/src/esp/metadata/managers/SceneDatasetAttributesManager.cpp @@ -66,9 +66,12 @@ SceneDatasetAttributesManager::initNewObjectInternal( return newAttributes; } // SceneDatasetAttributesManager::initNewObjectInternal -void SceneDatasetAttributesManager::setValsFromJSONDoc( +void SceneDatasetAttributesManager::setValsFromJSONDocInternal( attributes::SceneDatasetAttributes::ptr dsAttribs, const io::JsonGenericValue& jsonConfig) { + // check for diagnostics requests + this->setDSDiagnostics(dsAttribs, jsonConfig); + // dataset root directory to build paths from std::string dsDir = dsAttribs->getFileDirectory(); // process stages @@ -138,6 +141,9 @@ void SceneDatasetAttributesManager::readDatasetJSONCell( const io::JsonGenericValue& jsonConfig, const U& attrMgr, std::map* strKeyMap) { + // merge DatasetDiagnostics tool from this manager into passed manager + attrMgr->mergeDSDiagnosticsTool(*(this->datasetDiagnostics_)); + io::JsonGenericValue::ConstMemberIterator jsonIter = jsonConfig.FindMember(tag); if (jsonIter != jsonConfig.MemberEnd()) { diff --git a/src/esp/metadata/managers/SceneDatasetAttributesManager.h b/src/esp/metadata/managers/SceneDatasetAttributesManager.h index d95ca497de..f1ff9727db 100644 --- a/src/esp/metadata/managers/SceneDatasetAttributesManager.h +++ b/src/esp/metadata/managers/SceneDatasetAttributesManager.h @@ -43,15 +43,6 @@ class SceneDatasetAttributesManager const std::string& attributesTemplateHandle, bool registerTemplate = true) override; - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::SceneDatasetAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief This will set the current physics manager attributes that is * governing the world that this SceneDatasetAttributesManager's datasets will @@ -109,6 +100,16 @@ class SceneDatasetAttributesManager const override {} protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::SceneDatasetAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief This will validate a loaded dataset map with file location values * from the dataset config, by attempting to either verify those diff --git a/src/esp/metadata/managers/SceneInstanceAttributesManager.cpp b/src/esp/metadata/managers/SceneInstanceAttributesManager.cpp index 0494f951eb..6205c890a3 100644 --- a/src/esp/metadata/managers/SceneInstanceAttributesManager.cpp +++ b/src/esp/metadata/managers/SceneInstanceAttributesManager.cpp @@ -67,7 +67,7 @@ SceneInstanceAttributesManager::initNewObjectInternal( return newAttributes; } // SceneInstanceAttributesManager::initNewObjectInternal -void SceneInstanceAttributesManager::setValsFromJSONDoc( +void SceneInstanceAttributesManager::setValsFromJSONDocInternal( SceneInstanceAttributes::ptr attribs, const io::JsonGenericValue& jsonConfig) { const std::string attribsDispName = attribs->getSimplifiedHandle(); @@ -111,8 +111,20 @@ void SceneInstanceAttributesManager::setValsFromJSONDoc( << "` so no Stage can be created for this Scene."); } } - // TODO : drive by diagnostics when implemented - bool validateUnique = false; + + // Set this via configuration value - should only be called when explicitly + // filtering dataset + // Whether uniqueness validation should be performed + bool validateUniqueness = + this->datasetDiagnostics_->testDuplicateSceneInstances(); + + // Only resave if instance attributes' attempt to be added reveals duplicate + // attributes + bool saveValidationResults = + validateUniqueness && this->datasetDiagnostics_->shouldSaveCorrected(); + + // Whether this scene instance should be resaved or not. + bool resaveAttributes = false; // Check for object instances existence io::JsonGenericValue::ConstMemberIterator objJSONIter = jsonConfig.FindMember("object_instances"); @@ -123,8 +135,11 @@ void SceneInstanceAttributesManager::setValsFromJSONDoc( for (rapidjson::SizeType i = 0; i < objectArray.Size(); ++i) { const auto& objCell = objectArray[i]; if (objCell.IsObject()) { - attribs->addObjectInstanceAttrs( - createInstanceAttributesFromJSON(objCell), validateUnique); + // Resave if attributes not added due to being already found in the + // subconfiguration + bool objWasAdded = attribs->addObjectInstanceAttrs( + createInstanceAttributesFromJSON(objCell), validateUniqueness); + resaveAttributes = !objWasAdded || resaveAttributes; } else { ESP_WARNING(Mn::Debug::Flag::NoSpace) << "Object instance issue in Scene Instance `" << attribsDispName @@ -134,9 +149,9 @@ void SceneInstanceAttributesManager::setValsFromJSONDoc( } } } else { - // object_instances tag exists but is not an array. should warn (perhaps - // error?) - ESP_WARNING(Mn::Debug::Flag::NoSpace) + // object_instances tag exists but is not an array; gives error message. + // (Perhaps should fail?) + ESP_ERROR(Mn::Debug::Flag::NoSpace) << "Object instances issue in Scene Instance `" << attribsDispName << "`: JSON cell `object_instances` is not a valid JSON " "array, so no object instances loaded."; @@ -161,8 +176,12 @@ void SceneInstanceAttributesManager::setValsFromJSONDoc( const auto& artObjCell = articulatedObjArray[i]; if (artObjCell.IsObject()) { - attribs->addArticulatedObjectInstanceAttrs( - createAOInstanceAttributesFromJSON(artObjCell), validateUnique); + // Resave if attributes not added due to being already found in the + // subconfiguration + bool artObjWasAdded = attribs->addArticulatedObjectInstanceAttrs( + createAOInstanceAttributesFromJSON(artObjCell), + validateUniqueness); + resaveAttributes = !artObjWasAdded || resaveAttributes; } else { ESP_WARNING(Mn::Debug::Flag::NoSpace) << "Articulated Object specification error in Scene Instance `" @@ -172,9 +191,9 @@ void SceneInstanceAttributesManager::setValsFromJSONDoc( } } } else { - // articulated_object_instances tag exists but is not an array. should - // warn (perhaps error?) - ESP_WARNING(Mn::Debug::Flag::NoSpace) + // articulated_object_instances tag exists but is not an array; gives + // error message. (Perhaps should fail?) + ESP_ERROR(Mn::Debug::Flag::NoSpace) << "Articulated Object instances issue in Scene " "InstanceScene Instance `" << attribsDispName @@ -284,6 +303,9 @@ void SceneInstanceAttributesManager::setValsFromJSONDoc( // check for user defined attributes this->parseUserDefinedJsonVals(attribs, jsonConfig); + // If we want to save corrected, and we need to due to corrections happening + this->datasetDiagnostics_->setSaveRequired(saveValidationResults && + resaveAttributes); } // SceneInstanceAttributesManager::setValsFromJSONDoc SceneObjectInstanceAttributes::ptr diff --git a/src/esp/metadata/managers/SceneInstanceAttributesManager.h b/src/esp/metadata/managers/SceneInstanceAttributesManager.h index 1cf0776b1d..06a5f3535b 100644 --- a/src/esp/metadata/managers/SceneInstanceAttributesManager.h +++ b/src/esp/metadata/managers/SceneInstanceAttributesManager.h @@ -56,15 +56,6 @@ class SceneInstanceAttributesManager defaultPbrShaderAttributesHandle_ = pbrHandle; } - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::SceneInstanceAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief This will return a @ref * attributes::SceneObjectInstanceAttributes object with passed handle. @@ -112,6 +103,16 @@ class SceneInstanceAttributesManager const override {} protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::SceneInstanceAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief Gets the name/key value of the appropriate enum corresponding to the * desired Translation Origin used to determine the location of the asset in @@ -219,19 +220,21 @@ class SceneInstanceAttributesManager } /** - * @brief Not required for this manager. - * - * This method will perform any final manager-related handling after - * successfully registering an object. + * @brief This method will perform any final manager-related handling after + * successfully registering an object, specifically saving the attributes back + * to file if it was found to be necessary due to user-specified diagnostics. * * See @ref esp::attributes::managers::ObjectAttributesManager for an example. * * @param objectID the ID of the successfully registered managed object * @param objectHandle The name of the managed object */ - void postRegisterObjectHandling( - CORRADE_UNUSED int objectID, - CORRADE_UNUSED const std::string& objectHandle) override {} + void postRegisterObjectHandling(CORRADE_UNUSED int objectID, + const std::string& objectHandle) override { + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectHandle, true); + } + } /** * @brief Name of the attributes used for the default Pbr/Ibl shader diff --git a/src/esp/metadata/managers/SemanticAttributesManager.cpp b/src/esp/metadata/managers/SemanticAttributesManager.cpp index 94a9690e1f..fab936eee0 100644 --- a/src/esp/metadata/managers/SemanticAttributesManager.cpp +++ b/src/esp/metadata/managers/SemanticAttributesManager.cpp @@ -136,7 +136,7 @@ SemanticAttributesManager::createRegionAttributesFromJSON( return regionAttrs; } // SemanticAttributesManager::createRegionAttributesFromJSON -void SemanticAttributesManager::setValsFromJSONDoc( +void SemanticAttributesManager::setValsFromJSONDocInternal( SemanticAttributes::ptr semanticAttribs, const io::JsonGenericValue& jsonConfig) { const std::string attribsDispName = semanticAttribs->getSimplifiedHandle(); @@ -199,6 +199,21 @@ void SemanticAttributesManager::setValsFromJSONDoc( // Check for region instances existence io::JsonGenericValue::ConstMemberIterator regionJSONIter = jsonConfig.FindMember("region_annotations"); + + // Set this via configuration value - should only be called when explicitly + // filtering dataset + // Whether uniqueness validation should be performed + bool validateUniqueness = + this->datasetDiagnostics_->testDuplicateSemanticRegions(); + + // Only resave if instance attributes' attempt to be added reveals duplicate + // attributes + bool saveValidationResults = + validateUniqueness && this->datasetDiagnostics_->shouldSaveCorrected(); + + // Whether this scene instance should be resaved or not. + bool resaveAttributes = false; + if (regionJSONIter != jsonConfig.MemberEnd()) { // region_annotations tag exists if (regionJSONIter->value.IsArray()) { @@ -206,8 +221,9 @@ void SemanticAttributesManager::setValsFromJSONDoc( for (rapidjson::SizeType i = 0; i < regionArray.Size(); ++i) { const auto& regionCell = regionArray[i]; if (regionCell.IsObject()) { - semanticAttribs->addRegionInstanceAttrs( - createRegionAttributesFromJSON(regionCell), validateUnique); + bool regionWasAdded = semanticAttribs->addRegionInstanceAttrs( + createRegionAttributesFromJSON(regionCell), validateUniqueness); + resaveAttributes = !regionWasAdded || resaveAttributes; } else { ESP_WARNING(Mn::Debug::Flag::NoSpace) << "Region instance issue in Semantic Configuration `" @@ -234,10 +250,13 @@ void SemanticAttributesManager::setValsFromJSONDoc( << "`: JSON cell with tag `region_annotations` does not exist in " "Semantic Configuration file."; } - // check for user defined attributes this->parseUserDefinedJsonVals(semanticAttribs, jsonConfig); + // If we want to save corrected, and we need to due to corrections happening + this->datasetDiagnostics_->setSaveRequired(saveValidationResults && + resaveAttributes); + } // SemanticAttributesManager::setValsFromJSONDoc core::managedContainers::ManagedObjectPreregistration diff --git a/src/esp/metadata/managers/SemanticAttributesManager.h b/src/esp/metadata/managers/SemanticAttributesManager.h index 76d3e9adf1..24120b326f 100644 --- a/src/esp/metadata/managers/SemanticAttributesManager.h +++ b/src/esp/metadata/managers/SemanticAttributesManager.h @@ -53,15 +53,6 @@ class SemanticAttributesManager const std::string& semanticConfigFilename, bool registerTemplate = true) override; - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::SemanticAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief This will return a @ref * attributes::SemanticVolumeAttributes object with passed handle. @@ -82,6 +73,16 @@ class SemanticAttributesManager const attributes::SemanticAttributes::ptr& attributes) const override; protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::SemanticAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief Used Internally. Create a @ref * esp::metadata::attributes::SemanticVolumeAttributes object from the @@ -152,19 +153,21 @@ class SemanticAttributesManager CORRADE_UNUSED bool forceRegistration) override; /** - * @brief Not required for this manager. - * - * This method will perform any final manager-related handling after - * successfully registering an object. + * @brief This method will perform any final manager-related handling after + * successfully registering an object, specifically saving the attributes back + * to file if it was found to be necessary due to user-specified diagnostics. * * See @ref esp::attributes::managers::ObjectAttributesManager for an example. * * @param objectID the ID of the successfully registered managed object * @param objectHandle The name of the managed object */ - void postRegisterObjectHandling( - CORRADE_UNUSED int objectID, - CORRADE_UNUSED const std::string& objectHandle) override {} + void postRegisterObjectHandling(CORRADE_UNUSED int objectID, + const std::string& objectHandle) override { + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectHandle, true); + } + } /** * @brief Any physics-attributes-specific resetting that needs to happen on diff --git a/src/esp/metadata/managers/StageAttributesManager.cpp b/src/esp/metadata/managers/StageAttributesManager.cpp index 5b611ffa2a..3139aceb4b 100644 --- a/src/esp/metadata/managers/StageAttributesManager.cpp +++ b/src/esp/metadata/managers/StageAttributesManager.cpp @@ -276,7 +276,7 @@ void StageAttributesManager::setDefaultAssetNameBasedAttributes( } } // StageAttributesManager::setDefaultAssetNameBasedAttributes -void StageAttributesManager::setValsFromJSONDoc( +void StageAttributesManager::setValsFromJSONDocInternal( attributes::StageAttributes::ptr stageAttributes, const io::JsonGenericValue& jsonConfig) { this->setAbstractObjectAttributesFromJson(stageAttributes, jsonConfig); diff --git a/src/esp/metadata/managers/StageAttributesManager.h b/src/esp/metadata/managers/StageAttributesManager.h index 032961e124..96fb4dbbd5 100644 --- a/src/esp/metadata/managers/StageAttributesManager.h +++ b/src/esp/metadata/managers/StageAttributesManager.h @@ -70,15 +70,6 @@ class StageAttributesManager const std::string& primAttrTemplateHandle, bool registerTemplate = true) override; - /** - * @brief Method to take an existing attributes and set its values from passed - * json config file. - * @param attribs (out) an existing attributes to be modified. - * @param jsonConfig json document to parse - */ - void setValsFromJSONDoc(attributes::StageAttributes::ptr attribs, - const io::JsonGenericValue& jsonConfig) override; - /** * @brief This function will be called to finalize attributes' paths before * registration, moving fully qualified paths to the appropriate hidden @@ -90,6 +81,16 @@ class StageAttributesManager const attributes::StageAttributes::ptr& attributes) const override; protected: + /** + * @brief Internally accessed from AbstractAttributesManager. Method to take + * an existing attributes and set its values from passed json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDocInternal( + attributes::StageAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + /** * @brief Create and save default primitive asset-based object templates, * saving their handles as non-deletable default handles. @@ -164,19 +165,21 @@ class StageAttributesManager bool forceRegistration) override; /** - * @brief Not required for this manager. - * - * This method will perform any final manager-related handling after - * successfully registering an object. + * @brief This method will perform any final manager-related handling after + * successfully registering an object, specifically saving the attributes back + * to file if it was found to be necessary due to user-specified diagnostics. * * See @ref esp::attributes::managers::ObjectAttributesManager for an example. * * @param objectID the ID of the successfully registered managed object * @param objectHandle The name of the managed object */ - void postRegisterObjectHandling( - CORRADE_UNUSED int objectID, - CORRADE_UNUSED const std::string& objectHandle) override {} + void postRegisterObjectHandling(CORRADE_UNUSED int objectID, + const std::string& objectHandle) override { + if (this->datasetDiagnostics_->saveRequired()) { + this->saveManagedObjectToFile(objectHandle, true); + } + } /** * @brief Any scene-attributes-specific resetting that needs to happen on