Procedural Prefabs: Entity parenting fixes (#4669)

* Parent top level entities to container entity when creating prefab

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add to_json method to PythonProxyObject to allow serializing any AZ serialializable type

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Update scene_mesh_to_prefab.py to parent entities in a chain

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Remove redundant eval

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Improve error handling in ToJson

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>

* Add maybe_unused for commonRoot since it's not used

Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com>
monroegm-disable-blank-issue-2
amzn-mike 4 years ago committed by GitHub
parent d84bb6a72f
commit 969a55170e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -74,6 +74,7 @@ def update_manifest(scene):
source_filename_only = os.path.basename(clean_filename)
created_entities = []
previous_entity_id = azlmbr.entity.InvalidEntityId
# Loop every mesh node in the scene
for activeMeshIndex in range(len(mesh_name_list)):
@ -102,14 +103,33 @@ def update_manifest(scene):
# The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
# The assetHint will be converted to an AssetId later during prefab loading
json_update = json.dumps({
"Controller": { "Configuration": { "ModelAsset": {
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
});
"Controller": { "Configuration": { "ModelAsset": {
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
});
# Apply the JSON above to the component we created
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
if not result:
raise RuntimeError("UpdateComponentForEntity failed")
raise RuntimeError("UpdateComponentForEntity failed for Mesh component")
# Get the transform component
transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0")
# Set this entity to be a child of the last entity we created
# This is just an example of how to do parenting and isn't necessarily useful to parent everything like this
if previous_entity_id is not None:
transform_json = json.dumps({
"Parent Entity" : previous_entity_id.to_json()
});
# Apply the JSON update
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, transform_component, transform_json)
if not result:
raise RuntimeError("UpdateComponentForEntity failed for Transform component")
# Update the last entity id for next time
previous_entity_id = entity_id
# Keep track of the entity we set up, we'll add them all to the prefab we're creating later
created_entities.append(entity_id)
@ -147,6 +167,8 @@ def on_update_manifest(args):
except RuntimeError as err:
print (f'ERROR - {err}')
log_exception_traceback()
except:
log_exception_traceback()
global sceneJobHandler
sceneJobHandler = None

@ -6,11 +6,14 @@
*
*/
#include <API/ToolsApplicationAPI.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <Prefab/PrefabSystemComponentInterface.h>
#include <Prefab/PrefabSystemScriptingHandler.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/TransformBus.h>
#include <ToolsComponents/TransformComponent.h>
namespace AzToolsFramework::Prefab
{
@ -61,9 +64,29 @@ namespace AzToolsFramework::Prefab
entities.push_back(entity);
}
}
auto prefab = m_prefabSystemComponentInterface->CreatePrefab(entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)));
bool result = false;
[[maybe_unused]] AZ::EntityId commonRoot;
EntityList topLevelEntities;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(result, &AzToolsFramework::ToolsApplicationRequestBus::Events::FindCommonRootInactive,
entities, commonRoot, &topLevelEntities);
auto containerEntity = AZStd::make_unique<AZ::Entity>();
for (AZ::Entity* entity : topLevelEntities)
{
AzToolsFramework::Components::TransformComponent* transformComponent =
entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
if (transformComponent)
{
transformComponent->SetParent(containerEntity->GetId());
}
}
auto prefab = m_prefabSystemComponentInterface->CreatePrefab(
entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)), AZStd::move(containerEntity));
if (!prefab)
{
AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str());

@ -17,10 +17,16 @@
#include <Source/PythonSymbolsBus.h>
#include <pybind11/embed.h>
#include <pybind11/pybind11.h>
#include <pybind11/eval.h>
#include <AzCore/PlatformDef.h>
#include <AzCore/JSON/rapidjson.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/JsonSerializationSettings.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
namespace EditorPythonBindings
{
@ -571,6 +577,37 @@ namespace EditorPythonBindings
return false;
}
pybind11::object PythonProxyObject::ToJson()
{
rapidjson::Document document;
AZ::JsonSerializerSettings settings;
settings.m_keepDefaults = true;
auto resultCode =
AZ::JsonSerialization::Store(document, document.GetAllocator(), m_wrappedObject.m_address, nullptr, m_wrappedObject.m_typeId, settings);
if (resultCode.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
{
AZ_Error("PythonProxyObject", false, "Failed to serialize to json");
return pybind11::cast<pybind11::none>(Py_None);
}
AZStd::string jsonString;
AZ::Outcome<void, AZStd::string> outcome = AZ::JsonSerializationUtils::WriteJsonString(document, jsonString);
if (!outcome.IsSuccess())
{
AZ_Error("PythonProxyObject", false, "Failed to write json string: %s", outcome.GetError().c_str());
return pybind11::cast<pybind11::none>(Py_None);
}
jsonString.erase(AZStd::remove(jsonString.begin(), jsonString.end(), '\n'), jsonString.end());
auto pythonCode = AZStd::string::format(
R"PYTHON(exec("import json") or json.loads("""%s"""))PYTHON", jsonString.c_str());
return pybind11::eval(pythonCode.c_str());
}
bool PythonProxyObject::DoComparisonEvaluation(pybind11::object pythonOther, Comparison comparison)
{
bool invertLogic = false;
@ -912,6 +949,7 @@ namespace EditorPythonBindings
.def("set_property", &PythonProxyObject::SetPropertyValue)
.def("get_property", &PythonProxyObject::GetPropertyValue)
.def("invoke", &PythonProxyObject::Invoke)
.def("to_json", &PythonProxyObject::ToJson)
.def(Operator::s_isEqual, [](PythonProxyObject& self, pybind11::object rhs)
{
return self.DoEqualityEvaluation(rhs);

@ -58,6 +58,8 @@ namespace EditorPythonBindings
//! Performs an equality operation to compare this object with another object
bool DoEqualityEvaluation(pybind11::object pythonOther);
pybind11::object ToJson();
//! Perform a comparison of a Python operator
enum class Comparison
{

Loading…
Cancel
Save