Merge branch 'development' into LYN-5265_state_tracker_impl
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiSystemComponent.h>
|
||||
#include <AzToolsFramework/Undo/UndoCacheInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <Entity/EntityUtilityComponent.h>
|
||||
|
||||
#include <QtWidgets/QMessageBox>
|
||||
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QFileInfo::d_ptr': class 'QSharedDataPointer<QFileInfoPrivate>' needs to have dll-interface to be used by clients of class 'QFileInfo'
|
||||
@@ -271,7 +272,8 @@ namespace AzToolsFramework
|
||||
azrtti_typeid<AzToolsFramework::EditorInteractionSystemComponent>(),
|
||||
azrtti_typeid<Components::EditorEntitySearchComponent>(),
|
||||
azrtti_typeid<Components::EditorIntersectorComponent>(),
|
||||
azrtti_typeid<AzToolsFramework::SliceRequestComponent>()
|
||||
azrtti_typeid<AzToolsFramework::SliceRequestComponent>(),
|
||||
azrtti_typeid<AzToolsFramework::EntityUtilityComponent>()
|
||||
});
|
||||
|
||||
return components;
|
||||
|
||||
@@ -410,7 +410,7 @@ namespace AzToolsFramework
|
||||
filter.append(ext);
|
||||
if (i < n - 1)
|
||||
{
|
||||
filter.append(", ");
|
||||
filter.append(" ");
|
||||
}
|
||||
}
|
||||
filter.append(")");
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerNullComponent.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserComponent.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h>
|
||||
#include <AzToolsFramework/Entity/EntityUtilityComponent.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(AzToolsFramework);
|
||||
|
||||
@@ -71,6 +72,7 @@ namespace AzToolsFramework
|
||||
Components::EditorSelectionAccentSystemComponent::CreateDescriptor(),
|
||||
EditorEntityContextComponent::CreateDescriptor(),
|
||||
EditorEntityFixupComponent::CreateDescriptor(),
|
||||
EntityUtilityComponent::CreateDescriptor(),
|
||||
ContainerEntitySystemComponent::CreateDescriptor(),
|
||||
FocusModeSystemComponent::CreateDescriptor(),
|
||||
SliceMetadataEntityContextComponent::CreateDescriptor(),
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include <AzCore/JSON/rapidjson.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerializationSettings.h>
|
||||
#include <AzCore/Serialization/Json/JsonUtils.h>
|
||||
#include <AzFramework/Entity/EntityContext.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
#include <AzToolsFramework/Entity/EntityUtilityComponent.h>
|
||||
#include <Entity/EditorEntityContextBus.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void ComponentDetails::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<ComponentDetails>()
|
||||
->Field("TypeInfo", &ComponentDetails::m_typeInfo)
|
||||
->Field("BaseClasses", &ComponentDetails::m_baseClasses);
|
||||
|
||||
serializeContext->RegisterGenericType<AZStd::vector<ComponentDetails>>();
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<ComponentDetails>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "entity")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Property("TypeInfo", BehaviorValueProperty(&ComponentDetails::m_typeInfo))
|
||||
->Property("BaseClasses", BehaviorValueProperty(&ComponentDetails::m_baseClasses))
|
||||
->Method("__repr__", [](const ComponentDetails& obj)
|
||||
{
|
||||
std::ostringstream result;
|
||||
bool first = true;
|
||||
|
||||
for (const auto& baseClass : obj.m_baseClasses)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
result << ", ";
|
||||
}
|
||||
|
||||
first = false;
|
||||
result << baseClass.c_str();
|
||||
}
|
||||
|
||||
return AZStd::string::format("%s, Base Classes: <%s>", obj.m_typeInfo.c_str(), result.str().c_str());
|
||||
})
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::EntityId EntityUtilityComponent::CreateEditorReadyEntity(const AZStd::string& entityName)
|
||||
{
|
||||
auto* newEntity = m_entityContext->CreateEntity(entityName.c_str());
|
||||
|
||||
if (!newEntity)
|
||||
{
|
||||
AZ_Error("EditorEntityUtility", false, "Failed to create new entity %s", entityName.c_str());
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorEntityContextRequestBus::Events::AddRequiredComponents, *newEntity);
|
||||
|
||||
newEntity->Init();
|
||||
auto newEntityId = newEntity->GetId();
|
||||
|
||||
m_createdEntities.emplace_back(newEntityId);
|
||||
|
||||
return newEntityId;
|
||||
}
|
||||
|
||||
AZ::TypeId GetComponentTypeIdFromName(const AZStd::string& typeName)
|
||||
{
|
||||
// Try to create a TypeId first. We won't show any warnings if this fails as the input might be a class name instead
|
||||
AZ::TypeId typeId = AZ::TypeId::CreateStringPermissive(typeName.data());
|
||||
|
||||
// If the typeId is null, try a lookup by class name
|
||||
if (typeId.IsNull())
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
|
||||
auto typeNameCrc = AZ::Crc32(typeName.data());
|
||||
auto typeUuidList = serializeContext->FindClassId(typeNameCrc);
|
||||
|
||||
// TypeId is invalid or class name is invalid
|
||||
if (typeUuidList.empty())
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Provided type %s is either an invalid TypeId or does not match any class names", typeName.c_str());
|
||||
return AZ::TypeId::CreateNull();
|
||||
}
|
||||
|
||||
typeId = typeUuidList[0];
|
||||
}
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
AZ::Component* FindComponentHelper(AZ::EntityId entityId, const AZ::TypeId& typeId, AZ::ComponentId componentId, bool createComponent = false)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
|
||||
|
||||
if (!entity)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Invalid entityId %s", entityId.ToString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AZ::Component* component = nullptr;
|
||||
if (componentId != AZ::InvalidComponentId)
|
||||
{
|
||||
component = entity->FindComponent(componentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
component = entity->FindComponent(typeId);
|
||||
}
|
||||
|
||||
if (!component && createComponent)
|
||||
{
|
||||
component = entity->CreateComponent(typeId);
|
||||
}
|
||||
|
||||
if (!component)
|
||||
{
|
||||
AZ_Error(
|
||||
"EntityUtilityComponent", false, "Failed to find component (%s) on entity %s (%s)",
|
||||
componentId != AZ::InvalidComponentId ? AZStd::to_string(componentId).c_str()
|
||||
: typeId.ToString<AZStd::string>().c_str(),
|
||||
entityId.ToString().c_str(),
|
||||
entity->GetName().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
AzFramework::BehaviorComponentId EntityUtilityComponent::GetOrAddComponentByTypeName(AZ::EntityId entityId, const AZStd::string& typeName)
|
||||
{
|
||||
AZ::TypeId typeId = GetComponentTypeIdFromName(typeName);
|
||||
|
||||
if (typeId.IsNull())
|
||||
{
|
||||
return AzFramework::BehaviorComponentId(AZ::InvalidComponentId);
|
||||
}
|
||||
|
||||
AZ::Component* component = FindComponentHelper(entityId, typeId, AZ::InvalidComponentId, true);
|
||||
|
||||
return component ? AzFramework::BehaviorComponentId(component->GetId()) :
|
||||
AzFramework::BehaviorComponentId(AZ::InvalidComponentId);
|
||||
}
|
||||
|
||||
bool EntityUtilityComponent::UpdateComponentForEntity(AZ::EntityId entityId, AzFramework::BehaviorComponentId componentId, const AZStd::string& json)
|
||||
{
|
||||
if (!componentId.IsValid())
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Invalid componentId passed to UpdateComponentForEntity");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Component* component = FindComponentHelper(entityId, AZ::TypeId::CreateNull(), componentId);
|
||||
|
||||
if (!component)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
AZ::JsonDeserializerSettings settings = AZ::JsonDeserializerSettings{};
|
||||
settings.m_reporting = []([[maybe_unused]] AZStd::string_view message, ResultCode result, AZStd::string_view) -> auto
|
||||
{
|
||||
if (result.GetProcessing() == Processing::Halted)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "JSON %s\n", message.data());
|
||||
}
|
||||
else if (result.GetOutcome() > Outcomes::PartialDefaults)
|
||||
{
|
||||
AZ_Warning("EntityUtilityComponent", false, "JSON %s\n", message.data());
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
rapidjson::Document doc;
|
||||
doc.Parse<rapidjson::kParseCommentsFlag>(json.data(), json.size());
|
||||
ResultCode resultCode = AZ::JsonSerialization::Load(*component, doc, settings);
|
||||
|
||||
return resultCode.GetProcessing() != Processing::Halted;
|
||||
}
|
||||
|
||||
AZStd::string EntityUtilityComponent::GetComponentDefaultJson(const AZStd::string& typeName)
|
||||
{
|
||||
AZ::TypeId typeId = GetComponentTypeIdFromName(typeName);
|
||||
|
||||
if (typeId.IsNull())
|
||||
{
|
||||
// GetComponentTypeIdFromName already does error handling
|
||||
return "";
|
||||
}
|
||||
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
|
||||
const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(typeId);
|
||||
|
||||
if (!classData)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Failed to find ClassData for typeId %s (%s)", typeId.ToString<AZStd::string>().c_str(), typeName.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
void* component = classData->m_factory->Create("Component");
|
||||
rapidjson::Document document;
|
||||
AZ::JsonSerializerSettings settings;
|
||||
settings.m_keepDefaults = true;
|
||||
|
||||
auto resultCode = AZ::JsonSerialization::Store(document, document.GetAllocator(), component, nullptr, typeId, settings);
|
||||
|
||||
// Clean up the allocated component ASAP, we don't need it anymore
|
||||
classData->m_factory->Destroy(component);
|
||||
|
||||
if (resultCode.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Failed to serialize component to json (%s): %s",
|
||||
typeName.c_str(), resultCode.ToString(typeName).c_str())
|
||||
return "";
|
||||
}
|
||||
|
||||
AZStd::string jsonString;
|
||||
AZ::Outcome<void, AZStd::string> outcome = AZ::JsonSerializationUtils::WriteJsonString(document, jsonString);
|
||||
|
||||
if (!outcome.IsSuccess())
|
||||
{
|
||||
AZ_Error("EntityUtilityComponent", false, "Failed to write component json to string: %s", outcome.GetError().c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
AZStd::vector<ComponentDetails> EntityUtilityComponent::FindMatchingComponents(const AZStd::string& searchTerm)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
|
||||
if (m_typeInfo.empty())
|
||||
{
|
||||
serializeContext->EnumerateDerived<AZ::Component>(
|
||||
[this, serializeContext](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid& /*typeId*/)
|
||||
{
|
||||
auto& typeInfo = m_typeInfo.emplace_back(classData->m_typeId, classData->m_name, AZStd::vector<AZStd::string>{});
|
||||
|
||||
serializeContext->EnumerateBase(
|
||||
[&typeInfo](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid&)
|
||||
{
|
||||
if (classData)
|
||||
{
|
||||
AZStd::get<2>(typeInfo).emplace_back(classData->m_name);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
classData->m_typeId);
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
AZStd::vector<ComponentDetails> matches;
|
||||
|
||||
for (const auto& [typeId, typeName, baseClasses] : m_typeInfo)
|
||||
{
|
||||
if (AZStd::wildcard_match(searchTerm, typeName))
|
||||
{
|
||||
ComponentDetails details;
|
||||
details.m_typeInfo = AZStd::string::format("%s %s", typeId.ToString<AZStd::string>().c_str(), typeName.c_str());
|
||||
details.m_baseClasses = baseClasses;
|
||||
|
||||
matches.emplace_back(AZStd::move(details));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::ResetEntityContext()
|
||||
{
|
||||
for (AZ::EntityId entityId : m_createdEntities)
|
||||
{
|
||||
m_entityContext->DestroyEntityById(entityId);
|
||||
}
|
||||
|
||||
m_createdEntities.clear();
|
||||
m_entityContext->ResetContext();
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
ComponentDetails::Reflect(context);
|
||||
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<EntityUtilityComponent, AZ::Component>();
|
||||
}
|
||||
|
||||
if (auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->ConstantProperty("InvalidComponentId", BehaviorConstant(AZ::InvalidComponentId))
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Entity")
|
||||
->Attribute(AZ::Script::Attributes::Module, "entity");
|
||||
|
||||
behaviorContext->EBus<EntityUtilityBus>("EntityUtilityBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Entity")
|
||||
->Attribute(AZ::Script::Attributes::Module, "entity")
|
||||
->Event("CreateEditorReadyEntity", &EntityUtilityBus::Events::CreateEditorReadyEntity)
|
||||
->Event("GetOrAddComponentByTypeName", &EntityUtilityBus::Events::GetOrAddComponentByTypeName)
|
||||
->Event("UpdateComponentForEntity", &EntityUtilityBus::Events::UpdateComponentForEntity)
|
||||
->Event("FindMatchingComponents", &EntityUtilityBus::Events::FindMatchingComponents)
|
||||
->Event("GetComponentDefaultJson", &EntityUtilityBus::Events::GetComponentDefaultJson)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::Activate()
|
||||
{
|
||||
m_entityContext = AZStd::make_unique<AzFramework::EntityContext>(UtilityEntityContextId);
|
||||
m_entityContext->InitContext();
|
||||
EntityUtilityBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void EntityUtilityComponent::Deactivate()
|
||||
{
|
||||
EntityUtilityBus::Handler::BusDisconnect();
|
||||
m_entityContext = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorDisabledCompositionBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorPendingCompositionBus.h>
|
||||
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzFramework/Entity/BehaviorEntity.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
struct ComponentDetails
|
||||
{
|
||||
AZ_TYPE_INFO(AzToolsFramework::ComponentDetails, "{107D8379-4AD4-4547-BEE1-184B120F23E9}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_typeInfo;
|
||||
AZStd::vector<AZStd::string> m_baseClasses;
|
||||
};
|
||||
|
||||
// This ebus is intended to provide behavior-context friendly APIs to create and manage entities
|
||||
struct EntityUtilityTraits : AZ::EBusTraits
|
||||
{
|
||||
AZ_RTTI(AzToolsFramework::EntityUtilityTraits, "{A6305CAE-C825-43F9-A44D-E503910912AF}");
|
||||
|
||||
virtual ~EntityUtilityTraits() = default;
|
||||
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
// Creates an entity with the default editor components attached and initializes the entity
|
||||
virtual AZ::EntityId CreateEditorReadyEntity(const AZStd::string& entityName) = 0;
|
||||
|
||||
virtual AzFramework::BehaviorComponentId GetOrAddComponentByTypeName(AZ::EntityId entity, const AZStd::string& typeName) = 0;
|
||||
|
||||
virtual bool UpdateComponentForEntity(AZ::EntityId entity, AzFramework::BehaviorComponentId component, const AZStd::string& json) = 0;
|
||||
|
||||
// Gets a JSON string containing describing the default serialization state of the specified component
|
||||
virtual AZStd::string GetComponentDefaultJson(const AZStd::string& typeName) = 0;
|
||||
|
||||
// Returns a list of matching component type names. Supports wildcard search terms
|
||||
virtual AZStd::vector<ComponentDetails> FindMatchingComponents(const AZStd::string& searchTerm) = 0;
|
||||
|
||||
virtual void ResetEntityContext() = 0;
|
||||
};
|
||||
|
||||
using EntityUtilityBus = AZ::EBus<EntityUtilityTraits>;
|
||||
|
||||
struct EntityUtilityComponent : AZ::Component
|
||||
, EntityUtilityBus::Handler
|
||||
{
|
||||
inline const static AZ::Uuid UtilityEntityContextId = AZ::Uuid("{9C277B88-E79E-4F8A-BAFF-A4C175BD565F}");
|
||||
|
||||
AZ_COMPONENT(EntityUtilityComponent, "{47205907-A0EA-4FFF-A620-04D20C04A379}");
|
||||
|
||||
AZ::EntityId CreateEditorReadyEntity(const AZStd::string& entityName) override;
|
||||
AzFramework::BehaviorComponentId GetOrAddComponentByTypeName(AZ::EntityId entity, const AZStd::string& typeName) override;
|
||||
bool UpdateComponentForEntity(AZ::EntityId entity, AzFramework::BehaviorComponentId component, const AZStd::string& json) override;
|
||||
AZStd::string GetComponentDefaultJson(const AZStd::string& typeName) override;
|
||||
AZStd::vector<ComponentDetails> FindMatchingComponents(const AZStd::string& searchTerm) override;
|
||||
void ResetEntityContext() override;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
protected:
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
// Our own entity context. This API is intended mostly for use in Asset Builders where there is no editor context
|
||||
// Additionally, an entity context is needed when using the Behavior Entity class
|
||||
AZStd::unique_ptr<AzFramework::EntityContext> m_entityContext;
|
||||
|
||||
// TypeId, TypeName, Vector<BaseClassName>
|
||||
AZStd::vector<AZStd::tuple<AZ::TypeId, AZStd::string, AZStd::vector<AZStd::string>>> m_typeInfo;
|
||||
|
||||
// Keep track of the entities we create so they can be reset
|
||||
AZStd::vector<AZ::EntityId> m_createdEntities;
|
||||
};
|
||||
}; // namespace AzToolsFramework
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
|
||||
@@ -224,6 +224,7 @@ namespace AzToolsFramework
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Data::SerializedAssetTracker* assetTracker = settings.m_metadata.Find<AZ::Data::SerializedAssetTracker>();
|
||||
|
||||
referencedAssets = AZStd::move(assetTracker->GetTrackedAssets());
|
||||
@@ -245,6 +246,30 @@ namespace AzToolsFramework
|
||||
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
|
||||
}
|
||||
|
||||
// some assets may come in from the JSON serialzier with no AssetID, but have an asset hint
|
||||
// this attempts to fix up the assets using the assetHint field
|
||||
auto fixUpInvalidAssets = [](AZ::Data::Asset<AZ::Data::AssetData>& asset)
|
||||
{
|
||||
if (!asset.GetId().IsValid() && !asset.GetHint().empty())
|
||||
{
|
||||
AZ::Data::AssetId assetId;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
assetId,
|
||||
&AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
|
||||
asset.GetHint().c_str(),
|
||||
AZ::Data::s_invalidAssetType,
|
||||
false);
|
||||
|
||||
if (assetId.IsValid())
|
||||
{
|
||||
asset.Create(assetId, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto tracker = AZ::Data::SerializedAssetTracker{};
|
||||
tracker.SetAssetFixUp(fixUpInvalidAssets);
|
||||
|
||||
AZ::JsonDeserializerSettings settings;
|
||||
// The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is
|
||||
// specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta
|
||||
@@ -252,16 +277,17 @@ namespace AzToolsFramework
|
||||
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
|
||||
settings.m_metadata.Add(&entityIdMapper);
|
||||
settings.m_metadata.Create<InstanceEntityScrubber>(newlyAddedEntities);
|
||||
settings.m_metadata.Add(tracker);
|
||||
|
||||
AZStd::string scratchBuffer;
|
||||
auto issueReportingCallback = [&scratchBuffer](
|
||||
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
|
||||
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
|
||||
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
|
||||
{
|
||||
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
|
||||
};
|
||||
settings.m_reporting = AZStd::move(issueReportingCallback);
|
||||
|
||||
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings);
|
||||
|
||||
AZ::Data::AssetManager::Instance().ResumeAssetRelease();
|
||||
|
||||
@@ -50,17 +50,19 @@ namespace AzToolsFramework
|
||||
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
AZ_Assert(settingsRegistry, "Settings registry is not set");
|
||||
|
||||
|
||||
[[maybe_unused]] bool result =
|
||||
settingsRegistry->Get(m_projectPathWithOsSeparator.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath);
|
||||
AZ_Warning("Prefab", result, "Couldn't retrieve project root path");
|
||||
m_projectPathWithSlashSeparator = AZ::IO::Path(m_projectPathWithOsSeparator.Native(), '/').MakePreferred();
|
||||
|
||||
AZ::Interface<PrefabLoaderInterface>::Register(this);
|
||||
m_scriptingPrefabLoader.Connect(this);
|
||||
}
|
||||
|
||||
void PrefabLoader::UnregisterPrefabLoaderInterface()
|
||||
{
|
||||
m_scriptingPrefabLoader.Disconnect();
|
||||
AZ::Interface<PrefabLoaderInterface>::Unregister(this);
|
||||
}
|
||||
|
||||
@@ -568,7 +570,7 @@ namespace AzToolsFramework
|
||||
(pathStr.find_first_of(AZ_FILESYSTEM_INVALID_CHARACTERS) == AZStd::string::npos) &&
|
||||
(pathStr.back() != '\\' && pathStr.back() != '/');
|
||||
}
|
||||
|
||||
|
||||
AZ::IO::Path PrefabLoader::GetFullPath(AZ::IO::PathView path)
|
||||
{
|
||||
AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path).MakePreferred();
|
||||
@@ -596,26 +598,38 @@ namespace AzToolsFramework
|
||||
{
|
||||
// The asset system provided us with a valid root folder and relative path, so return it.
|
||||
fullPath = AZ::IO::Path(rootFolder) / assetInfo.m_relativePath;
|
||||
return fullPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If for some reason the Asset system couldn't provide a relative path, provide some fallback logic.
|
||||
|
||||
// Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow
|
||||
// the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside
|
||||
// a unit test, so just execute the fallback logic without an error.
|
||||
[[maybe_unused]] bool assetProcessorReady = false;
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady);
|
||||
|
||||
AZ_Error(
|
||||
"Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.",
|
||||
AZ_STRING_ARG(path.Native()));
|
||||
|
||||
// If a relative path was passed in, make it relative to the project root.
|
||||
fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator);
|
||||
// attempt to find the absolute from the Cache folder
|
||||
AZStd::string assetRootFolder;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
settingsRegistry->Get(assetRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder);
|
||||
}
|
||||
fullPath = AZ::IO::Path(assetRootFolder) / path;
|
||||
if (fullPath.IsAbsolute() && AZ::IO::SystemFile::Exists(fullPath.c_str()))
|
||||
{
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
// If for some reason the Asset system couldn't provide a relative path, provide some fallback logic.
|
||||
|
||||
// Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow
|
||||
// the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside
|
||||
// a unit test, so just execute the fallback logic without an error.
|
||||
[[maybe_unused]] bool assetProcessorReady = false;
|
||||
AzFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady);
|
||||
|
||||
AZ_Error(
|
||||
"Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.",
|
||||
AZ_STRING_ARG(path.Native()));
|
||||
|
||||
// If a relative path was passed in, make it relative to the project root.
|
||||
fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator);
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
|
||||
#include <Prefab/ScriptingPrefabLoader.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -114,6 +115,7 @@ namespace AzToolsFramework
|
||||
void SetSaveAllPrefabsPreference(SaveAllPrefabsPreference saveAllPrefabsPreference) override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Copies the template dom provided and manipulates it into the proper format to be saved to disk.
|
||||
* @param templateRef The template whose dom we want to transform into the proper format to be saved to disk.
|
||||
@@ -177,6 +179,7 @@ namespace AzToolsFramework
|
||||
AZStd::optional<AZStd::pair<PrefabDom, AZ::IO::Path>> StoreTemplateIntoFileFormat(TemplateId templateId);
|
||||
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
|
||||
ScriptingPrefabLoader m_scriptingPrefabLoader;
|
||||
AZ::IO::Path m_projectPathWithOsSeparator;
|
||||
AZ::IO::Path m_projectPathWithSlashSeparator;
|
||||
};
|
||||
|
||||
@@ -99,7 +99,6 @@ namespace AzToolsFramework
|
||||
// Generates a new path
|
||||
static AZ::IO::Path GeneratePath();
|
||||
};
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
// Ebus for script-friendly APIs for the prefab loader
|
||||
struct PrefabLoaderScriptingTraits : AZ::EBusTraits
|
||||
{
|
||||
AZ_TYPE_INFO(PrefabLoaderScriptingTraits, "{C344B7D8-8299-48C9-8450-26E1332EA011}");
|
||||
|
||||
virtual ~PrefabLoaderScriptingTraits() = default;
|
||||
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
/**
|
||||
* Saves a Prefab Template into the provided output string.
|
||||
* Converts Prefab Template form into .prefab form by collapsing nested Template info
|
||||
* into a source path and patches.
|
||||
* @param templateId Id of the template to be saved
|
||||
* @return Will contain the serialized template json on success
|
||||
*/
|
||||
virtual AZ::Outcome<AZStd::string, void> SaveTemplateToString(TemplateId templateId) = 0;
|
||||
};
|
||||
|
||||
using PrefabLoaderScriptingBus = AZ::EBus<PrefabLoaderScriptingTraits>;
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.h>
|
||||
@@ -36,12 +37,14 @@ namespace AzToolsFramework
|
||||
m_instanceToTemplatePropagator.RegisterInstanceToTemplateInterface();
|
||||
m_prefabPublicHandler.RegisterPrefabPublicHandlerInterface();
|
||||
m_prefabPublicRequestHandler.Connect();
|
||||
m_prefabSystemScriptingHandler.Connect(this);
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::Deactivate()
|
||||
{
|
||||
AZ::SystemTickBus::Handler::BusDisconnect();
|
||||
m_prefabSystemScriptingHandler.Disconnect();
|
||||
m_prefabPublicRequestHandler.Disconnect();
|
||||
m_prefabPublicHandler.UnregisterPrefabPublicHandlerInterface();
|
||||
m_instanceToTemplatePropagator.UnregisterInstanceToTemplateInterface();
|
||||
@@ -58,13 +61,24 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover::Reflect(context);
|
||||
PrefabPublicRequestHandler::Reflect(context);
|
||||
PrefabLoader::Reflect(context);
|
||||
PrefabSystemScriptingHandler::Reflect(context);
|
||||
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<PrefabSystemComponent, AZ::Component>()->Version(1);
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
|
||||
behaviorContext->EBus<PrefabLoaderScriptingBus>("PrefabLoaderScriptingBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Attribute(AZ::Script::Attributes::Category, "Prefab")
|
||||
->Event("SaveTemplateToString", &PrefabLoaderScriptingBus::Events::SaveTemplateToString);
|
||||
;
|
||||
}
|
||||
|
||||
AZ::JsonRegistrationContext* jsonRegistration = azrtti_cast<AZ::JsonRegistrationContext*>(context);
|
||||
if (jsonRegistration)
|
||||
{
|
||||
@@ -145,7 +159,7 @@ namespace AzToolsFramework
|
||||
newInstance->SetTemplateId(newTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PrefabSystemComponent::PropagateTemplateChanges(TemplateId templateId, bool immediate, InstanceOptionalReference instanceToExclude)
|
||||
{
|
||||
UpdatePrefabInstances(templateId, immediate, instanceToExclude);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicRequestHandler.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
#include <Prefab/PrefabSystemScriptingHandler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -219,7 +220,7 @@ namespace AzToolsFramework
|
||||
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume,
|
||||
AZ::IO::PathView filePath, AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr,
|
||||
InstanceOptionalReference parent = AZStd::nullopt, bool shouldCreateLinks = true) override;
|
||||
|
||||
|
||||
PrefabDom& FindTemplateDom(TemplateId templateId) override;
|
||||
|
||||
/**
|
||||
@@ -244,7 +245,7 @@ namespace AzToolsFramework
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(PrefabSystemComponent);
|
||||
|
||||
|
||||
/**
|
||||
* Builds a new Prefab Template out of entities and instances and returns the first instance comprised of
|
||||
* these entities and instances.
|
||||
@@ -412,6 +413,8 @@ namespace AzToolsFramework
|
||||
|
||||
// Handler of the public Prefab requests.
|
||||
PrefabPublicRequestHandler m_prefabPublicRequestHandler;
|
||||
|
||||
PrefabSystemScriptingHandler m_prefabSystemScriptingHandler;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-2
@@ -78,8 +78,7 @@ namespace AzToolsFramework
|
||||
AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr, InstanceOptionalReference parent = AZStd::nullopt,
|
||||
bool shouldCreateLinks = true) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Link/Link.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
// Bus that exposes a script-friendly interface to the PrefabSystemComponent
|
||||
struct PrefabSystemScriptingEbusTraits : AZ::EBusTraits
|
||||
{
|
||||
using MutexType = AZ::NullMutex;
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
|
||||
virtual TemplateId CreatePrefabTemplate(
|
||||
const AZStd::vector<AZ::EntityId>& entityIds, const AZStd::string& filePath) = 0;
|
||||
};
|
||||
|
||||
using PrefabSystemScriptingBus = AZ::EBus<PrefabSystemScriptingEbusTraits>;
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <Prefab/PrefabSystemScriptingHandler.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
void PrefabSystemScriptingHandler::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->ConstantProperty("InvalidTemplateId", BehaviorConstant(InvalidTemplateId))
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Attribute(AZ::Script::Attributes::Category, "Prefab");
|
||||
|
||||
behaviorContext->EBus<PrefabSystemScriptingBus>("PrefabSystemScriptingBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "prefab")
|
||||
->Attribute(AZ::Script::Attributes::Category, "Prefab")
|
||||
->Event("CreatePrefab", &PrefabSystemScriptingBus::Events::CreatePrefabTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabSystemScriptingHandler::Connect(PrefabSystemComponentInterface* prefabSystemComponentInterface)
|
||||
{
|
||||
AZ_Assert(prefabSystemComponentInterface != nullptr, "prefabSystemComponentInterface must not be null");
|
||||
m_prefabSystemComponentInterface = prefabSystemComponentInterface;
|
||||
PrefabSystemScriptingBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void PrefabSystemScriptingHandler::Disconnect()
|
||||
{
|
||||
PrefabSystemScriptingBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
TemplateId PrefabSystemScriptingHandler::CreatePrefabTemplate(const AZStd::vector<AZ::EntityId>& entityIds, const AZStd::string& filePath)
|
||||
{
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
|
||||
for (const auto& entityId : entityIds)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
|
||||
|
||||
AZ_Warning(
|
||||
"PrefabSystemComponent", entity, "EntityId %s was not found and will not be added to the prefab",
|
||||
entityId.ToString().c_str());
|
||||
|
||||
if (entity)
|
||||
{
|
||||
entities.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
auto prefab = m_prefabSystemComponentInterface->CreatePrefab(entities, {}, AZ::IO::PathView(AZStd::string_view(filePath)));
|
||||
|
||||
if (!prefab)
|
||||
{
|
||||
AZ_Error("PrefabSystemComponenent", false, "Failed to create prefab %s", filePath.c_str());
|
||||
return InvalidTemplateId;
|
||||
}
|
||||
|
||||
return prefab->GetTemplateId();
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <Prefab/PrefabSystemScriptingBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabSystemScriptingHandler
|
||||
: PrefabSystemScriptingBus::Handler
|
||||
{
|
||||
public:
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
PrefabSystemScriptingHandler() = default;
|
||||
|
||||
void Connect(PrefabSystemComponentInterface* prefabSystemComponentInterface);
|
||||
void Disconnect();
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY(PrefabSystemScriptingHandler);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PrefabSystemScriptingBus implementation
|
||||
TemplateId CreatePrefabTemplate(const AZStd::vector<AZ::EntityId>& entityIds, const AZStd::string& filePath) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include <Prefab/Procedural/ProceduralPrefabAsset.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
|
||||
namespace AZ::Prefab
|
||||
{
|
||||
static constexpr const char s_useProceduralPrefabsKey[] = "/O3DE/Preferences/Prefabs/UseProceduralPrefabs";
|
||||
|
||||
// ProceduralPrefabAsset
|
||||
|
||||
ProceduralPrefabAsset::ProceduralPrefabAsset(const AZ::Data::AssetId& assetId)
|
||||
: AZ::Data::AssetData(assetId)
|
||||
, m_templateId(AzToolsFramework::Prefab::InvalidTemplateId)
|
||||
{
|
||||
}
|
||||
|
||||
void ProceduralPrefabAsset::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
PrefabDomData::Reflect(context);
|
||||
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
|
||||
{
|
||||
serializeContext->Class<ProceduralPrefabAsset, AZ::Data::AssetData>()
|
||||
->Version(1)
|
||||
->Field("Template Name", &ProceduralPrefabAsset::m_templateName)
|
||||
->Field("Template ID", &ProceduralPrefabAsset::m_templateId);
|
||||
}
|
||||
}
|
||||
|
||||
const AZStd::string& ProceduralPrefabAsset::GetTemplateName() const
|
||||
{
|
||||
return m_templateName;
|
||||
}
|
||||
|
||||
void ProceduralPrefabAsset::SetTemplateName(AZStd::string templateName)
|
||||
{
|
||||
m_templateName = AZStd::move(templateName);
|
||||
}
|
||||
|
||||
AzToolsFramework::Prefab::TemplateId ProceduralPrefabAsset::GetTemplateId() const
|
||||
{
|
||||
return m_templateId;
|
||||
}
|
||||
|
||||
void ProceduralPrefabAsset::SetTemplateId(AzToolsFramework::Prefab::TemplateId templateId)
|
||||
{
|
||||
m_templateId = templateId;
|
||||
}
|
||||
|
||||
bool ProceduralPrefabAsset::UseProceduralPrefabs()
|
||||
{
|
||||
bool useProceduralPrefabs = false;
|
||||
bool result = AZ::SettingsRegistry::Get()->GetObject(useProceduralPrefabs, s_useProceduralPrefabsKey);
|
||||
return result && useProceduralPrefabs;
|
||||
}
|
||||
|
||||
// PrefabDomData
|
||||
|
||||
void PrefabDomData::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* jsonContext = azrtti_cast<AZ::JsonRegistrationContext*>(context))
|
||||
{
|
||||
jsonContext->Serializer<PrefabDomDataJsonSerializer>()->HandlesType<PrefabDomData>();
|
||||
}
|
||||
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<PrefabDomData>()
|
||||
->Version(1);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabDomData::CopyValue(const rapidjson::Value& inputValue)
|
||||
{
|
||||
m_prefabDom.CopyFrom(inputValue, m_prefabDom.GetAllocator());
|
||||
}
|
||||
|
||||
const AzToolsFramework::Prefab::PrefabDom& PrefabDomData::GetValue() const
|
||||
{
|
||||
return m_prefabDom;
|
||||
}
|
||||
|
||||
// PrefabDomDataJsonSerializer
|
||||
|
||||
AZ::JsonSerializationResult::Result PrefabDomDataJsonSerializer::Load(
|
||||
void* outputValue,
|
||||
[[maybe_unused]] const AZ::Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
AZ::JsonDeserializerContext& context)
|
||||
{
|
||||
AZ_Assert(outputValueTypeId == azrtti_typeid<PrefabDomData>(),
|
||||
"PrefabDomDataJsonSerializer Load against output typeID that was not PrefabDomData");
|
||||
AZ_Assert(outputValue, "PrefabDomDataJsonSerializer Load against null output");
|
||||
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
|
||||
if (inputValue.IsObject() == false)
|
||||
{
|
||||
result.Combine(context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, "Missing object"));
|
||||
return context.Report(result, "Prefab should be an object.");
|
||||
}
|
||||
|
||||
if (inputValue.MemberCount() < 1)
|
||||
{
|
||||
result.Combine(context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, "Missing members"));
|
||||
return context.Report(result, "Prefab should have multiple members.");
|
||||
}
|
||||
|
||||
auto* outputVariable = reinterpret_cast<PrefabDomData*>(outputValue);
|
||||
outputVariable->CopyValue(inputValue);
|
||||
return context.Report(result, "Loaded procedural prefab");
|
||||
}
|
||||
|
||||
AZ::JsonSerializationResult::Result PrefabDomDataJsonSerializer::Store(
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
[[maybe_unused]] const void* defaultValue,
|
||||
[[maybe_unused]] const AZ::Uuid& valueTypeId,
|
||||
AZ::JsonSerializerContext& context)
|
||||
{
|
||||
AZ_Assert(inputValue, "Input value for PrefabDomDataJsonSerializer can't be null.");
|
||||
AZ_Assert(azrtti_typeid<PrefabDomData>() == valueTypeId,
|
||||
"Unable to Serialize because the provided type is not PrefabGroup::PrefabDomData.");
|
||||
|
||||
const PrefabDomData* prefabDomData = reinterpret_cast<const PrefabDomData*>(inputValue);
|
||||
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
JSR::ResultCode result(JSR::Tasks::WriteValue);
|
||||
outputValue.SetObject();
|
||||
outputValue.CopyFrom(prefabDomData->GetValue(), context.GetJsonAllocator());
|
||||
return context.Report(result, "Stored procedural prefab");
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
|
||||
namespace AZ::Prefab
|
||||
{
|
||||
//! A wrapper around the JSON DOM type so that the assets can read in and write out
|
||||
//! JSON directly since Prefabs are JSON serialized entity-component data
|
||||
class PrefabDomData final
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PrefabDomData, "{C73A3360-D772-4D41-9118-A039BF9340C1}");
|
||||
AZ_CLASS_ALLOCATOR(PrefabDomData, AZ::SystemAllocator, 0);
|
||||
|
||||
PrefabDomData() = default;
|
||||
~PrefabDomData() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
void CopyValue(const rapidjson::Value& inputValue);
|
||||
const AzToolsFramework::Prefab::PrefabDom& GetValue() const;
|
||||
|
||||
private:
|
||||
AzToolsFramework::Prefab::PrefabDom m_prefabDom;
|
||||
};
|
||||
|
||||
//! Registered to help read/write JSON for the PrefabDomData::m_prefabDom
|
||||
class PrefabDomDataJsonSerializer final
|
||||
: public AZ::BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PrefabDomDataJsonSerializer, "{9FC48652-A00B-4EFA-8FD9-345A8E625439}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR(PrefabDomDataJsonSerializer, AZ::SystemAllocator, 0);
|
||||
|
||||
~PrefabDomDataJsonSerializer() override = default;
|
||||
|
||||
AZ::JsonSerializationResult::Result Load(
|
||||
void* outputValue,
|
||||
const AZ::Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
AZ::JsonDeserializerContext& context) override;
|
||||
|
||||
AZ::JsonSerializationResult::Result Store(
|
||||
rapidjson::Value& outputValue,
|
||||
const void* inputValue,
|
||||
const void* defaultValue,
|
||||
const AZ::Uuid& valueTypeId,
|
||||
AZ::JsonSerializerContext& context) override;
|
||||
};
|
||||
|
||||
//! An asset type to register templates into the Prefab system so that they
|
||||
//! can instantiate like Authored Prefabs
|
||||
class ProceduralPrefabAsset
|
||||
: public AZ::Data::AssetData
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ProceduralPrefabAsset, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(ProceduralPrefabAsset, "{9B7C8459-471E-4EAD-A363-7990CC4065A9}", AZ::Data::AssetData);
|
||||
|
||||
static bool UseProceduralPrefabs();
|
||||
|
||||
ProceduralPrefabAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId());
|
||||
~ProceduralPrefabAsset() override = default;
|
||||
ProceduralPrefabAsset(const ProceduralPrefabAsset& rhs) = delete;
|
||||
ProceduralPrefabAsset& operator=(const ProceduralPrefabAsset& rhs) = delete;
|
||||
|
||||
const AZStd::string& GetTemplateName() const;
|
||||
void SetTemplateName(AZStd::string templateName);
|
||||
|
||||
AzToolsFramework::Prefab::TemplateId GetTemplateId() const;
|
||||
void SetTemplateId(AzToolsFramework::Prefab::TemplateId templateId);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
AZStd::string m_templateName;
|
||||
AzToolsFramework::Prefab::TemplateId m_templateId;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Prefab/ScriptingPrefabLoader.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab
|
||||
{
|
||||
void ScriptingPrefabLoader::Connect(PrefabLoaderInterface* prefabLoaderInterface)
|
||||
{
|
||||
AZ_Assert(prefabLoaderInterface, "prefabLoaderInterface must not be null");
|
||||
|
||||
m_prefabLoaderInterface = prefabLoaderInterface;
|
||||
PrefabLoaderScriptingBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void ScriptingPrefabLoader::Disconnect()
|
||||
{
|
||||
PrefabLoaderScriptingBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZ::Outcome<AZStd::string, void> ScriptingPrefabLoader::SaveTemplateToString(TemplateId templateId)
|
||||
{
|
||||
AZStd::string json;
|
||||
|
||||
if (m_prefabLoaderInterface->SaveTemplateToString(templateId, json))
|
||||
{
|
||||
return AZ::Success(json);
|
||||
}
|
||||
|
||||
return AZ::Failure();
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Prefab/PrefabLoaderInterface.h>
|
||||
#include <Prefab/PrefabLoaderScriptingBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
/**
|
||||
* The Scripting Prefab Loader handles scripting-friendly API requests for the prefab loader
|
||||
*/
|
||||
class ScriptingPrefabLoader
|
||||
: private PrefabLoaderScriptingBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ScriptingPrefabLoader, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(ScriptingPrefabLoader, "{ABC3C989-4D4F-41E7-B25B-B0FEF97177E6}");
|
||||
|
||||
void Connect(PrefabLoaderInterface* prefabLoaderInterface);
|
||||
void Disconnect();
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PrefabLoaderRequestBus implementation
|
||||
AZ::Outcome<AZStd::string, void> SaveTemplateToString(TemplateId templateId) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrefabLoaderInterface* m_prefabLoaderInterface = nullptr;
|
||||
};
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+1
-1
@@ -1025,7 +1025,7 @@ namespace AzToolsFramework
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/LuaScript.svg")
|
||||
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<AZ::ScriptAsset>::Uuid())
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Script.png")
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/lua-script/")
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/lua-script/")
|
||||
->DataElement("AssetRef", &ScriptEditorComponent::m_scriptAsset, "Script", "Which script to use")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &ScriptEditorComponent::ScriptHasChanged)
|
||||
->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg")
|
||||
|
||||
+73
@@ -13,6 +13,7 @@
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
@@ -25,6 +26,9 @@
|
||||
#include <AzToolsFramework/ContainerEntity/ContainerEntityInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
||||
@@ -218,6 +222,16 @@ namespace AzToolsFramework
|
||||
instantiateAction, &QAction::triggered, instantiateAction, [] { ContextMenu_InstantiatePrefab(); });
|
||||
}
|
||||
|
||||
// Instantiate Procedural Prefab
|
||||
if (AZ::Prefab::ProceduralPrefabAsset::UseProceduralPrefabs())
|
||||
{
|
||||
QAction* action = menu->addAction(QObject::tr("Instantiate Procedural Prefab..."));
|
||||
action->setToolTip(QObject::tr("Instantiates a procedural prefab file in a prefab."));
|
||||
|
||||
QObject::connect(
|
||||
action, &QAction::triggered, action, [] { ContextMenu_InstantiateProceduralPrefab(); });
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
bool itemWasShown = false;
|
||||
@@ -435,6 +449,38 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_InstantiateProceduralPrefab()
|
||||
{
|
||||
AZStd::string prefabAssetPath;
|
||||
bool hasUserForProceduralPrefabAsset = QueryUserForProceduralPrefabAsset(prefabAssetPath);
|
||||
|
||||
if (hasUserForProceduralPrefabAsset)
|
||||
{
|
||||
AZ::EntityId parentId;
|
||||
AZ::Vector3 position = AZ::Vector3::CreateZero();
|
||||
|
||||
EntityIdList selectedEntities;
|
||||
ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities);
|
||||
if (selectedEntities.size() == 1)
|
||||
{
|
||||
parentId = selectedEntities.front();
|
||||
AZ::TransformBus::EventResult(position, parentId, &AZ::TransformInterface::GetWorldTranslation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise return since it needs to be inside an authored prefab
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiating from context menu always puts the instance at the root level
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(prefabAssetPath, parentId, position);
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
{
|
||||
WarnUserOfError("Prefab Instantiation Error", createPrefabOutcome.GetError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::ContextMenu_EditPrefab(AZ::EntityId containerEntity)
|
||||
{
|
||||
s_prefabFocusInterface->FocusOnOwningPrefab(containerEntity);
|
||||
@@ -690,6 +736,33 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PrefabIntegrationManager::QueryUserForProceduralPrefabAsset(AZStd::string& outPrefabAssetPath)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
auto selection = AssetBrowser::AssetSelectionModel::AssetTypeSelection(azrtti_typeid<AZ::Prefab::ProceduralPrefabAsset>());
|
||||
EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection);
|
||||
|
||||
if (!selection.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
|
||||
if (product == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
outPrefabAssetPath = product->GetRelativePath();
|
||||
|
||||
auto asset = AZ::Data::AssetManager::Instance().GetAsset(
|
||||
product->GetAssetId(),
|
||||
azrtti_typeid<AZ::Prefab::ProceduralPrefabAsset>(),
|
||||
AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
return asset.BlockUntilLoadComplete() != AZ::Data::AssetData::AssetStatus::Error;
|
||||
}
|
||||
|
||||
void PrefabIntegrationManager::WarnUserOfError(AZStd::string_view title, AZStd::string_view message)
|
||||
{
|
||||
QWidget* activeWindow = QApplication::activeWindow();
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace AzToolsFramework
|
||||
// Context menu item handlers
|
||||
static void ContextMenu_CreatePrefab(AzToolsFramework::EntityIdList selectedEntities);
|
||||
static void ContextMenu_InstantiatePrefab();
|
||||
static void ContextMenu_InstantiateProceduralPrefab();
|
||||
static void ContextMenu_EditPrefab(AZ::EntityId containerEntity);
|
||||
static void ContextMenu_SavePrefab(AZ::EntityId containerEntity);
|
||||
static void ContextMenu_DeleteSelected();
|
||||
@@ -101,6 +102,7 @@ namespace AzToolsFramework
|
||||
const AZStd::string& suggestedName, const char* initialTargetDirectory, AZ::u32 prefabUserSettingsId, QWidget* activeWindow,
|
||||
AZStd::string& outPrefabName, AZStd::string& outPrefabFilePath);
|
||||
static bool QueryUserForPrefabFilePath(AZStd::string& outPrefabFilePath);
|
||||
static bool QueryUserForProceduralPrefabAsset(AZStd::string& outPrefabAssetPath);
|
||||
static void WarnUserOfError(AZStd::string_view title, AZStd::string_view message);
|
||||
|
||||
// Path and filename generation
|
||||
|
||||
+2
-42
@@ -103,10 +103,6 @@ namespace AzToolsFramework
|
||||
static const char* const ResetEntityTransformDesc = "Reset transform based on manipulator mode";
|
||||
static const char* const ResetManipulatorTitle = "Reset Manipulator";
|
||||
static const char* const ResetManipulatorDesc = "Reset the manipulator to recenter it on the selected entity";
|
||||
static const char* const ResetTransformLocalTitle = "Reset Transform (Local)";
|
||||
static const char* const ResetTransformLocalDesc = "Reset transform to local space";
|
||||
static const char* const ResetTransformWorldTitle = "Reset Transform (World)";
|
||||
static const char* const ResetTransformWorldDesc = "Reset transform to world space";
|
||||
|
||||
static const char* const EntityBoxSelectUndoRedoDesc = "Box Select Entities";
|
||||
static const char* const EntityDeselectUndoRedoDesc = "Deselect Entity";
|
||||
@@ -2424,45 +2420,9 @@ namespace AzToolsFramework
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_R) }, EditResetManipulator, ResetManipulatorTitle, ResetManipulatorDesc,
|
||||
AZStd::bind(AZStd::mem_fn(&EditorTransformComponentSelection::DelegateClearManipulatorOverride), this));
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::ALT + Qt::Key_R) }, EditResetLocal, ResetTransformLocalTitle, ResetTransformLocalDesc,
|
||||
[this]()
|
||||
[this]
|
||||
{
|
||||
switch (m_mode)
|
||||
{
|
||||
case Mode::Rotation:
|
||||
ResetOrientationForSelectedEntitiesLocal();
|
||||
break;
|
||||
case Mode::Scale:
|
||||
CopyScaleToSelectedEntitiesIndividualWorld(1.0f);
|
||||
break;
|
||||
case Mode::Translation:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
AddAction(
|
||||
m_actions, { QKeySequence(Qt::SHIFT + Qt::Key_R) }, EditResetWorld, ResetTransformWorldTitle, ResetTransformWorldDesc,
|
||||
[this]()
|
||||
{
|
||||
switch (m_mode)
|
||||
{
|
||||
case Mode::Rotation:
|
||||
{
|
||||
// begin an undo batch so operations inside CopyOrientation... and
|
||||
// DelegateClear... are grouped into a single undo/redo
|
||||
ScopedUndoBatch undoBatch{ ResetTransformWorldTitle };
|
||||
CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity());
|
||||
ClearManipulatorOrientationOverride();
|
||||
}
|
||||
break;
|
||||
case Mode::Scale:
|
||||
case Mode::Translation:
|
||||
break;
|
||||
}
|
||||
DelegateClearManipulatorOverride();
|
||||
});
|
||||
|
||||
AddAction(
|
||||
|
||||
-2
@@ -31,8 +31,6 @@ namespace AzToolsFramework
|
||||
constexpr inline AZ::Crc32 EditPivot = AZ_CRC_CE("com.o3de.action.editortransform.editpivot");
|
||||
constexpr inline AZ::Crc32 EditReset = AZ_CRC_CE("com.o3de.action.editortransform.editreset");
|
||||
constexpr inline AZ::Crc32 EditResetManipulator = AZ_CRC_CE("com.o3de.action.editortransform.editresetmanipulator");
|
||||
constexpr inline AZ::Crc32 EditResetLocal = AZ_CRC_CE("com.o3de.action.editortransform.editresetlocal");
|
||||
constexpr inline AZ::Crc32 EditResetWorld = AZ_CRC_CE("com.o3de.action.editortransform.editresetworld");
|
||||
constexpr inline AZ::Crc32 ViewportUiVisible = AZ_CRC_CE("com.o3de.action.editortransform.viewportuivisible");
|
||||
//@}
|
||||
|
||||
|
||||
@@ -154,6 +154,8 @@ set(FILES
|
||||
Entity/SliceEditorEntityOwnershipService.h
|
||||
Entity/SliceEditorEntityOwnershipService.cpp
|
||||
Entity/SliceEditorEntityOwnershipServiceBus.h
|
||||
Entity/EntityUtilityComponent.h
|
||||
Entity/EntityUtilityComponent.cpp
|
||||
Fingerprinting/TypeFingerprinter.h
|
||||
Fingerprinting/TypeFingerprinter.cpp
|
||||
FocusMode/FocusModeInterface.h
|
||||
@@ -648,9 +650,15 @@ set(FILES
|
||||
Prefab/PrefabLoader.h
|
||||
Prefab/PrefabLoader.cpp
|
||||
Prefab/PrefabLoaderInterface.h
|
||||
Prefab/PrefabLoaderScriptingBus.h
|
||||
Prefab/ScriptingPrefabLoader.h
|
||||
Prefab/ScriptingPrefabLoader.cpp
|
||||
Prefab/PrefabSystemComponent.h
|
||||
Prefab/PrefabSystemComponent.cpp
|
||||
Prefab/PrefabSystemComponentInterface.h
|
||||
Prefab/PrefabSystemScriptingBus.h
|
||||
Prefab/PrefabSystemScriptingHandler.h
|
||||
Prefab/PrefabSystemScriptingHandler.cpp
|
||||
Prefab/Instance/Instance.h
|
||||
Prefab/Instance/Instance.cpp
|
||||
Prefab/Instance/InstanceSerializer.h
|
||||
@@ -673,6 +681,8 @@ set(FILES
|
||||
Prefab/Instance/TemplateInstanceMapperInterface.h
|
||||
Prefab/Link/Link.h
|
||||
Prefab/Link/Link.cpp
|
||||
Prefab/Procedural/ProceduralPrefabAsset.h
|
||||
Prefab/Procedural/ProceduralPrefabAsset.cpp
|
||||
Prefab/PrefabPublicHandler.h
|
||||
Prefab/PrefabPublicHandler.cpp
|
||||
Prefab/PrefabPublicInterface.h
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Entity/BehaviorEntity.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
|
||||
#include <Entity/EntityUtilityComponent.h>
|
||||
#include <ToolsComponents/TransformComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
// Global variables for communicating between Lua test code and C++
|
||||
AZ::EntityId g_globalEntityId = AZ::EntityId{};
|
||||
AZStd::string g_globalString = "";
|
||||
AzFramework::BehaviorComponentId g_globalComponentId = {};
|
||||
AZStd::vector<AzToolsFramework::ComponentDetails> g_globalComponentDetails = {};
|
||||
bool g_globalBool = false;
|
||||
|
||||
class EntityUtilityComponentTests
|
||||
: public ToolsApplicationFixture
|
||||
{
|
||||
void InitProperties()
|
||||
{
|
||||
AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
|
||||
ASSERT_NE(componentApplicationRequests, nullptr);
|
||||
|
||||
auto behaviorContext = componentApplicationRequests->GetBehaviorContext();
|
||||
|
||||
ASSERT_NE(behaviorContext, nullptr);
|
||||
|
||||
behaviorContext->Property("g_globalEntityId", BehaviorValueProperty(&g_globalEntityId));
|
||||
behaviorContext->Property("g_globalString", BehaviorValueProperty(&g_globalString));
|
||||
behaviorContext->Property("g_globalComponentId", BehaviorValueProperty(&g_globalComponentId));
|
||||
behaviorContext->Property("g_globalBool", BehaviorValueProperty(&g_globalBool));
|
||||
behaviorContext->Property("g_globalComponentDetails", BehaviorValueProperty(&g_globalComponentDetails));
|
||||
|
||||
g_globalEntityId = AZ::EntityId{};
|
||||
g_globalString = AZStd::string{};
|
||||
g_globalComponentId = AzFramework::BehaviorComponentId{};
|
||||
g_globalBool = false;
|
||||
g_globalComponentDetails = AZStd::vector<AzToolsFramework::ComponentDetails>{};
|
||||
}
|
||||
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
InitProperties();
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
{
|
||||
g_globalString.set_capacity(0); // Free all memory
|
||||
g_globalComponentDetails.set_capacity(0);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, CreateEntity)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
my_entity = Entity(g_globalEntityId)
|
||||
g_globalString = my_entity:GetName()
|
||||
)LUA");
|
||||
|
||||
EXPECT_NE(g_globalEntityId, AZ::EntityId{});
|
||||
EXPECT_STREQ(g_globalString.c_str(), "test");
|
||||
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
ASSERT_NE(entity, nullptr);
|
||||
|
||||
// Test cleaning up, make sure the entity is destroyed
|
||||
AzToolsFramework::EntityUtilityBus::Broadcast(&AzToolsFramework::EntityUtilityBus::Events::ResetEntityContext);
|
||||
|
||||
entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
ASSERT_EQ(entity, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, CreateEntityEmptyName)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("")
|
||||
)LUA");
|
||||
|
||||
EXPECT_NE(g_globalEntityId, AZ::EntityId{});
|
||||
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
ASSERT_NE(entity, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, FindComponent)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0 TransformComponent")
|
||||
)LUA");
|
||||
|
||||
EXPECT_TRUE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, InvalidComponentName)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "ThisIsNotAComponent-Error")
|
||||
)LUA");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
EXPECT_FALSE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, InvalidComponentId)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "{1234-hello-world-this-is-not-an-id}")
|
||||
)LUA");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // Should get 1 error stating the type id is not valid
|
||||
EXPECT_FALSE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, CreateComponent)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
ent_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
g_globalComponentId = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(ent_id, "ScriptEditorComponent")
|
||||
)LUA");
|
||||
|
||||
EXPECT_TRUE(g_globalComponentId.IsValid());
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, UpdateComponent)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalEntityId = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
comp_id = EntityUtilityBus.Broadcast.GetOrAddComponentByTypeName(g_globalEntityId, "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent")
|
||||
json_update = [[
|
||||
{
|
||||
"Transform Data": { "Rotate": [0.0, 0.1, 180.0] }
|
||||
}
|
||||
]]
|
||||
g_globalBool = EntityUtilityBus.Broadcast.UpdateComponentForEntity(g_globalEntityId, comp_id, json_update);
|
||||
)LUA");
|
||||
|
||||
EXPECT_TRUE(g_globalBool);
|
||||
EXPECT_NE(g_globalEntityId, AZ::EntityId(AZ::EntityId::InvalidEntityId));
|
||||
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(g_globalEntityId);
|
||||
|
||||
auto* transformComponent = entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
|
||||
ASSERT_NE(transformComponent, nullptr);
|
||||
|
||||
AZ::Vector3 localRotation = transformComponent->GetLocalRotationQuaternion().GetEulerDegrees();
|
||||
|
||||
EXPECT_EQ(localRotation, AZ::Vector3(.0f, 0.1f, 180.0f));
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, GetComponentJson)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalString = EntityUtilityBus.Broadcast.GetComponentDefaultJson("ScriptEditorComponent")
|
||||
)LUA");
|
||||
|
||||
EXPECT_STRNE(g_globalString.c_str(), "");
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, GetComponentJsonDoesNotExist)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
g_globalString = EntityUtilityBus.Broadcast.GetComponentDefaultJson("404")
|
||||
)LUA");
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 error: Failed to find component id for type name 404
|
||||
|
||||
EXPECT_STREQ(g_globalString.c_str(), "");
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, SearchComponents)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalComponentDetails = EntityUtilityBus.Broadcast.FindMatchingComponents("Transform*")
|
||||
)LUA");
|
||||
|
||||
// There should be 2 transform components
|
||||
EXPECT_EQ(g_globalComponentDetails.size(), 2);
|
||||
}
|
||||
|
||||
TEST_F(EntityUtilityComponentTests, SearchComponentsNotFound)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
g_globalComponentDetails = EntityUtilityBus.Broadcast.FindMatchingComponents("404")
|
||||
)LUA");
|
||||
|
||||
EXPECT_EQ(g_globalComponentDetails.size(), 0);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace UnitTest
|
||||
R"X(Executing RC.EXE: '"E:\lyengine\dev\windows\bin\profile\rc.exe" "E:/Directory/File.tga")X",
|
||||
R"X(Executing RC.EXE with working directory : '')X",
|
||||
R"X(ResourceCompiler 64 - bit DEBUG)X",
|
||||
R"X(Platform support : PC, PowerVR, etc2Comp)X",
|
||||
R"X(Platform support : PC, PowerVR)X",
|
||||
R"X(Version 1.1.8.6 Nov 5 2018 13 : 28 : 28)X"
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
#include <Entity/EntityUtilityComponent.h>
|
||||
|
||||
#include <Prefab/PrefabTestComponent.h>
|
||||
#include <Prefab/PrefabTestDomUtils.h>
|
||||
#include <Prefab/PrefabTestFixture.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
TemplateId g_globalTemplateId = {};
|
||||
AZStd::string g_globalPrefabString = "";
|
||||
|
||||
class PrefabScriptingTest : public PrefabTestFixture
|
||||
{
|
||||
void InitProperties() const
|
||||
{
|
||||
AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
|
||||
ASSERT_NE(componentApplicationRequests, nullptr);
|
||||
|
||||
auto behaviorContext = componentApplicationRequests->GetBehaviorContext();
|
||||
|
||||
ASSERT_NE(behaviorContext, nullptr);
|
||||
|
||||
behaviorContext->Property("g_globalTemplateId", BehaviorValueProperty(&g_globalTemplateId));
|
||||
behaviorContext->Property("g_globalPrefabString", BehaviorValueProperty(&g_globalPrefabString));
|
||||
|
||||
g_globalTemplateId = TemplateId{};
|
||||
g_globalPrefabString = AZStd::string{};
|
||||
}
|
||||
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
InitProperties();
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
{
|
||||
g_globalPrefabString.set_capacity(0); // Free all memory
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PrefabScriptingTest, PrefabScripting_CreatePrefab)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
entities = vector_EntityId()
|
||||
entities:push_back(my_id)
|
||||
g_globalTemplateId = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "test.prefab")
|
||||
)LUA");
|
||||
|
||||
EXPECT_NE(g_globalTemplateId, TemplateId{});
|
||||
|
||||
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
|
||||
ASSERT_NE(prefabSystemComponentInterface, nullptr);
|
||||
|
||||
TemplateReference templateRef = prefabSystemComponentInterface->FindTemplate(g_globalTemplateId);
|
||||
|
||||
EXPECT_TRUE(templateRef);
|
||||
}
|
||||
|
||||
TEST_F(PrefabScriptingTest, PrefabScripting_CreatePrefab_NoEntities)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
entities = vector_EntityId()
|
||||
g_globalTemplateId = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "test.prefab")
|
||||
)LUA");
|
||||
|
||||
EXPECT_NE(g_globalTemplateId, TemplateId{});
|
||||
|
||||
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
|
||||
ASSERT_NE(prefabSystemComponentInterface, nullptr);
|
||||
|
||||
TemplateReference templateRef = prefabSystemComponentInterface->FindTemplate(g_globalTemplateId);
|
||||
|
||||
EXPECT_TRUE(templateRef);
|
||||
}
|
||||
|
||||
TEST_F(PrefabScriptingTest, PrefabScripting_CreatePrefab_NoPath)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
sc.Execute(R"LUA(
|
||||
my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
entities = vector_EntityId()
|
||||
template_id = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "")
|
||||
)LUA");
|
||||
/*
|
||||
error: PrefabSystemComponent::CreateTemplateFromInstance - Attempted to create a prefab template from an instance without a source file path. Unable to proceed.
|
||||
error: Failed to create a Template associated with file path during CreatePrefab.
|
||||
error: Failed to create prefab
|
||||
*/
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(3);
|
||||
}
|
||||
|
||||
TEST_F(PrefabScriptingTest, PrefabScripting_SaveToString)
|
||||
{
|
||||
AZ::ScriptContext sc;
|
||||
auto behaviorContext = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->GetBehaviorContext();
|
||||
|
||||
sc.BindTo(behaviorContext);
|
||||
sc.Execute(R"LUA(
|
||||
my_id = EntityUtilityBus.Broadcast.CreateEditorReadyEntity("test")
|
||||
entities = vector_EntityId()
|
||||
entities:push_back(my_id)
|
||||
template_id = PrefabSystemScriptingBus.Broadcast.CreatePrefab(entities, "test.prefab")
|
||||
my_result = PrefabLoaderScriptingBus.Broadcast.SaveTemplateToString(template_id)
|
||||
|
||||
if my_result:IsSuccess() then
|
||||
g_globalPrefabString = my_result:GetValue()
|
||||
end
|
||||
)LUA");
|
||||
|
||||
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
prefabSystemComponentInterface->RemoveAllTemplates();
|
||||
|
||||
EXPECT_STRNE(g_globalPrefabString.c_str(), "");
|
||||
TemplateId templateFromString = AZ::Interface<PrefabLoaderInterface>::Get()->LoadTemplateFromString(g_globalPrefabString);
|
||||
|
||||
EXPECT_NE(templateFromString, InvalidTemplateId);
|
||||
|
||||
// Create another entity for comparison purposes
|
||||
AZ::EntityId entityId;
|
||||
AzToolsFramework::EntityUtilityBus::BroadcastResult(
|
||||
entityId, &AzToolsFramework::EntityUtilityBus::Events::CreateEditorReadyEntity, "test");
|
||||
|
||||
AZ::Entity* testEntity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
|
||||
|
||||
// Instantiate the prefab we saved
|
||||
AZStd::unique_ptr<Instance> instance = prefabSystemComponentInterface->InstantiatePrefab(templateFromString);
|
||||
|
||||
EXPECT_NE(instance, nullptr);
|
||||
|
||||
AZStd::vector<const AZ::Entity*> loadedEntities;
|
||||
|
||||
// Get the entities from the instance
|
||||
instance->GetConstEntities(
|
||||
[&loadedEntities](const AZ::Entity& entity)
|
||||
{
|
||||
loadedEntities.push_back(&entity);
|
||||
return true;
|
||||
});
|
||||
|
||||
// Make sure the instance has an entity with the same number of components as our test entity
|
||||
EXPECT_EQ(loadedEntities.size(), 1);
|
||||
EXPECT_EQ(loadedEntities[0]->GetComponents().size(), testEntity->GetComponents().size());
|
||||
|
||||
g_globalPrefabString.set_capacity(0); // Free all memory
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
#include <Entity/EntityUtilityComponent.h>
|
||||
|
||||
#include <Prefab/PrefabTestComponent.h>
|
||||
#include <Prefab/PrefabTestDomUtils.h>
|
||||
#include <Prefab/PrefabTestFixture.h>
|
||||
#include <Prefab/Procedural/ProceduralPrefabAsset.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class ProceduralPrefabAssetTest
|
||||
: public PrefabTestFixture
|
||||
{
|
||||
void SetUpEditorFixtureImpl() override
|
||||
{
|
||||
AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
ASSERT_NE(componentApplicationRequests, nullptr);
|
||||
|
||||
auto* behaviorContext = componentApplicationRequests->GetBehaviorContext();
|
||||
ASSERT_NE(behaviorContext, nullptr);
|
||||
|
||||
auto* jsonRegistrationContext = componentApplicationRequests->GetJsonRegistrationContext();
|
||||
ASSERT_NE(jsonRegistrationContext, nullptr);
|
||||
|
||||
auto* serializeContext = componentApplicationRequests->GetSerializeContext();
|
||||
ASSERT_NE(serializeContext, nullptr);
|
||||
|
||||
AZ::Prefab::ProceduralPrefabAsset::Reflect(serializeContext);
|
||||
AZ::Prefab::ProceduralPrefabAsset::Reflect(behaviorContext);
|
||||
AZ::Prefab::ProceduralPrefabAsset::Reflect(jsonRegistrationContext);
|
||||
}
|
||||
|
||||
void TearDownEditorFixtureImpl() override
|
||||
{
|
||||
AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
componentApplicationRequests->GetJsonRegistrationContext()->EnableRemoveReflection();
|
||||
AZ::Prefab::ProceduralPrefabAsset::Reflect(componentApplicationRequests->GetJsonRegistrationContext());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ProceduralPrefabAssetTest, ReflectContext_AccessMethods_Works)
|
||||
{
|
||||
AZ::ComponentApplicationRequests* componentApplicationRequests = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
|
||||
auto* serializeContext = componentApplicationRequests->GetSerializeContext();
|
||||
EXPECT_TRUE(!serializeContext->CreateAny(azrtti_typeid<AZ::Prefab::ProceduralPrefabAsset>()).empty());
|
||||
EXPECT_TRUE(!serializeContext->CreateAny(azrtti_typeid<AZ::Prefab::PrefabDomData>()).empty());
|
||||
|
||||
auto* jsonRegistrationContext = componentApplicationRequests->GetJsonRegistrationContext();
|
||||
EXPECT_TRUE(jsonRegistrationContext->GetSerializerForSerializerType(azrtti_typeid<AZ::Prefab::PrefabDomDataJsonSerializer>()));
|
||||
}
|
||||
|
||||
TEST_F(ProceduralPrefabAssetTest, ProceduralPrefabAsset_AccessMethods_Works)
|
||||
{
|
||||
const auto templateId = TemplateId(1);
|
||||
const auto prefabString = "fake.prefab";
|
||||
|
||||
AZ::Prefab::ProceduralPrefabAsset asset{};
|
||||
asset.SetTemplateId(templateId);
|
||||
EXPECT_EQ(asset.GetTemplateId(), templateId);
|
||||
|
||||
asset.SetTemplateName(prefabString);
|
||||
EXPECT_EQ(asset.GetTemplateName(), prefabString);
|
||||
}
|
||||
|
||||
TEST_F(ProceduralPrefabAssetTest, PrefabDomData_AccessMethods_Works)
|
||||
{
|
||||
AzToolsFramework::Prefab::PrefabDom dom;
|
||||
dom.SetObject();
|
||||
dom.AddMember("boolValue", true, dom.GetAllocator());
|
||||
|
||||
AZ::Prefab::PrefabDomData prefabDomData;
|
||||
prefabDomData.CopyValue(dom);
|
||||
|
||||
const AzToolsFramework::Prefab::PrefabDom& result = prefabDomData.GetValue();
|
||||
EXPECT_TRUE(result.HasMember("boolValue"));
|
||||
EXPECT_TRUE(result.FindMember("boolValue")->value.GetBool());
|
||||
}
|
||||
|
||||
TEST_F(ProceduralPrefabAssetTest, PrefabDomDataJsonSerializer_Load_Works)
|
||||
{
|
||||
AZ::Prefab::PrefabDomData prefabDomData;
|
||||
|
||||
AzToolsFramework::Prefab::PrefabDom dom;
|
||||
dom.SetObject();
|
||||
dom.AddMember("member", "value", dom.GetAllocator());
|
||||
|
||||
AZ::Prefab::PrefabDomDataJsonSerializer prefabDomDataJsonSerializer;
|
||||
AZ::JsonDeserializerSettings settings;
|
||||
settings.m_reporting = [](auto, auto, auto)
|
||||
{
|
||||
AZ::JsonSerializationResult::ResultCode result(AZ::JsonSerializationResult::Tasks::ReadField);
|
||||
return result;
|
||||
};
|
||||
AZ::JsonDeserializerContext context{ settings };
|
||||
|
||||
auto result = prefabDomDataJsonSerializer.Load(&prefabDomData, azrtti_typeid(prefabDomData), dom, context);
|
||||
EXPECT_EQ(result.GetResultCode().GetOutcome(), AZ::JsonSerializationResult::Outcomes::DefaultsUsed);
|
||||
EXPECT_TRUE(prefabDomData.GetValue().HasMember("member"));
|
||||
EXPECT_STREQ(prefabDomData.GetValue().FindMember("member")->value.GetString(), "value");
|
||||
}
|
||||
|
||||
TEST_F(ProceduralPrefabAssetTest, PrefabDomDataJsonSerializer_Store_Works)
|
||||
{
|
||||
AzToolsFramework::Prefab::PrefabDom dom;
|
||||
dom.SetObject();
|
||||
dom.AddMember("member", "value", dom.GetAllocator());
|
||||
|
||||
AZ::Prefab::PrefabDomData prefabDomData;
|
||||
prefabDomData.CopyValue(dom);
|
||||
|
||||
AZ::Prefab::PrefabDomDataJsonSerializer prefabDomDataJsonSerializer;
|
||||
AzToolsFramework::Prefab::PrefabDom outputValue;
|
||||
AZ::JsonSerializerSettings settings;
|
||||
settings.m_reporting = [](auto, auto, auto)
|
||||
{
|
||||
AZ::JsonSerializationResult::ResultCode result(AZ::JsonSerializationResult::Tasks::WriteValue);
|
||||
return result;
|
||||
};
|
||||
AZ::JsonSerializerContext context{ settings, outputValue.GetAllocator() };
|
||||
auto result = prefabDomDataJsonSerializer.Store(outputValue, &prefabDomData, nullptr, azrtti_typeid(prefabDomData), context);
|
||||
EXPECT_EQ(result.GetResultCode().GetOutcome(), AZ::JsonSerializationResult::Outcomes::DefaultsUsed);
|
||||
EXPECT_TRUE(outputValue.HasMember("member"));
|
||||
EXPECT_STREQ(outputValue.FindMember("member")->value.GetString(), "value");
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ set(FILES
|
||||
Entity/EditorEntityHelpersTests.cpp
|
||||
Entity/EditorEntitySearchComponentTests.cpp
|
||||
Entity/EditorEntitySelectionTests.cpp
|
||||
Entity/EntityUtilityComponentTests.cpp
|
||||
EntityIdQLabelTests.cpp
|
||||
EntityInspectorTests.cpp
|
||||
EntityOwnershipService/EntityOwnershipServiceTestFixture.cpp
|
||||
@@ -91,6 +92,8 @@ set(FILES
|
||||
Prefab/SpawnableSortEntitiesTestFixture.cpp
|
||||
Prefab/SpawnableSortEntitiesTestFixture.h
|
||||
Prefab/SpawnableSortEntitiesTests.cpp
|
||||
Prefab/PrefabScriptingTests.cpp
|
||||
Prefab/ProceduralPrefabAssetTests.cpp
|
||||
PropertyIntCtrlCommonTests.h
|
||||
PropertyIntSliderCtrlTests.cpp
|
||||
PropertyIntSpinCtrlTests.cpp
|
||||
|
||||
Reference in New Issue
Block a user