Integrating latest 47acbe8

This commit is contained in:
alexpete
2021-03-25 13:57:57 -07:00
parent 448c549698
commit 75dc720198
10312 changed files with 2711566 additions and 671451 deletions
@@ -61,6 +61,7 @@
#include <AzFramework/Archive/ArchiveFileIO.h>
#include <AzFramework/Script/ScriptRemoteDebugging.h>
#include <AzFramework/Script/ScriptComponent.h>
#include <AzFramework/Spawnable/SpawnableSystemComponent.h>
#include <AzFramework/StreamingInstall/StreamingInstall.h>
#include <AzFramework/TargetManagement/TargetManagementComponent.h>
#include <AzFramework/Viewport/CameraState.h>
@@ -407,6 +408,7 @@ namespace AzFramework
azrtti_typeid<AzFramework::InputSystemComponent>(),
azrtti_typeid<AzFramework::DrillerNetworkAgentComponent>(),
azrtti_typeid<AzFramework::StreamingInstall::StreamingInstallSystemComponent>(),
azrtti_typeid<AzFramework::SpawnableSystemComponent>(),
AZ::Uuid("{624a7be2-3c7e-4119-aee2-1db2bdb6cc89}"), // ScriptDebugAgent
});
@@ -28,6 +28,7 @@
#include <AzFramework/Scene/SceneSystemComponent.h>
#include <AzFramework/Script/ScriptComponent.h>
#include <AzFramework/Script/ScriptRemoteDebugging.h>
#include <AzFramework/Spawnable/SpawnableSystemComponent.h>
#include <AzFramework/StreamingInstall/StreamingInstall.h>
#include <AzFramework/TargetManagement/TargetManagementComponent.h>
#include <AzFramework/Visibility/OctreeSystemComponent.h>
@@ -63,6 +64,7 @@ namespace AzFramework
AzFramework::AzFrameworkConfigurationSystemComponent::CreateDescriptor(),
AzFramework::OctreeSystemComponent::CreateDescriptor(),
AzFramework::SpawnableSystemComponent::CreateDescriptor(),
});
}
@@ -57,7 +57,7 @@ namespace AzFramework
{
Scene* scene = createSceneOutcome.GetValue();
bool success = false;
EntityContextId gameEntityContextId;
EntityContextId gameEntityContextId = EntityContextId::CreateNull();
GameEntityContextRequestBus::BroadcastResult(gameEntityContextId, &GameEntityContextRequests::GetGameEntityContextId);
if (!gameEntityContextId.IsNull())
@@ -12,6 +12,8 @@
#include <AzFramework/Components/NonUniformScaleComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Math/ToString.h>
#include <AzCore/Component/Entity.h>
namespace AzFramework
{
@@ -33,7 +35,6 @@ namespace AzFramework
void NonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("SkyCloudService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
@@ -49,8 +50,6 @@ namespace AzFramework
incompatible.push_back(AZ_CRC_CE("PhysXShapeColliderService"));
incompatible.push_back(AZ_CRC_CE("PhysXCharacterControllerService"));
incompatible.push_back(AZ_CRC_CE("PhysXRagdollService"));
incompatible.push_back(AZ_CRC_CE("TouchBendingPhysicsService"));
incompatible.push_back(AZ_CRC_CE("WaterVolumeService"));
incompatible.push_back(AZ_CRC_CE("WhiteBoxService"));
incompatible.push_back(AZ_CRC_CE("NavigationAreaService"));
incompatible.push_back(AZ_CRC_CE("GeometryService"));
@@ -58,12 +57,9 @@ namespace AzFramework
incompatible.push_back(AZ_CRC_CE("CompoundShapeService"));
incompatible.push_back(AZ_CRC_CE("CylinderShapeService"));
incompatible.push_back(AZ_CRC_CE("DiskShapeService"));
incompatible.push_back(AZ_CRC_CE("FixedVertexContainerService"));
incompatible.push_back(AZ_CRC_CE("PolygonPrismShapeService"));
incompatible.push_back(AZ_CRC_CE("SphereShapeService"));
incompatible.push_back(AZ_CRC_CE("SplineService"));
incompatible.push_back(AZ_CRC_CE("TubeShapeService"));
incompatible.push_back(AZ_CRC_CE("VariableVertexContainerService"));
}
void NonUniformScaleComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
@@ -88,7 +84,17 @@ namespace AzFramework
void NonUniformScaleComponent::SetScale(const AZ::Vector3& scale)
{
m_scale = scale;
if (scale.GetMinElement() >= AZ::MinNonUniformScale)
{
m_scale = scale;
}
else
{
AZ::Vector3 clampedScale = scale.GetMax(AZ::Vector3(AZ::MinNonUniformScale));
AZ_Warning("Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s",
AZ::ToString(scale).c_str(), AZ::ToString(clampedScale).c_str(), GetEntity()->GetName().c_str());
m_scale = clampedScale;
}
m_scaleChangedEvent.Signal(m_scale);
}
@@ -17,25 +17,23 @@
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Quaternion.h>
#include <AzFramework/Network/NetBindingHandlerBus.h>
#include <AzFramework/Network/NetBindingSystemBus.h>
#include <AzFramework/Network/NetworkContext.h>
#include <GridMate/Replica/ReplicaChunk.h>
#include <GridMate/Replica/ReplicaFunctions.h>
#include <GridMate/Replica/DataSet.h>
#include <GridMate/Serialize/CompressionMarshal.h>
namespace AZ
{
class BehaviorTransformNotificationBusHandler : public TransformNotificationBus::Handler, public AZ::BehaviorEBusHandler
class BehaviorTransformNotificationBusHandler
: public TransformNotificationBus::Handler
, public AZ::BehaviorEBusHandler
{
public:
AZ_EBUS_BEHAVIOR_BINDER(BehaviorTransformNotificationBusHandler, "{9CEF4DAB-F359-4A3E-9856-7780281E0DAA}", AZ::SystemAllocator
, OnTransformChanged
, OnParentChanged
, OnChildAdded
, OnChildRemoved
AZ_EBUS_BEHAVIOR_BINDER
(
BehaviorTransformNotificationBusHandler,
"{9CEF4DAB-F359-4A3E-9856-7780281E0DAA}",
AZ::SystemAllocator,
OnTransformChanged,
OnParentChanged,
OnChildAdded,
OnChildRemoved
);
void OnTransformChanged(const Transform& localTM, const Transform& worldTM) override
@@ -80,109 +78,10 @@ namespace AZ
new(self) TransformConfig();
}
}
} // namespace AZ
namespace AzFramework
{
//=========================================================================
// TransformReplicaChunk
// [3/9/2016]
//=========================================================================
class TransformReplicaChunk
: public GridMate::ReplicaChunkBase
{
public:
AZ_CLASS_ALLOCATOR(TransformReplicaChunk, AZ::SystemAllocator, 0);
static const char* GetChunkName() { return "TransformReplicaChunk"; }
TransformReplicaChunk()
: m_parentId("ParentId")
, m_localTranslation("LocalTranslationData")
, m_localRotation("LocalRotationData")
, m_localScale("LocalScaleData")
{
m_localTranslation.GetThrottler().SetThreshold(AZ::Vector3(0.005f, 0.005f, 0.005f));
m_localScale.GetThrottler().SetThreshold(AZ::Vector3(0.001f, 0.001f, 0.001f));
}
bool IsReplicaMigratable() override
{
return true;
}
void SetInitialTM(const AZ::Transform& t)
{
m_initialWorldTM = t;
}
void SetLocalTM(const AZ::Transform& t)
{
m_localScale.Set(t.GetScale());
m_localTranslation.Set(t.GetTranslation());
m_localRotation.Set(t.GetRotation());
}
AZ::Transform GetLocalTransform() const
{
AZ::Transform newXform;
newXform.SetTranslation(m_localTranslation.Get());
newXform.SetRotation(m_localRotation.Get());
newXform.SetScale(m_localScale.Get());
return newXform;
}
unsigned int GetLocalTime()
{
return GetReplicaManager()->GetTime().m_localTime;
}
// parentId (can have no parent)
DataSet<AZ::u64>::BindInterface<TransformComponent, &TransformComponent::OnNewNetParentData> m_parentId;
// transform
DataSet<AZ::Vector3, GridMate::Marshaler<AZ::Vector3>, GridMate::EpsilonThrottle<AZ::Vector3>>::BindInterface<TransformComponent, &TransformComponent::OnNewPositionData> m_localTranslation;
DataSet<AZ::Quaternion, GridMate::Marshaler<AZ::Quaternion>, GridMate::BasicThrottle<AZ::Quaternion>>::BindInterface<TransformComponent, &TransformComponent::OnNewRotationData> m_localRotation;
DataSet<AZ::Vector3, GridMate::Marshaler<AZ::Vector3>, GridMate::EpsilonThrottle<AZ::Vector3>>::BindInterface<TransformComponent, &TransformComponent::OnNewScaleData> m_localScale;
AZ::Transform m_initialWorldTM;
class Descriptor
: public ExternalChunkDescriptor<TransformReplicaChunk>
{
public:
ReplicaChunkBase* CreateFromStream(UnmarshalContext& context) override
{
// Pre/Post construct allow DataSets and RPCs to bind to the chunk.
TransformReplicaChunk* transformChunk = aznew TransformReplicaChunk;
context.m_iBuf->Read(transformChunk->m_initialWorldTM);
return transformChunk;
}
void DiscardCtorStream(UnmarshalContext& context) override
{
AZ::Transform discard;
context.m_iBuf->Read(discard);
}
void MarshalCtorData(ReplicaChunkBase* chunk, WriteBuffer& wb) override
{
TransformReplicaChunk* transformChunk = static_cast<TransformReplicaChunk*>(chunk);
TransformComponent* transformComponent = static_cast<TransformComponent*>(transformChunk->GetHandler());
if (transformComponent)
{
wb.Write(transformComponent->GetWorldTM());
}
else
{
wb.Write(transformChunk->m_initialWorldTM);
}
}
};
};
//=========================================================================
bool TransformComponentVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
{
if (classElement.GetVersion() < 3)
@@ -204,28 +103,10 @@ namespace AzFramework
// future re-additions of it won't remove it (as long as they bump the version number.)
classElement.RemoveElementByName(AZ_CRC("InterpolateScale", 0x9d00b831));
}
return true;
}
//=========================================================================
// TransformComponent
// [8/9/2013]
//=========================================================================
TransformComponent::TransformComponent()
: m_parentTM(nullptr)
, m_parentActive(false)
, m_onNewParentKeepWorldTM(true)
, m_parentActivationTransformMode(ParentActivationTransformMode::MaintainOriginalRelativeTransform)
, m_isStatic(false)
, m_interpolatePosition(AZ::InterpolationMode::NoInterpolation)
, m_interpolateRotation(AZ::InterpolationMode::NoInterpolation)
{
m_localTM = AZ::Transform::CreateIdentity();
m_worldTM = AZ::Transform::CreateIdentity();
}
TransformComponent::TransformComponent(const TransformComponent& copy)
: m_localTM(copy.m_localTM)
, m_worldTM(copy.m_worldTM)
@@ -235,89 +116,9 @@ namespace AzFramework
, m_notificationBus(nullptr)
, m_onNewParentKeepWorldTM(copy.m_onNewParentKeepWorldTM)
, m_parentActivationTransformMode(copy.m_parentActivationTransformMode)
, m_replicaChunk(nullptr)
, m_isStatic(copy.m_isStatic)
, m_interpolatePosition(copy.m_interpolatePosition)
, m_interpolateRotation(copy.m_interpolateRotation)
, m_netTargetTranslation()
, m_netTargetRotation()
, m_netTargetScale(copy.m_netTargetScale)
{
CreateSamples();
if (copy.m_netTargetTranslation)
{
m_netTargetTranslation->SetNewTarget(copy.m_netTargetTranslation->GetTargetValue(), copy.m_netTargetTranslation->GetTargetTimestamp());
}
if (copy.m_netTargetRotation)
{
m_netTargetRotation->SetNewTarget(copy.m_netTargetRotation->GetTargetValue(), copy.m_netTargetRotation->GetTargetTimestamp());
}
SetSyncEnabled(copy.m_isSyncEnabled);
}
void TransformComponent::CreateTranslationSample()
{
switch(m_interpolatePosition)
{
case AZ::InterpolationMode::LinearInterpolation:
m_netTargetTranslation = AZStd::make_unique<AZ::LinearlyInterpolatedSample<AZ::Vector3>>();
break;
case AZ::InterpolationMode::NoInterpolation:
default:
m_netTargetTranslation = AZStd::make_unique<AZ::UninterpolatedSample<AZ::Vector3>>();
break;
}
}
void TransformComponent::CreateRotationSample()
{
switch (m_interpolateRotation)
{
case AZ::InterpolationMode::LinearInterpolation:
m_netTargetRotation = AZStd::make_unique<AZ::LinearlyInterpolatedSample<AZ::Quaternion>>();
break;
case AZ::InterpolationMode::NoInterpolation:
default:
m_netTargetRotation = AZStd::make_unique<AZ::UninterpolatedSample<AZ::Quaternion>>();
break;
}
}
void TransformComponent::CreateSamples()
{
if (m_netTargetTranslation)
{
auto target = m_netTargetTranslation->GetTargetValue();
auto timeStamp = m_netTargetTranslation->GetTargetTimestamp();
CreateTranslationSample();
m_netTargetTranslation->SetNewTarget(target, timeStamp);
}
else
{
CreateTranslationSample();
}
if (m_netTargetRotation)
{
auto target = m_netTargetRotation->GetTargetValue();
auto timeStamp = m_netTargetRotation->GetTargetTimestamp();
CreateRotationSample();
m_netTargetRotation->SetNewTarget(target, timeStamp);
}
else
{
CreateRotationSample();
}
}
TransformComponent::~TransformComponent()
{
;
}
bool TransformComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
@@ -328,9 +129,6 @@ namespace AzFramework
m_worldTM = config->m_worldTransform;
m_parentId = config->m_parentId;
m_parentActivationTransformMode = config->m_parentActivationTransformMode;
SetSyncEnabled(config->m_netSyncEnabled);
m_interpolatePosition = config->m_interpolatePosition;
m_interpolateRotation = config->m_interpolateRotation;
m_isStatic = config->m_isStatic;
return true;
}
@@ -345,9 +143,6 @@ namespace AzFramework
config->m_worldTransform = m_worldTM;
config->m_parentId = m_parentId;
config->m_parentActivationTransformMode = m_parentActivationTransformMode;
config->m_netSyncEnabled = IsSyncEnabled();
config->m_interpolatePosition = m_interpolatePosition;
config->m_interpolateRotation = m_interpolateRotation;
config->m_isStatic = m_isStatic;
return true;
}
@@ -366,8 +161,11 @@ namespace AzFramework
void TransformComponent::Deactivate()
{
EBUS_EVENT_ID(m_parentId, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId());
UnbindFromNetwork();
auto parentTransform = AZ::TransformBus::FindFirstHandler(m_parentId);
if (parentTransform)
{
parentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId());
}
m_notificationBus = nullptr;
if (m_parentId.IsValid())
@@ -379,12 +177,31 @@ namespace AzFramework
AZ::TransformBus::Handler::BusDisconnect();
}
void TransformComponent::BindTransformChangedEventHandler(AZ::TransformChangedEvent::Handler& handler)
{
handler.Connect(m_transformChangedEvent);
}
void TransformComponent::BindParentChangedEventHandler(AZ::ParentChangedEvent::Handler& handler)
{
handler.Connect(m_parentChangedEvent);
}
void TransformComponent::BindChildChangedEventHandler(AZ::ChildChangedEvent::Handler& handler)
{
handler.Connect(m_childChangedEvent);
}
void TransformComponent::NotifyChildChangedEvent(AZ::ChildChangeType changeType, AZ::EntityId entityId)
{
m_childChangedEvent.Signal(changeType, entityId);
}
void TransformComponent::SetLocalTM(const AZ::Transform& tm)
{
if (AreMoveRequestsAllowed())
{
SetLocalTMImpl(tm);
UpdateReplicaChunk();
}
}
@@ -393,28 +210,17 @@ namespace AzFramework
if (AreMoveRequestsAllowed())
{
SetWorldTMImpl(tm);
UpdateReplicaChunk();
}
}
void TransformComponent::SetParent(AZ::EntityId id)
{
if (!IsNetworkControlled())
{
SetParentImpl(id, true);
UpdateReplicaChunk();
}
SetParentImpl(id, true);
}
void TransformComponent::SetParentRelative(AZ::EntityId id)
{
if (!IsNetworkControlled())
{
SetParentImpl(id, m_isStatic);
UpdateReplicaChunk();
}
SetParentImpl(id, m_isStatic);
}
void TransformComponent::SetWorldTranslation(const AZ::Vector3& newPosition)
@@ -860,267 +666,6 @@ namespace AzFramework
}
void TransformComponent::OnEntityActivated(const AZ::EntityId& parentEntityId)
{
OnEntityActivatedImpl(parentEntityId);
UpdateReplicaChunk();
}
void TransformComponent::OnEntityDeactivated(const AZ::EntityId& parentEntityId)
{
if (!IsNetworkControlled())
{
OnEntityDeactivateImpl(parentEntityId);
UpdateReplicaChunk();
}
else
{
// If this transform is network controlled, then the localTM is updated by the network,
// so update m_parentTM and compute worldTM instead.
AZ_Assert(parentEntityId == m_parentId, "We expect to receive notifications only from the current parent!");
m_parentTM = nullptr;
m_parentActive = false;
ComputeWorldTM();
}
}
GridMate::ReplicaChunkPtr TransformComponent::GetNetworkBinding()
{
TransformReplicaChunk* replicaChunk = GridMate::CreateReplicaChunk<TransformReplicaChunk>();
replicaChunk->SetHandler(this);
m_replicaChunk = replicaChunk;
UpdateReplicaChunk();
return m_replicaChunk;
}
void TransformComponent::SetNetworkBinding(GridMate::ReplicaChunkPtr replicaChunk)
{
AZ_Assert(m_replicaChunk == nullptr, "Being bound to two ReplicaChunks");
bool isTransformChunk = replicaChunk != nullptr;
AZ_Assert(isTransformChunk, "Being bound to invalid chunk type");
if (isTransformChunk)
{
replicaChunk->SetHandler(this);
m_replicaChunk = replicaChunk;
TransformReplicaChunk* transformReplicaChunk = static_cast<TransformReplicaChunk*>(m_replicaChunk.get());
m_parentId = AZ::EntityId(transformReplicaChunk->m_parentId.Get());
m_worldTM = transformReplicaChunk->m_initialWorldTM;
m_localTM = transformReplicaChunk->GetLocalTransform();
CreateSamples();
m_netTargetTranslation->SetNewTarget(
transformReplicaChunk->m_localTranslation.Get(),
transformReplicaChunk->m_localTranslation.GetLastUpdateTime());
m_netTargetRotation->SetNewTarget(
transformReplicaChunk->m_localRotation.Get(),
transformReplicaChunk->m_localRotation.GetLastUpdateTime());
m_netTargetScale = transformReplicaChunk->m_localScale.Get();
if (HasAnyInterpolation())
{
// only connect if interpolation was selected for either position or rotation
AZ::TickBus::Handler::BusConnect();
}
}
m_onNewParentKeepWorldTM = false;
}
void TransformComponent::UnbindFromNetwork()
{
if (HasAnyInterpolation())
{
AZ::TickBus::Handler::BusDisconnect();
}
if (m_replicaChunk)
{
m_replicaChunk->SetHandler(nullptr);
m_replicaChunk = nullptr;
}
}
void TransformComponent::OnNewNetTransformData(const AZ::Transform& transform, const GridMate::TimeContext& /*tc*/)
{
SetLocalTMImpl(transform);
}
void TransformComponent::OnNewNetParentData(const AZ::u64& parentId, const GridMate::TimeContext& /*tc*/)
{
SetParentImpl(AZ::EntityId(parentId), false);
}
bool TransformComponent::IsNetworkControlled() const
{
return m_replicaChunk && m_replicaChunk->GetReplica() && !m_replicaChunk->IsMaster();
}
bool TransformComponent::IsPositionInterpolated()
{
return m_interpolatePosition != AZ::InterpolationMode::NoInterpolation;
}
bool TransformComponent::IsRotationInterpolated()
{
return m_interpolateRotation != AZ::InterpolationMode::NoInterpolation;
}
bool TransformComponent::HasAnyInterpolation()
{
return IsPositionInterpolated() || IsRotationInterpolated();
}
void TransformComponent::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*currentTime*/)
{
if (GetEntity() && GetEntity()->GetState() == AZ::Entity::State::Active)
{
if (m_replicaChunk && m_replicaChunk->IsProxy())
{
const unsigned int localTime = m_replicaChunk->GetReplicaManager()->GetTime().m_localTime;
const AZ::Transform newXform = GetInterpolatedTransform(localTime);
SetLocalTMImpl(newXform);
}
}
}
AZ::Transform TransformComponent::GetInterpolatedTransform(unsigned localTime)
{
const AZ::Vector3 newTranslation = m_netTargetTranslation->GetInterpolatedValue(localTime);
const AZ::Quaternion newRotation = m_netTargetRotation->GetInterpolatedValue(localTime);
AZ::Transform newXform = AZ::Transform::CreateFromQuaternionAndTranslation(newRotation, newTranslation);
newXform.MultiplyByScale(m_netTargetScale);
return newXform;
}
void TransformComponent::OnNewPositionData(const AZ::Vector3& translation, const GridMate::TimeContext& tc)
{
m_netTargetTranslation->SetNewTarget(translation, tc.m_realTime);
if (!HasAnyInterpolation())
{
unsigned int localTime = m_replicaChunk->GetReplicaManager()->GetTime().m_localTime;
AZ::Transform newXform = GetInterpolatedTransform(localTime);
SetLocalTMImpl(newXform);
}
};
void TransformComponent::OnNewRotationData(const AZ::Quaternion& rotation, const GridMate::TimeContext& tc)
{
m_netTargetRotation->SetNewTarget(rotation, tc.m_realTime);
if (!HasAnyInterpolation())
{
unsigned int localTime = m_replicaChunk->GetReplicaManager()->GetTime().m_localTime;
AZ::Transform newXform = GetInterpolatedTransform(localTime);
SetLocalTMImpl(newXform);
}
}
void TransformComponent::OnNewScaleData(const AZ::Vector3& scale, const GridMate::TimeContext& /*tc*/)
{
// no interpolation of scale by design, very unlikely somebody needs it
m_netTargetScale = scale;
}
void TransformComponent::UpdateReplicaChunk()
{
if (!IsNetworkControlled() && m_replicaChunk)
{
TransformReplicaChunk* transformReplicaChunk = static_cast<TransformReplicaChunk*>(m_replicaChunk.get());
transformReplicaChunk->SetLocalTM(GetLocalTM());
transformReplicaChunk->m_parentId.Set(static_cast<AZ::u64>(GetParentId()));
}
}
void TransformComponent::SetParentImpl(AZ::EntityId parentId, bool isKeepWorldTM)
{
if (parentId == GetEntityId())
{
AZ_Warning("TransformComponent", false, "An entity can not be set as its own parent.");
return;
}
AZ::EntityId oldParent = m_parentId;
if (m_parentId.IsValid())
{
AZ::TransformNotificationBus::Handler::BusDisconnect();
AZ::TransformHierarchyInformationBus::Handler::BusDisconnect();
AZ::EntityBus::Handler::BusDisconnect();
m_parentActive = false;
}
m_parentId = parentId;
if (m_parentId.IsValid())
{
AZ::Entity* parentEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(parentEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_parentId);
m_parentActive = parentEntity && (parentEntity->GetState() == AZ::Entity::State::Active);
m_onNewParentKeepWorldTM = isKeepWorldTM;
AZ::TransformNotificationBus::Handler::BusConnect(m_parentId);
AZ::TransformHierarchyInformationBus::Handler::BusConnect(m_parentId);
AZ::EntityBus::Handler::BusConnect(m_parentId);
}
else
{
m_parentTM = nullptr;
if (isKeepWorldTM)
{
SetWorldTM(m_worldTM);
}
else
{
SetLocalTM(m_localTM);
}
if (oldParent.IsValid())
{
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
}
}
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnParentChanged, oldParent, parentId);
if (oldParent != parentId) // Don't send removal notification while activating.
{
EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId());
}
EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId());
}
void TransformComponent::SetLocalTMImpl(const AZ::Transform& tm)
{
m_localTM = tm;
ComputeWorldTM(); // We can user dirty flags and compute it later on demand
}
void TransformComponent::SetWorldTMImpl(const AZ::Transform& tm)
{
m_worldTM = tm;
ComputeLocalTM(); // We can user dirty flags and compute it later on demand
}
void TransformComponent::OnTransformChangedImpl(const AZ::Transform& /*parentLocalTM*/, const AZ::Transform& parentWorldTM)
{
// Called when our parent transform changes
// Ignore the event until we've already derived our local transform.
if (m_parentTM)
{
m_worldTM = parentWorldTM * m_localTM;
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
}
}
void TransformComponent::OnEntityActivatedImpl(const AZ::EntityId& parentEntityId)
{
AZ_Assert(parentEntityId == m_parentId, "We expect to receive notifications only from the current parent!");
@@ -1171,15 +716,109 @@ namespace AzFramework
}
}
void TransformComponent::OnEntityDeactivateImpl(const AZ::EntityId& parentEntityId)
void TransformComponent::OnEntityDeactivated([[maybe_unused]] const AZ::EntityId& parentEntityId)
{
(void)parentEntityId;
AZ_Assert(parentEntityId == m_parentId, "We expect to receive notifications only from the current parent!");
m_parentTM = nullptr;
m_parentActive = false;
ComputeLocalTM();
}
void TransformComponent::SetParentImpl(AZ::EntityId parentId, bool isKeepWorldTM)
{
if (parentId == GetEntityId())
{
AZ_Warning("TransformComponent", false, "An entity can not be set as its own parent.");
return;
}
AZ::EntityId oldParent = m_parentId;
if (m_parentId.IsValid())
{
AZ::TransformNotificationBus::Handler::BusDisconnect();
AZ::TransformHierarchyInformationBus::Handler::BusDisconnect();
AZ::EntityBus::Handler::BusDisconnect();
m_parentActive = false;
}
m_parentId = parentId;
if (m_parentId.IsValid())
{
AZ::Entity* parentEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(parentEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_parentId);
m_parentActive = parentEntity && (parentEntity->GetState() == AZ::Entity::State::Active);
m_onNewParentKeepWorldTM = isKeepWorldTM;
AZ::TransformNotificationBus::Handler::BusConnect(m_parentId);
AZ::TransformHierarchyInformationBus::Handler::BusConnect(m_parentId);
AZ::EntityBus::Handler::BusConnect(m_parentId);
}
else
{
m_parentTM = nullptr;
if (isKeepWorldTM)
{
SetWorldTM(m_worldTM);
}
else
{
SetLocalTM(m_localTM);
}
if (oldParent.IsValid())
{
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
m_transformChangedEvent.Signal(m_localTM, m_worldTM);
}
}
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnParentChanged, oldParent, parentId);
m_parentChangedEvent.Signal(oldParent, parentId);
if (oldParent != parentId) // Don't send removal notification while activating.
{
EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId());
auto oldParentTransform = AZ::TransformBus::FindFirstHandler(oldParent);
if (oldParentTransform)
{
oldParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId());
}
}
EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId());
auto newParentTransform = AZ::TransformBus::FindFirstHandler(parentId);
if (newParentTransform)
{
newParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Added, GetEntityId());
}
}
void TransformComponent::SetLocalTMImpl(const AZ::Transform& tm)
{
m_localTM = tm;
ComputeWorldTM(); // We can user dirty flags and compute it later on demand
}
void TransformComponent::SetWorldTMImpl(const AZ::Transform& tm)
{
m_worldTM = tm;
ComputeLocalTM(); // We can user dirty flags and compute it later on demand
}
void TransformComponent::OnTransformChangedImpl(const AZ::Transform& /*parentLocalTM*/, const AZ::Transform& parentWorldTM)
{
// Called when our parent transform changes
// Ignore the event until we've already derived our local transform.
if (m_parentTM)
{
m_worldTM = parentWorldTM * m_localTM;
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
m_transformChangedEvent.Signal(m_localTM, m_worldTM);
}
}
void TransformComponent::ComputeLocalTM()
{
if (m_parentTM)
@@ -1192,6 +831,7 @@ namespace AzFramework
}
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
m_transformChangedEvent.Signal(m_localTM, m_worldTM);
}
void TransformComponent::ComputeWorldTM()
@@ -1206,15 +846,11 @@ namespace AzFramework
}
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
m_transformChangedEvent.Signal(m_localTM, m_worldTM);
}
bool TransformComponent::AreMoveRequestsAllowed() const
{
if (IsNetworkControlled())
{
return false;
}
// Don't allow static transform to be moved while entity is activated.
// But do allow a static transform to be moved when the entity is deactivated.
if (m_isStatic && m_entity && (m_entity->GetState() > AZ::Entity::State::Init))
@@ -1248,7 +884,7 @@ namespace AzFramework
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflection);
if(behaviorContext)
if (behaviorContext)
{
behaviorContext->EBus<AZ::TransformNotificationBus>("TransformNotificationBus")->
Handler<AZ::BehaviorTransformNotificationBusHandler>();
@@ -1396,26 +1032,8 @@ namespace AzFramework
->Property("parentActivationTransformMode",
[](AZ::TransformConfig* config) { return (int&)(config->m_parentActivationTransformMode); },
[](AZ::TransformConfig* config, const int& i) { config->m_parentActivationTransformMode = (AZ::TransformConfig::ParentActivationTransformMode)i; })
->Property("netSyncEnabled", BehaviorValueProperty(&AZ::TransformConfig::m_netSyncEnabled))
->Property("interpolatePosition",
[](AZ::TransformConfig* config) { return (int&)(config->m_interpolatePosition); },
[](AZ::TransformConfig* config, const int& i) { config->m_interpolatePosition = (AZ::InterpolationMode)i; })
->Property("interpolateRotation",
[](AZ::TransformConfig* config) { return (int&)(config->m_interpolateRotation); },
[](AZ::TransformConfig* config, const int& i) { config->m_interpolateRotation = (AZ::InterpolationMode)i; })
->Property("isStatic", BehaviorValueProperty(&AZ::TransformConfig::m_isStatic))
;
}
NetworkContext* netContext = azrtti_cast<NetworkContext*>(reflection);
if (netContext)
{
netContext->Class<TransformComponent>()
->Chunk<TransformReplicaChunk, TransformReplicaChunk::Descriptor>()
->Field("ParentId", &TransformReplicaChunk::m_parentId)
->Field("LocalTranslationData", &TransformReplicaChunk::m_localTranslation)
->Field("LocalRotationData", &TransformReplicaChunk::m_localRotation)
->Field("LocalScaleData", &TransformReplicaChunk::m_localScale);
}
}
} // namespace AZ
@@ -29,26 +29,20 @@ namespace AzToolsFramework
namespace AzFramework
{
class TransformReplicaChunk;
class GameEntityContextComponent;
/// @deprecated Use AZ::TransformConfig
using TransformComponentConfiguration = AZ::TransformConfig;
//! Fundamental component that describes the entity in 3D space.
//! It is net-bindable. Only local transform is synchronized, so when
//! parented, the parent must properly synchronize its transform as well.
class TransformComponent
: public AZ::Component
, public AZ::EntityBus::Handler
, public AZ::TransformBus::Handler
, public AZ::TransformNotificationBus::Handler
, public AZ::EntityBus::Handler
, public AZ::TickBus::Handler
, private AZ::TransformHierarchyInformationBus::Handler
, public NetBindable
{
friend class TransformReplicaChunk;
public:
AZ_COMPONENT(TransformComponent, AZ::TransformComponentTypeId, NetBindable, AZ::TransformInterface);
@@ -56,11 +50,15 @@ namespace AzFramework
using ParentActivationTransformMode = AZ::TransformConfig::ParentActivationTransformMode;
TransformComponent();
TransformComponent() = default;
TransformComponent(const TransformComponent& copy);
virtual ~TransformComponent();
~TransformComponent() override = default;
// TransformBus events (publicly accessible)
void BindTransformChangedEventHandler(AZ::TransformChangedEvent::Handler& handler) override;
void BindParentChangedEventHandler(AZ::ParentChangedEvent::Handler& handler) override;
void BindChildChangedEventHandler(AZ::ChildChangedEvent::Handler& handler) override;
void NotifyChildChangedEvent(AZ::ChildChangeType changeType, AZ::EntityId entityId) override;
//! Returns true if the tm was set to the local transform.
const AZ::Transform& GetLocalTM() override { return m_localTM; }
//! Returns true if the tm was set to the world transform.
@@ -115,8 +113,6 @@ namespace AzFramework
float GetLocalY() override;
float GetLocalZ() override;
bool IsPositionInterpolated() override;
// Rotation modifiers
void SetRotation(const AZ::Vector3& eulerAnglesRadian) override;
void SetRotationQuaternion(const AZ::Quaternion& quaternion) override;
@@ -148,8 +144,6 @@ namespace AzFramework
AZ::Vector3 GetLocalRotation() override;
AZ::Quaternion GetLocalRotationQuaternion() override;
bool IsRotationInterpolated() override;
// Scale Modifiers
void SetScale(const AZ::Vector3& scale) override;
void SetScaleX(float scaleX) override;
@@ -187,28 +181,6 @@ namespace AzFramework
void OnEntityDeactivated(const AZ::EntityId& parentEntityId) override;
//! @}
//! Methods implementing NetBindable.
//! @{
GridMate::ReplicaChunkPtr GetNetworkBinding() override;
void SetNetworkBinding(GridMate::ReplicaChunkPtr chunk) override;
void UnbindFromNetwork() override;
//! Called by the net chunk when new transform data arrives from the network.
void OnNewNetTransformData(const AZ::Transform& transform, const GridMate::TimeContext& tc);
//! Called by the net chunk when new parent id arrives from the network.
void OnNewNetParentData(const AZ::u64& parentId, const GridMate::TimeContext& tc);
//! Returns true if this instance is non-authoritative.
bool IsNetworkControlled() const;
//! Triggers an update of the chunk data. Should only be called on the authoritative instance.
void UpdateReplicaChunk();
//! @}
// AZ::TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
//////////////////////////////////////////////////////////////////////////
// Actual Implementation Functions
// They are protected so we can gate them when network-controlled
@@ -216,8 +188,6 @@ namespace AzFramework
void SetLocalTMImpl(const AZ::Transform& tm);
void SetWorldTMImpl(const AZ::Transform& tm);
void OnTransformChangedImpl(const AZ::Transform& parentLocalTM, const AZ::Transform& parentWorldTM);
void OnEntityActivatedImpl(const AZ::EntityId& parentEntityId);
void OnEntityDeactivateImpl(const AZ::EntityId& parentEntityId);
void ComputeLocalTM();
void ComputeWorldTM();
//////////////////////////////////////////////////////////////////////////
@@ -228,44 +198,31 @@ namespace AzFramework
// TransformHierarchyInformationBus
void GatherChildren(AZStd::vector<AZ::EntityId>& children) override;
//! Feedback from corresponding replica chunk.
//! @{
void OnNewPositionData(const AZ::Vector3&, const GridMate::TimeContext&);
void OnNewRotationData(const AZ::Quaternion&, const GridMate::TimeContext&);
void OnNewScaleData(const AZ::Vector3&, const GridMate::TimeContext&);
//! @}
/// \ref ComponentDescriptor::GetProvidedServices
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
/// \ref ComponentDescriptor::Reflect
static void Reflect(AZ::ReflectContext* reflection);
AZ::Transform m_localTM; ///< Local transform relative to parent transform (same as worldTM if no parent).
AZ::Transform m_worldTM; ///< World transform including parent transform (same as localTM if no parent).
AZ::EntityId m_parentId; ///< If valid, this transform is parented to m_parentId.
AZ::TransformInterface* m_parentTM; ///< Cached - pointer to parent transform, to avoid extra calls. Valid only when if it's present.
bool m_parentActive; ///< Keeps track of the state of the parent entity.
AZ::TransformNotificationBus::BusPtr m_notificationBus; ///< Cached bus pointer to the notification bus.
bool m_onNewParentKeepWorldTM; ///< If set, recompute localTM instead of worldTM when parent becomes active.
ParentActivationTransformMode m_parentActivationTransformMode;
GridMate::ReplicaChunkPtr m_replicaChunk;
bool m_isStatic; ///< If true, the transform is static and doesn't move while entity is active.
AZ::InterpolationMode m_interpolatePosition; ///< Interpolation mode for net-synced position updates.
AZ::InterpolationMode m_interpolateRotation; ///< Interpolation mode for net-synced rotation updates.
AZ::TransformChangedEvent m_transformChangedEvent; ///< Event used to signal when a transform changes.
AZ::ParentChangedEvent m_parentChangedEvent; ///< Event used to signal when a transforms parent changes.
AZ::ChildChangedEvent m_childChangedEvent; ///< Event used to signal when a transform has a child entity added or removed.
private:
AZ::Transform m_localTM = AZ::Transform::CreateIdentity(); ///< Local transform relative to parent transform (same as worldTM if no parent).
AZ::Transform m_worldTM = AZ::Transform::CreateIdentity(); ///< World transform including parent transform (same as localTM if no parent).
bool HasAnyInterpolation();
AZ::EntityId m_parentId; ///< If valid, this transform is parented to m_parentId.
AZ::TransformInterface* m_parentTM = nullptr; ///< Cached - pointer to parent transform, to avoid extra calls. Valid only when if it's present.
AZ::TransformNotificationBus::BusPtr m_notificationBus; ///< Cached bus pointer to the notification bus.
ParentActivationTransformMode m_parentActivationTransformMode = ParentActivationTransformMode::MaintainOriginalRelativeTransform;
bool m_parentActive = false; ///< Keeps track of the state of the parent entity.
bool m_onNewParentKeepWorldTM = true; ///< If set, recompute localTM instead of worldTM when parent becomes active.
bool m_isStatic = false; ///< If true, the transform is static and doesn't move while entity is active.
void CreateSamples();
void CreateTranslationSample();
void CreateRotationSample();
AZ::Transform GetInterpolatedTransform(unsigned int localTime);
AZStd::unique_ptr<AZ::Sample<AZ::Vector3>> m_netTargetTranslation;
AZStd::unique_ptr<AZ::Sample<AZ::Quaternion>> m_netTargetRotation;
AZ::Vector3 m_netTargetScale;
//! @deprecated
//! @{
AZ::InterpolationMode m_interpolatePosition = AZ::InterpolationMode::NoInterpolation;
AZ::InterpolationMode m_interpolateRotation = AZ::InterpolationMode::NoInterpolation;
//! @}
};
} // namespace AZ
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/Engine/Engine.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Utils/Utils.h>
namespace AzFramework
{
namespace Engine
{
AZ::IO::FixedMaxPath FindEngineRoot(AZStd::string_view searchPath)
{
// File to locate
const char engineRootMarker[] = "engine.json";
AZ::IO::FixedMaxPath currentSearchPath{searchPath};
if (currentSearchPath.empty())
{
char executablePath[AZ_MAX_PATH_LEN];
AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executablePath, AZ_MAX_PATH_LEN);
currentSearchPath = executablePath;
}
do
{
currentSearchPath = currentSearchPath.ParentPath();
if (AZ::IO::SystemFile::Exists((currentSearchPath / engineRootMarker).c_str()))
{
return currentSearchPath;
}
} while (currentSearchPath.ParentPath() != currentSearchPath);
return {};
}
}
} // AzFramework
@@ -0,0 +1,25 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/IO/Path/Path.h>
#include <AzCore/std/string/string_view.h>
namespace AzFramework
{
namespace Engine
{
// Helper to attempt to locate the engine root by searching up the directory tree. If no search path is
// provided the current executable path is used
AZ::IO::FixedMaxPath FindEngineRoot(AZStd::string_view searchPath = {});
} // Engine
} // AzFramework
@@ -93,6 +93,8 @@ namespace AzFramework
virtual void SetEntitiesRemovedCallback(OnEntitiesRemovedCallback onEntitiesRemovedCallback) = 0;
virtual void SetValidateEntitiesCallback(ValidateEntitiesCallback validateEntitiesCallback) = 0;
bool m_shouldAssertForLegacySlicesUsage = false;
protected:
OnEntitiesAddedCallback m_entitiesAddedCallback;
OnEntitiesRemovedCallback m_entitiesRemovedCallback;
@@ -19,6 +19,19 @@ namespace AzFramework
using EntityContextId = AZ::Uuid;
using EntityList = AZStd::vector<AZ::Entity*>;
class EntityOwnershipService;
class EntityOwnershipServiceInterface
{
public:
AZ_RTTI(EntityOwnershipServiceInterface, "{6490E958-5DF5-45CF-9A25-D857DB0C67DB}");
EntityOwnershipServiceInterface() = default;
virtual ~EntityOwnershipServiceInterface() = default;
virtual AZStd::unique_ptr<EntityOwnershipService> CreateEntityOwnershipService() = 0;
};
class EntityOwnershipServiceNotifications
: public AZ::EBusTraits
{
@@ -1,288 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/Math/Quaternion.h>
namespace Physics
{
constexpr const char * const AZ_TOUCH_BENDING_WINDOW = "AzTouchBending";
// Bone orientation
//
// _ TOP Point Z+ up
// | | ^
// | | |
// |*| (0,0,0) X- <------|--------> X+
// | | |
// |_| BOTTOM Point |
// Z-
/// SpinePoint contains properties of mass, thickness, damping and stiffness
/// for the bone that will be made. The SpinePoint is the BOTTOM point
/// of a Bone.
struct SpinePoint
{
///mass in Kg.
float m_mass;
///If you imagine the Bone to be a cylinder, this is its radius in meters.
float m_thickness;
///A value from 0.0 to 1.0. 0.0 means no damping, lots of back and forth movement around its original pose.
///1.0 means maximum damping, the segment will quickly converge back to its original pose.
float m_damping;
///A value from 0.0 to 1.0. 0.0 means no stiffness, the segment will look like a sad willow,
///It would never return to its original pose.
float m_stiffness;
///Position is in Model Space.
AZ::Vector3 m_position;
};
struct Spine
{
///Index of parent spine. -1 if no parent.
int m_parentSpineIndex;
///Index of the point within the parent spine array of segments.
///-1 if no parent.
int m_parentPointIndex;
///Array of segments.
AZStd::vector<SpinePoint> m_points;
};
typedef void* SpineTreeIDType;
///SpineTree is an archetype. This is basically the AzFramework version
///of CStatObj.SSpine.
struct SpineTree
{
///Unique Identifier Of this SpineTree.
SpineTreeIDType m_spineTreeId;
///A SpineTree ALWAYS contains at least one spine.
AZStd::vector<Spine> m_spines;
///Helper method.
size_t CalculateTotalNumberOfBones() const
{
size_t numberOfBones = 0;
for (const Spine& spine : m_spines)
{
numberOfBones += spine.m_points.size() - 1;
}
return numberOfBones;
}
};
///The Engine side of Touch bending uses this as an opaque handle.
///Only the TouchBending Gem knows what's inside.
///This handle corresponds one-to-one with a unique Vegetation Render Node instance.
struct TouchBendingTriggerHandle;
///The Engine side of Touch bending uses this as an opaque handle.
///Only the TouchBending Gem knows what's inside.
///This handle corresponds one-to-one with a unique CStatObjFoliage instance.
struct TouchBendingSkeletonHandle;
///Used by TouchBending Gem to talk back with the Engine.
class ITouchBendingCallback
{
public:
ITouchBendingCallback() = default;
virtual ~ITouchBendingCallback() = default;
/** @brief Checks if a render node is within e_CullVegActivation radius from the camera
*
* @param privateData Pointer to the Render Node inside the Engine that represents
* the touch bendable entity. From the point of view of the TouchBending Gem this
* is an opaque pointer, but from the point of view of the engine this is a
* CVegetation render node.
* @returns Returns a non-zero SpineTreeIDType if the Render Node is within
* e_CullVegActivation radius from the center of the main camera.
* Otherwise returns zero.
*/
virtual SpineTreeIDType CheckDistanceToCamera(const void* privateData) = 0;
/** @brief Builds a SpineTree archetype object using its SpineTreeIDType.
*
* \p privateData is a CVegetation*
* \p spineTreeId is a CStatObj*
*
* @param privateData Pointer to the Render Node inside the Engine that represents
* the touch bendable entity.
* @param spineTreeId Spine Tree Archetype Identifier as given previously by the Engine.
* @param spineTreeOut Output SpineTree archetype object.
* @returns TRUE if such \p spineTreeId is valid and a SpineTree archetype was successfully built.
* Otherwise returns FALSE.
*/
virtual bool BuildSpineTree(const void* privateData, SpineTreeIDType spineTreeId, SpineTree& spineTreeOut) = 0;
/** TouchBending Gem calls this to notify the Engine that a unique PhysicalizedSkeleton instance was built
* on behalf of \p privateData.
*
* The Engine uses this event to build a CStatObjFoliage to keep track of active touch bendable objects.
* The Engine will keep CStatObjFoliage alive as long as it is touched or for a specific lifetime in seconds
* defined by the CVar e_FoliageBranchesTimeout.
*
* @param privateData Pointer to the Render Node inside the Engine that represents
* the touch bendable entity.
* @param skeletonHandle Opaque pointer that the CStatObjFoliage must keep a copy to. The engine
* should should use it later when calling *Skeleton*() named methods of the TouchBendingBus.
* @returns true if the CStatObjFoliage was created successfully. It may return false only for cases where the CStatObj
* was removed and CStatObjFoliage can only be created if CStatObj is not null.
*/
virtual bool OnPhysicalizedTouchBendingSkeleton(const void* privateData, TouchBendingSkeletonHandle* skeletonHandle) = 0;
}; //class ITouchBendingCallback
//Exact same memory format as QuatTS
//CStatObjFoliage::ComputeSkinningTransformations() uses:
//QuatTS.q[x,y,z] as TOP joint position.
//QuatTS.t[x,y,z] as BOTTOM joint position.
//QuatTS.s CStatObjFoliage::GetSkinningData() reads this value for the first bone of each spine
// as marker for valid data, if less than zero, the spine is skipped by the Skinning code.
// A bone has two joints, TOP and BOTTOM:
//
// _ TOP Z+ up
// | | ^
// | | |
// |*| (0,0,0) X- <------|--------> X+
// | | |
// |_| BOTTOM |
// Z-
struct JointPositions
{
float m_TopJointLocation[3]; //Equivalent to QuatTS.q.xyz (ijk)
float m_qw; //Equivalent to QuatTS.q.w
float m_BottomJointLocation[3]; //Equivalent to QuatTS.t
float m_hasNewData; //Equivalent to QuatTS.s (See description above about CStatObjFoliage::GetSkinningData()).
};
/**
* Replacement of CryPhysics Touch Bending simulation.
*/
class TouchBendingRequest
: public AZ::EBusTraits
{
public:
AZ_RTTI(TouchBendingRequest, "{4E9DE1BE-F0C7-47E7-B315-9302F62D044C}");
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
virtual ~TouchBendingRequest() = default;
/// If the EBUS implementation (aka TouchBending Gem) returns TRUE
/// all of the Physics simulation for Touch Bendable CVegetation is done
/// by the TouchBending Gem with PhysX. If it returns FALSE the engine
/// will default to CryPhysics.
virtual bool IsTouchBendingEnabled() const = 0;
/** @brief Creates a TouchBending Trigger with a simple trigger box.
*
* Initially a TouchBending Trigger is nothing more than a trigger volume. There's
* no skeleton, etc. It will serve as the trigger, that when touched, builds a unique physicalized
* skeleton with the same amount of bones as a SpineTree. Recall that SpineTree is an archetype.
* The TouchBending Gem Builds a TouchBendingSkeletonHandle based on a SpineTree when TouchBendingTriggerHandle is touched.
*
* When the User adds an object via the Vegetation panel of the "Terrain Tool" UI
* this method will be called by the engine.
*
* If the User has enabled the Dynamic Vegetation Gem this method can be called
* at runtime as CVegetation nodes appear within the Camera Frustum.
*
* @param worldTransform This transform includes the scale factor. It is the position of the root
* of the CVegetation node.
* @param worldAabb Axis Aligned Bounding Box in world coordinates of the CVegetation node.
* @param callback The engine gives this callback to the TouchBending Gem for further communication.
* @param callbackPrivateData The Engine gives this opaque handle to TouchBending Gem so the Gem it can properly address it
* address the right Render Node instance when using the \p callback.
* @returns An opaque handle of a TouchBending Trigger Instance created by the TouchBending Gem.
*/
virtual TouchBendingTriggerHandle* CreateTouchBendingTrigger(const AZ::Transform& worldTransform,
const AZ::Aabb&worldAabb, ITouchBendingCallback* callback, const void * callbackPrivateData) = 0;
/** @brief Used by the engine to notify TouchBending Gem about the visibility status of the physicalized skeleton.
*
* @param skeletonHandle Opaque pointer to the physicalized skeleton created by TouchBending Gem.
* @param isVisible if TRUE the engine finds out that the skeleton is visible. If FALSE the engine calculated
* that the skeleton is either totally outside of the Camera Frustum or its distance
* from the camera exceeds the CVAR e_CullVegActivation.
* @param skeletonBoneCountOut It is the responsibility of the TouchBending Gem to fill this out
* with the number of bones available for skinning.
* @param triggerTouchCountOut It is the responsibility of the TouchBending Gem to fill this out
* with the number of objects that are touching the touch bending trigger.
* @returns void
*/
virtual void SetTouchBendingSkeletonVisibility(Physics::TouchBendingSkeletonHandle* skeletonHandle,
bool isVisible, AZ::u32& skeletonBoneCountOut, AZ::u32& triggerTouchCountOut) = 0;
/** @brief The engine calls this when it is deleting the Render Node.
*
* When the User deletes an object via the Vegetation panel of the Rollup Bar (Legacy) UI
* this method will be called by the engine.
*
* If the User has enabled the Dynamic Vegetation Gem this method can be called
* at runtime as CVegetation nodes disappear from the Camera Frustum.
*
* @param handle Opaque handle of the TouchBending trigger instance as created by the
* TouchBending Gem.
* @returns void
*/
virtual void DeleteTouchBendingTrigger(TouchBendingTriggerHandle* handle) = 0;
/** @brief The engine calls this to destroy a physicalized skeleton.
*
* The touch bending trigger remains active.
* This means that in the future something may touch the trigger
* and the skeleton is created again.
*
* @param skeletonHandle Opaque handle of the TouchBending Skeleton as created by the
* TouchBending Gem. The skeleton will be removed from the Physics World.
* @returns
*/
virtual void DephysicalizeTouchBendingSkeleton(TouchBendingSkeletonHandle* skeletonHandle) = 0;
/** Reads the current position of the pair-of-joints per bone of the Skeleton into the \p jointPositions
* buffer.
*
* @param skeletonHandle Opaque handle of the physicalized skeleton instance as created by the
* TouchBending Gem.
* @param jointPositions Buffer where the Top and Bottom Joint positions for each bone
* is written to. Please read the documentation of "struct JointPositions" for clarification.
* @returns void
*/
virtual void ReadJointPositionsOfSkeleton(TouchBendingSkeletonHandle* skeletonHandle, JointPositions* jointPositions) = 0;
};
using TouchBendingBus = AZ::EBus<TouchBendingRequest>;
/// A helper method to test if there's a Gem implementing the TouchBendingBus.
AZ_INLINE bool IsTouchBendingEnabled()
{
bool isEnabled = false;
TouchBendingBus::BroadcastResult(isEnabled, &TouchBendingBus::Events::IsTouchBendingEnabled);
return isEnabled;
}
}
@@ -17,7 +17,7 @@
namespace AzFramework
{
static const char* PlatformNames[PlatformId::NumPlatformIds] = { PlatformPC, PlatformES3, PlatformIOS, PlatformOSX, PlatformXenia, PlatformProvo, PlatformSalem, PlatformJasper, PlatformServer, PlatformAll, PlatformAllClient };
static const char* PlatformNames[PlatformId::NumPlatformIds] = { PlatformPC, PlatformES3, PlatformIOS, PlatformOSX, PlatformProvo, PlatformSalem, PlatformJasper, PlatformServer, PlatformAll, PlatformAllClient };
const char* PlatformIdToPalFolder(AzFramework::PlatformId platform)
{
@@ -35,8 +35,6 @@ namespace AzFramework
return "iOS";
case AzFramework::OSX:
return "Mac";
case AzFramework::XENIA:
return "Xenia";
case AzFramework::PROVO:
return "Provo";
case AzFramework::SALEM:
@@ -84,10 +82,6 @@ namespace AzFramework
{
return PlatformSalem;
}
else if (osPlatform == PlatformCodeNameXenia)
{
return PlatformCodeNameXenia;
}
else if (osPlatform == PlatformCodeNameJasper)
{
return PlatformJasper;
@@ -220,9 +214,6 @@ namespace AzFramework
case PlatformId::OSX:
platformCodes.emplace_back(PlatformCodeNameMac);
break;
case PlatformId::XENIA:
platformCodes.emplace_back(PlatformCodeNameXenia);
break;
case PlatformId::PROVO:
platformCodes.emplace_back(PlatformCodeNameProvo);
break;
@@ -28,7 +28,6 @@ namespace AzFramework
constexpr char PlatformES3[] = "es3";
constexpr char PlatformIOS[] = "ios";
constexpr char PlatformOSX[] = "osx_gl";
constexpr char PlatformXenia[] = "xenia";
constexpr char PlatformProvo[] = "provo";
constexpr char PlatformSalem[] = "salem";
constexpr char PlatformJasper[] = "jasper";
@@ -39,7 +38,6 @@ namespace AzFramework
constexpr char PlatformCodeNameAndroid[] = "Android";
constexpr char PlatformCodeNameiOS[] = "iOS";
constexpr char PlatformCodeNameMac[] = "Mac";
constexpr char PlatformCodeNameXenia[] = "Xenia";
constexpr char PlatformCodeNameProvo[] = "Provo";
constexpr char PlatformCodeNameSalem[] = "Salem";
constexpr char PlatformCodeNameJasper[] = "Jasper";
@@ -57,7 +55,6 @@ namespace AzFramework
ES3,
IOS,
OSX,
XENIA,
PROVO,
SALEM,
JASPER,
@@ -68,7 +65,7 @@ namespace AzFramework
// Add new platforms above this
NumPlatformIds
);
constexpr int NumClientPlatforms = 8;
constexpr int NumClientPlatforms = 7;
constexpr int NumPlatforms = NumClientPlatforms + 1; // 1 "Server" platform currently
enum class PlatformFlags : AZ::u32
{
@@ -77,7 +74,6 @@ namespace AzFramework
Platform_ES3 = 1 << PlatformId::ES3,
Platform_IOS = 1 << PlatformId::IOS,
Platform_OSX = 1 << PlatformId::OSX,
Platform_XENIA = 1 << PlatformId::XENIA,
Platform_PROVO = 1 << PlatformId::PROVO,
Platform_SALEM = 1 << PlatformId::SALEM,
Platform_JASPER = 1 << PlatformId::JASPER,
@@ -89,7 +85,7 @@ namespace AzFramework
// A special platform that will always correspond to all non-server platforms, even if new ones are added
Platform_ALL_CLIENT = 1ULL << 31,
AllNamedPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_XENIA | Platform_PROVO | Platform_SALEM | Platform_JASPER | Platform_SERVER,
AllNamedPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_PROVO | Platform_SALEM | Platform_JASPER | Platform_SERVER,
};
AZ_DEFINE_ENUM_BITWISE_OPERATORS(PlatformFlags);
@@ -0,0 +1,224 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/ProjectManager/ProjectManager.h>
#include <AzFramework/Engine/Engine.h>
#include <AzCore/IO/SystemFile.h>
namespace AzFramework
{
namespace ProjectManager
{
// Check if any project path appears to have been provided on the command line
bool HasCommandLineProjectName(const int argc, char* argv[])
{
constexpr int numOptionPrefixes = 3;
static const char* optionPrefixes[numOptionPrefixes] = { "/", "--", "-" };
constexpr int numOptionNames = 2;
static const char* optionNames[numOptionNames] = { "projectpath", R"(regset="/Amazon/AzCore/Bootstrap/sys_game_folder)" };
for (int i = 1; i < argc; ++i)
{
int thisPrefix = 0;
for (; thisPrefix < numOptionPrefixes; ++thisPrefix)
{
if (strncmp(argv[i], optionPrefixes[thisPrefix], strlen(optionPrefixes[thisPrefix])) == 0)
{
break;
}
}
// If the argument doesn't start with any of our switch start parameters, this isn't an argument giving us a project
if (thisPrefix == numOptionPrefixes)
{
continue;
}
// We compare the portion of the string after our prefix
int startIndex = strlen(optionPrefixes[thisPrefix]);
// If the whole argument was just one of the prefixes, this also isn't what we were looking for
if (startIndex == strlen(argv[i]))
{
continue;
}
int switchNum = 0;
for (; switchNum < numOptionNames; ++switchNum)
{
// Start the string comparison at startIndex for each string - after the option indicator
if (azstrnicmp(&argv[i][startIndex], optionNames[switchNum], strlen(optionNames[switchNum])) == 0)
{
int expectedOptionLength = strlen(optionNames[switchNum]) + startIndex;
// The option is what we're looking for if it had a space after it (it was the whole argument) or it has an equals next
if (strlen(argv[i]) == (expectedOptionLength) || ((strlen(argv[i]) > expectedOptionLength ) && argv[i][expectedOptionLength] == '='))
{
// We found one of the acceptable arguments
return true;
}
}
}
}
return false;
}
// Check for a project name, if not found, attempt to launch project manager and shut down
ProjectPathCheckResult CheckProjectPathProvided(const int argc, char* argv[])
{
// If we were able to locate a path to a project, we're done
if (HasProjectName(argc, argv))
{
return ProjectPathCheckResult::ProjectPathFound;
}
if (LaunchProjectManager())
{
AZ_TracePrintf("ProjectManager", "Project Manager launched successfully, requesting exit.");
return ProjectPathCheckResult::ProjectManagerLaunched;
}
AZ_Error("ProjectManager", false, "Project Manager failed to launch and no project selected!");
return ProjectPathCheckResult::ProjectManagerLaunchFailed;
}
} // ProjectManager
bool ProjectManager::HasProjectName(const int argc, char* argv[])
{
return HasCommandLineProjectName(argc, argv) || HasBootstrapProjectName();
}
// This is a transition method until all projects/tests/etc have been converted to expect and use the projectpath parameter
// If bootstrap.cfg exists and has a valid project name we should assume we're launching using it
// After that time it can be removed
bool ProjectManager::HasBootstrapProjectName(AZStd::string_view projectFolder)
{
AZ::IO::FixedMaxPath enginePath = Engine::FindEngineRoot(projectFolder);
if (enginePath.empty())
{
AZ_Warning("ProjectManager", false, "Couldn't find engine root");
return false;
}
auto bootstrapPath = enginePath / "bootstrap.cfg";
if (!AZ::IO::SystemFile::Exists(bootstrapPath.c_str()))
{
AZ_Warning("ProjectManager", false, "No bootstrap file found at %s", bootstrapPath.c_str());
return false;
}
AZStd::fixed_string< MaxBootstrapFileSize> bootstrapString;
auto fileSize = AZ::IO::SystemFile::Length(bootstrapPath.c_str());
if (fileSize >= MaxBootstrapFileSize)
{
AZ_Warning("ProjectManager", false, "Bootstrap read size at %s is %zu", bootstrapPath.c_str(), fileSize);
bootstrapString.resize_no_construct(MaxBootstrapFileSize);
}
else
{
bootstrapString.resize_no_construct(fileSize);
}
AZ::IO::SystemFile::SizeType bytesRead = AZ::IO::SystemFile::Read(bootstrapPath.c_str(), bootstrapString.data(), MaxBootstrapFileSize - 1);
if (bytesRead == (MaxBootstrapFileSize - 1))
{
AZ_Warning("ProjectManager", false, "Bootstrap read size at %s was %zu", bootstrapPath.c_str(), bytesRead);
}
if (!ContentHasProjectName(bootstrapString))
{
AZ_TracePrintf("ProjectManager", "Bootstrap at %s did not contain project name", bootstrapPath.c_str());
return false;
}
return true;
}
// This is a transition method until all projects/tests/etc have been converted to expect and use the projectpath parameter
// If bootstrap.cfg exists and has a valid project name we should assume we're launching using it
// After that time it can be removed
bool ProjectManager::ContentHasProjectName(AZStd::fixed_string< MaxBootstrapFileSize>& bootstrapString)
{
static const char* const projectKey = "sys_game_folder";
size_t searchStart = bootstrapString.find(projectKey);
while (searchStart != bootstrapString.npos)
{
// Once we've found the key we need to search the line forward and backwards. Commented out lines shouldn't count
// and if there's no value after the equals then it's also not set
auto checkPos = searchStart;
// We're at the start already if this is position 0
bool foundLineStart = checkPos == 0;
if (checkPos)
{
--checkPos;
}
while (checkPos > 0 && bootstrapString[checkPos] != '-')
{
if (bootstrapString[checkPos] == '\n')
{
// Looks like a valid key
foundLineStart = true;
break;
}
if (!std::isspace(bootstrapString[checkPos]))
{
// This appears to be some other character appearing before our key, this isn't valid
break;
}
--checkPos;
}
if (!foundLineStart)
{
// Commented line or other content preceding our key, keep searching
searchStart = bootstrapString.find(projectKey, searchStart + 1);
continue;
}
checkPos = searchStart + strlen(projectKey);
bool foundEquals = false;
while (checkPos < bootstrapString.length())
{
if (bootstrapString[checkPos] == '\n')
{
// We've reached the end of the line and didn't find anything that seems to be a value for our key
break;
}
if (std::isspace(bootstrapString[checkPos]))
{
// Whitespace - keep searching back
++checkPos;
continue;
}
if (bootstrapString[checkPos] == '=')
{
foundEquals = true;
++checkPos;
continue;
}
if (foundEquals)
{
auto nameEnd = bootstrapString.find_first_of(" \n", checkPos);
if (nameEnd == bootstrapString.npos)
{
// End of content, this is valid
nameEnd = bootstrapString.length();
}
constexpr size_t nameMax = 100;
if (nameEnd - checkPos > nameMax)
{
AZ_Warning("ProjectManager", false, "Project name exceeded %zu characters (%zu)", nameMax, nameEnd - checkPos);
return false;
}
AZStd::fixed_string<nameMax + 1> projectName(&bootstrapString[checkPos], nameEnd - checkPos);
AZ_TracePrintf("ProjectManager", "Found project name of %s", projectName.c_str());
// This is not a space, we've found our key, and we've found some sort of non space entry, we count this as "it looks like we have a value entered"
return true;
}
// there was some other content on this line after our key before the equals that was not a space, this isn't our key
searchStart = bootstrapString.find(projectKey, searchStart + 1);
break;
}
searchStart = bootstrapString.find(projectKey, searchStart + 1);
}
return false;
}
} // AzFramework
@@ -0,0 +1,43 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/string/fixed_string.h>
#include <AzCore/std/string/string_view.h>
namespace AzFramework
{
namespace ProjectManager
{
constexpr AZ::IO::SystemFile::SizeType MaxBootstrapFileSize = 1024 * 10;
// Check if any project name can be found anywhere
bool HasProjectName(const int argc, char* argv[]);
// Check if any project name can be found on the command line
bool HasCommandLineProjectName(const int argc, char* argv[]);
// Check if a relative project is being used through bootstrap
bool HasBootstrapProjectName(AZStd::string_view projectFolder = {});
// Search content for project name key
bool ContentHasProjectName(AZStd::fixed_string< MaxBootstrapFileSize>& bootstrapString);
enum class ProjectPathCheckResult
{
ProjectManagerLaunchFailed = -1,
ProjectManagerLaunched = 0,
ProjectPathFound = 1
};
// Check for a project name, if not found, attempts to launch project manager and returns false
ProjectPathCheckResult CheckProjectPathProvided(const int argc, char* argv[]);
// Attempt to Launch the project manager. Requires locating the engine root, project manager script, and python.
bool LaunchProjectManager();
}
} // AzFramework
@@ -0,0 +1,74 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Spawnable/Spawnable.h>
namespace AzFramework
{
Spawnable::Spawnable(const AZ::Data::AssetId& id)
: AZ::Data::AssetData(id)
{
}
Spawnable::Spawnable(Spawnable&& other)
: m_entities(AZStd::move(other.m_entities))
{
}
Spawnable& Spawnable::operator=(Spawnable&& other)
{
if (this != &other)
{
m_entities = AZStd::move(other.m_entities);
}
return *this;
}
const Spawnable::EntityList& Spawnable::GetEntities() const
{
return m_entities;
}
Spawnable::EntityList& Spawnable::GetEntities()
{
return m_entities;
}
bool Spawnable::IsEmpty() const
{
return m_entities.empty();
}
SpawnableMetaData& Spawnable::GetMetaData()
{
return m_metaData;
}
const SpawnableMetaData& Spawnable::GetMetaData() const
{
return m_metaData;
}
void Spawnable::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
{
serializeContext->Class<Spawnable, AZ::Data::AssetData>()->Version(1)
->Field("Meta data", &Spawnable::m_metaData)
->Field("Entities", &Spawnable::m_entities);
}
}
} // namespace AzFramework
@@ -0,0 +1,65 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Spawnable/SpawnableMetaData.h>
namespace AzFramework
{
class ReflectContext;
class Spawnable final
: public AZ::Data::AssetData
{
public:
AZ_CLASS_ALLOCATOR(Spawnable, AZ::SystemAllocator, 0);
AZ_RTTI(AzFramework::Spawnable, "{855E3021-D305-4845-B284-20C3F7FDF16B}", AZ::Data::AssetData);
using EntityList = AZStd::vector<AZStd::unique_ptr<AZ::Entity>>;
inline static constexpr const char* FileExtension = "spawnable";
Spawnable() = default;
explicit Spawnable(const AZ::Data::AssetId& id);
Spawnable(const Spawnable& rhs) = delete;
Spawnable(Spawnable&& other);
~Spawnable() override = default;
Spawnable& operator=(const Spawnable& rhs) = delete;
Spawnable& operator=(Spawnable&& other);
const EntityList& GetEntities() const;
EntityList& GetEntities();
bool IsEmpty() const;
SpawnableMetaData& GetMetaData();
const SpawnableMetaData& GetMetaData() const;
static void Reflect(AZ::ReflectContext* context);
private:
SpawnableMetaData m_metaData;
// Container for keeping all entities of the prefab the Spawnable was created from.
// Includes both direct and nested entities of the prefab.
EntityList m_entities;
};
using SpawnableList = AZStd::vector<Spawnable>;
} // namespace AzFramework
@@ -0,0 +1,91 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Serialization/Utils.h>
#include <AzCore/std/string/string.h>
#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
#include <AzFramework/Spawnable/Spawnable.h>
namespace AzFramework
{
SpawnableAssetHandler::SpawnableAssetHandler()
{
AZ::AssetTypeInfoBus::MultiHandler::BusConnect(AZ::AzTypeInfo<Spawnable>::Uuid());
}
SpawnableAssetHandler::~SpawnableAssetHandler()
{
AZ::AssetTypeInfoBus::MultiHandler::BusDisconnect();
}
AZ::Data::AssetPtr SpawnableAssetHandler::CreateAsset(const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type)
{
AZ_Assert(type == AZ::AzTypeInfo<Spawnable>::Uuid(),
"Asset handler for Spawnable was given a type that's not a Spawnable: %s", type.ToString<AZStd::string>().c_str());
return aznew Spawnable(id);
}
void SpawnableAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
{
delete ptr;
}
void SpawnableAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
{
assetTypes.push_back(AZ::AzTypeInfo<Spawnable>::Uuid());
}
auto SpawnableAssetHandler::LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB) -> LoadResult
{
Spawnable* spawnable = asset.GetAs<Spawnable>();
AZ_Assert(spawnable, "Loaded asset data handed to the SpawnableAssetHandler didn't contain a Spawanble.");
AZ::ObjectStream::FilterDescriptor filter(assetLoadFilterCB);
if (AZ::Utils::LoadObjectFromStreamInPlace(*stream, *spawnable, nullptr /*SerializeContext*/, filter))
{
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
}
else
{
AZ_Error("Spawnable", false, "Failed to deserialize asset %s.", asset->GetId().ToString<AZStd::string>().c_str());
return AZ::Data::AssetHandler::LoadResult::Error;
}
}
AZ::Data::AssetType SpawnableAssetHandler::GetAssetType() const
{
return AZ::AzTypeInfo<Spawnable>::Uuid();
}
const char* SpawnableAssetHandler::GetAssetTypeDisplayName() const
{
return "Spawnable";
}
const char* SpawnableAssetHandler::GetGroup() const
{
return "Prefab";
}
const char* SpawnableAssetHandler::GetBrowserIcon() const
{
return "Editor/Icons/Components/Viewport/EntityInSlice.png";
}
void SpawnableAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
{
extensions.push_back(Spawnable::FileExtension);
}
} // namespace AzFramework
@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Asset/AssetTypeInfoBus.h>
#include <AzCore/Memory/SystemAllocator.h>
namespace AzFramework
{
class SpawnableAssetHandler final
: public AZ::Data::AssetHandler
, public AZ::AssetTypeInfoBus::MultiHandler
{
public:
AZ_CLASS_ALLOCATOR(SpawnableAssetHandler, AZ::SystemAllocator, 0);
AZ_RTTI(AZ::SpawnableAssetHandler, "{BF6E2D17-87C9-4BB1-A205-3656CF6D551D}", AZ::Data::AssetHandler);
SpawnableAssetHandler();
~SpawnableAssetHandler() override;
//
// AssetHandler
//
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
//
// AssetTypeInfoBus
//
AZ::Data::AssetType GetAssetType() const override;
const char* GetAssetTypeDisplayName() const override;
const char* GetGroup() const override;
const char* GetBrowserIcon() const override;
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
protected:
LoadResult LoadAssetData(
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
};
} // namespace AzFramework
@@ -0,0 +1,220 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/ObjectStream.h> // Needed for ObjectStreamWriteOverrideCB and its AZ_TYPE_INFO_SPECIALIZE
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/typetraits/typetraits.h>
#include <AzFramework/Spawnable/SpawnableMetaData.h>
namespace AzFramework
{
SpawnableMetaData::SpawnableMetaData(Table table)
{
AZ_Assert(AZStd::is_sorted(table.begin(), table.end(),
[](const auto& lhs, const auto& rhs)
{
return lhs.first < rhs.first;
}), "The key/value table provided to SpawnableMetaData needs to be sorted by key.");
m_keys.reserve(table.size());
m_values.reserve(table.size());
for (auto&& entry : table)
{
m_keys.push_back(entry.first);
m_values.push_back(AZStd::move(entry.second));
}
}
bool SpawnableMetaData::Get(AZStd::string_view key, bool& value) const
{
return GetGeneric(GetKeyHash(key), value);
}
bool SpawnableMetaData::Get(AZStd::string_view key, uint64_t& value) const
{
return GetGeneric(GetKeyHash(key), value);
}
bool SpawnableMetaData::Get(AZStd::string_view key, int64_t& value) const
{
return GetGeneric(GetKeyHash(key), value);
}
bool SpawnableMetaData::Get(AZStd::string_view key, double& value) const
{
return GetGeneric(GetKeyHash(key), value);
}
bool SpawnableMetaData::Get(AZStd::string_view key, AZStd::string_view& value) const
{
return GetGeneric(GetKeyHash(key), value);
}
bool SpawnableMetaData::Get(AZStd::string_view key, SpawnableMetaDataArraySize& value) const
{
return GetGeneric(GetKeyHash(key), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, uint64_t index, bool& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, uint64_t index, uint64_t& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, uint64_t index, int64_t& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, uint64_t index, double& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, uint64_t index, AZStd::string_view& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, bool& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, uint64_t& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, int64_t& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, double& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
bool SpawnableMetaData::Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, AZStd::string_view& value) const
{
return GetGeneric(GetKeyHash(arrayKey, index), value);
}
auto SpawnableMetaData::GetType(AZStd::string_view key) const -> ValueType
{
return GetTypeGeneric(GetKeyHash(key));
}
auto SpawnableMetaData::GetType(AZStd::string_view arrayKey, uint64_t index) const -> ValueType
{
return GetTypeGeneric(GetKeyHash(arrayKey, index));
}
auto SpawnableMetaData::GetType(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index) const -> ValueType
{
return GetTypeGeneric(GetKeyHash(arrayKey, index));
}
void SpawnableMetaData::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
{
serializeContext->Class<SpawnableMetaData>()->Version(1)
->Field("Keys", &SpawnableMetaData::m_keys)
->Field("Values", &SpawnableMetaData::m_values);
}
}
auto SpawnableMetaData::GetKeyHash(AZStd::string_view key) const -> TableKey
{
return AZ::TypeHash64(reinterpret_cast<const uint8_t*>(key.data()), aznumeric_cast<uint64_t>(key.length()));
}
auto SpawnableMetaData::GetKeyHash(AZStd::string_view arrayKey, uint64_t index) const -> TableKey
{
return AZ::TypeHash64(
reinterpret_cast<const uint8_t*>(arrayKey.data()), aznumeric_cast<uint64_t>(arrayKey.length()),
aznumeric_caster(ArrayKeyRoot + index));
}
auto SpawnableMetaData::GetKeyHash(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index) const -> TableKey
{
return GetKeyHash(arrayKey, aznumeric_cast<uint64_t>(index));
}
template<typename T>
bool SpawnableMetaData::GetGeneric(AZ::HashValue64 key, T& value) const
{
auto it = AZStd::lower_bound(m_keys.begin(), m_keys.end(), key);
if (it != m_keys.end() && *it == key)
{
size_t index = AZStd::distance(m_keys.begin(), it);
if constexpr (AZStd::is_same_v<T, AZStd::string_view>)
{
if (const AZStd::string* storedValue = AZStd::get_if<AZStd::string>(&m_values[index]); storedValue != nullptr)
{
value = *storedValue;
return true;
}
}
else
{
if (const T* storedValue = AZStd::get_if<T>(&m_values[index]); storedValue != nullptr)
{
value = *storedValue;
return true;
}
}
}
return false;
}
auto SpawnableMetaData::GetTypeGeneric(AZ::HashValue64 key) const -> ValueType
{
auto it = AZStd::lower_bound(m_keys.begin(), m_keys.end(), key);
if (it != m_keys.end() && *it == key)
{
size_t index = AZStd::distance(m_keys.begin(), it);
return AZStd::visit([](auto&& args) -> ValueType
{
using Key = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Key, bool>) { return ValueType::Boolean; }
else if constexpr (AZStd::is_same_v<Key, uint64_t>) { return ValueType::UnsignedInteger; }
else if constexpr (AZStd::is_same_v<Key, int64_t>) { return ValueType::SignedInteger; }
else if constexpr (AZStd::is_same_v<Key, double>) { return ValueType::FloatingPoint; }
else if constexpr (AZStd::is_same_v<Key, AZStd::string>){ return ValueType::String; }
else if constexpr (AZStd::is_same_v<Key, SpawnableMetaDataArraySize>)
{
return ValueType::ArraySize;
}
else
{
return ValueType::Unavailable;
}
}, m_values[index]);
}
else
{
return ValueType::Unavailable;
}
}
}; // namespace AzFramework
@@ -0,0 +1,102 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/RTTI/TypeSafeIntegral.h>
#include <AzCore/Utils/TypeHash.h>
#include <AzCore/std/containers/variant.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/utils.h>
namespace AZ
{
class ReflectContext;
}
namespace AzFramework
{
AZ_TYPE_SAFE_INTEGRAL(SpawnableMetaDataArraySize, uint64_t);
using SpawnableMetaDataArrayIndex = SpawnableMetaDataArraySize;
//! Simple meta data that can be stored along with a spawnable.
//! This class is designed to be read-only and is expected to be serialized. AzToolsFramework provides a class for
//! constructing meta data.
class SpawnableMetaData final
{
public:
static inline constexpr uint64_t ArrayKeyRoot = 146223222818353; // Random prime number
using TableKey = AZ::HashValue64;
using TableValue = AZStd::variant<bool, uint64_t, int64_t, double, AZStd::string, SpawnableMetaDataArraySize>;
using TableEntry = AZStd::pair<TableKey, TableValue>;
using Table = AZStd::vector<TableEntry>;
enum class ValueType
{
Unavailable,
Boolean,
UnsignedInteger,
SignedInteger,
FloatingPoint,
String,
ArraySize
};
AZ_TYPE_INFO(AZ::SpawnableMetaData, "{3832FA08-B10B-49AF-A81E-8E2FC1FF98B1}");
SpawnableMetaData() = default;
// This constructor exists only so externally constructed tables can be provided by tools.
explicit SpawnableMetaData(Table table);
bool Get(AZStd::string_view key, bool& value) const;
bool Get(AZStd::string_view key, uint64_t& value) const;
bool Get(AZStd::string_view key, int64_t& value) const;
bool Get(AZStd::string_view key, double& value) const;
bool Get(AZStd::string_view key, AZStd::string_view& value) const;
bool Get(AZStd::string_view key, SpawnableMetaDataArraySize& value) const;
bool Get(AZStd::string_view arrayKey, uint64_t index, bool& value) const;
bool Get(AZStd::string_view arrayKey, uint64_t index, uint64_t& value) const;
bool Get(AZStd::string_view arrayKey, uint64_t index, int64_t& value) const;
bool Get(AZStd::string_view arrayKey, uint64_t index, double& value) const;
bool Get(AZStd::string_view arrayKey, uint64_t index, AZStd::string_view& value) const;
bool Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, bool& value) const;
bool Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, uint64_t& value) const;
bool Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, int64_t& value) const;
bool Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, double& value) const;
bool Get(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index, AZStd::string_view& value) const;
ValueType GetType(AZStd::string_view key) const;
ValueType GetType(AZStd::string_view arrayKey, uint64_t index) const;
ValueType GetType(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index) const;
static void Reflect(AZ::ReflectContext* context);
private:
TableKey GetKeyHash(AZStd::string_view key) const;
TableKey GetKeyHash(AZStd::string_view arrayKey, uint64_t index) const;
TableKey GetKeyHash(AZStd::string_view arrayKey, SpawnableMetaDataArrayIndex index) const;
template<typename T>
bool GetGeneric(AZ::HashValue64 key, T& value) const;
ValueType GetTypeGeneric(AZ::HashValue64 key) const;
AZStd::vector<TableKey> m_keys;
AZStd::vector<TableValue> m_values;
};
} // namespace AzFramework
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(AzFramework::SpawnableMetaDataArraySize);
@@ -0,0 +1,95 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Spawnable/SpawnableMetaData.h>
#include <AzFramework/Spawnable/SpawnableSystemComponent.h>
namespace AzFramework
{
void SpawnableSystemComponent::Reflect(AZ::ReflectContext* context)
{
Spawnable::Reflect(context);
SpawnableMetaData::Reflect(context);
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
{
serializeContext->RegisterGenericType<AZ::Data::Asset<Spawnable>>();
}
}
void SpawnableSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("SpawnableSystemService"));
}
void SpawnableSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("SpawnableSystemService"));
}
void SpawnableSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("AssetDatabaseService"));
services.push_back(AZ_CRC_CE("AssetCatalogService"));
}
void SpawnableSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
{
if (!m_rootSpawnableInitialized)
{
auto registry = AZ::SettingsRegistry::Get();
AZ_Assert(registry, "Unable to check for root spawnable because the Settings Registry is not available.");
if (registry->GetObject(m_rootSpawnable, RootSpawnableRegistryKey) && m_rootSpawnable.GetId().IsValid())
{
AZ_TracePrintf("Spawnables", "Root spawnable '%s' used.\n", m_rootSpawnable.GetHint().c_str());
if (!m_rootSpawnable.QueueLoad())
{
AZ_Error("Spawnables", false, "Unable to queue root spawnable for loading.\n");
}
}
else
{
AZ_Warning("Spawnables", false, "No root spawnable assigned or root spawanble couldnt' be loaded.\n"
"The root spawnable can be assigned in the Settings Registry under the key '$s'.\n", RootSpawnableRegistryKey);
}
m_rootSpawnableInitialized = true;
}
}
void SpawnableSystemComponent::Activate()
{
// Register with AssetDatabase
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Spawnables can't be registered because the Asset Manager is not ready yet.");
AZ::Data::AssetManager::Instance().RegisterHandler(&m_assetHandler, AZ::AzTypeInfo<Spawnable>::Uuid());
// Register with AssetCatalog
AZ::Data::AssetCatalogRequestBus::Broadcast(
&AZ::Data::AssetCatalogRequestBus::Events::EnableCatalogForAsset, AZ::AzTypeInfo<Spawnable>::Uuid());
AZ::Data::AssetCatalogRequestBus::Broadcast(
&AZ::Data::AssetCatalogRequestBus::Events::AddExtension, Spawnable::FileExtension);
AssetCatalogEventBus::Handler::BusConnect();
}
void SpawnableSystemComponent::Deactivate()
{
AssetCatalogEventBus::Handler::BusDisconnect();
AZ_Assert(AZ::Data::AssetManager::IsReady(),
"Spawnables can't be unregistered because the Asset Manager has been destroyed already or never started.");
AZ::Data::AssetManager::Instance().UnregisterHandler(&m_assetHandler);
}
} // namespace AzFramework
@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzFramework/Spawnable/SpawnableAssetHandler.h>
namespace AzFramework
{
class SpawnableSystemComponent
: public AZ::Component
, public AssetCatalogEventBus::Handler
{
public:
AZ_COMPONENT(SpawnableSystemComponent, "{12D0DA52-BB86-4AC3-8862-9493E0D0E207}");
inline static constexpr const char* RootSpawnableRegistryKey = "/Amazon/AzCore/Bootstrap/RootSpawnable";
SpawnableSystemComponent() = default;
SpawnableSystemComponent(const SpawnableSystemComponent&) = delete;
SpawnableSystemComponent(SpawnableSystemComponent&&) = delete;
SpawnableSystemComponent& operator=(const SpawnableSystemComponent&) = delete;
SpawnableSystemComponent& operator=(SpawnableSystemComponent&&) = delete;
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& services);
//
// AssetCatalogEventBus
//
void OnCatalogLoaded(const char* catalogFile) override;
protected:
void Activate() override;
void Deactivate() override;
SpawnableAssetHandler m_assetHandler;
AZ::Data::Asset<Spawnable> m_rootSpawnable;
bool m_rootSpawnableInitialized{ false };
};
} // namespace AzFramework
@@ -12,7 +12,7 @@
#pragma once
#include <AzFramework/Viewport/Viewport.h>
#include <AzFramework/Viewport/ViewportControllerInterface.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/unordered_map.h>
@@ -23,7 +23,12 @@ namespace AzFramework
//! Subclasses of MultiViewportController will be provided with one instance of TViewportControllerInstance
//! per registered viewport, where TViewportControllerInstance must implement the interface of
//! MultiViewportControllerInstance and provide a TViewportControllerInstance(ViewportId) constructor.
template <class TViewportControllerInstance>
//! @param TViewportControllerInstance is the instance type of the controller,
//! one shall be instantiated per registered viewport. This child should conform to the MultiViewportControllerInstanceInterface
//! @param Priority is the priority at which this controller should be dispatched events.
//! Input events may not be received if a higher prioririty controller consumes the event.
//! To receive events at all priorities, DispatchToAllPriorities may be specified.
template <class TViewportControllerInstance, ViewportControllerPriority Priority = ViewportControllerPriority::Normal>
class MultiViewportController
: public ViewportControllerInterface
{
@@ -31,10 +36,11 @@ namespace AzFramework
~MultiViewportController() override;
// ViewportControllerInterface ...
bool HandleInputChannelEvent(ViewportId viewport, const AzFramework::InputChannel& inputChannel) override;
void UpdateViewport(ViewportId viewport, FloatSeconds deltaTime, AZ::ScriptTimePoint time) override;
bool HandleInputChannelEvent(const ViewportControllerInputEvent& event) override;
void UpdateViewport(const ViewportControllerUpdateEvent& event) override;
void RegisterViewportContext(ViewportId viewport) override;
void UnregisterViewportContext(ViewportId viewport) override;
ViewportControllerPriority GetPriority() const override;
private:
AZStd::unordered_map<ViewportId, AZStd::unique_ptr<TViewportControllerInstance>> m_instances;
@@ -45,14 +51,14 @@ namespace AzFramework
{
public:
explicit MultiViewportControllerInstanceInterface(ViewportId viewport)
: m_viewport(viewport)
: m_viewportId(viewport)
{
}
ViewportId GetViewportId() const { return m_viewportId; }
virtual bool HandleInputChannelEvent([[maybe_unused]]const AzFramework::InputChannel& inputChannel) { return false; }
virtual void UpdateViewport([[maybe_unused]]FloatSeconds deltaTime, [[maybe_unused]]AZ::ScriptTimePoint time) {}
virtual bool HandleInputChannelEvent([[maybe_unused]]const ViewportControllerInputEvent& event) { return false; }
virtual void UpdateViewport([[maybe_unused]]const ViewportControllerUpdateEvent& event) {}
private:
ViewportId m_viewportId;
@@ -13,8 +13,8 @@
namespace AzFramework
{
template <class TViewportControllerInstance>
MultiViewportController<TViewportControllerInstance>::~MultiViewportController()
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
MultiViewportController<TViewportControllerInstance, Priority>::~MultiViewportController()
{
static_assert(
AZStd::is_constructible<TViewportControllerInstance, ViewportId>::value,
@@ -22,31 +22,37 @@ namespace AzFramework
);
}
template <class TViewportControllerInstance>
bool MultiViewportController<TViewportControllerInstance>::HandleInputChannelEvent(ViewportId viewport, const AzFramework::InputChannel& inputChannel)
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
bool MultiViewportController<TViewportControllerInstance, Priority>::HandleInputChannelEvent(const ViewportControllerInputEvent& event)
{
auto instanceIt = m_instances.find(viewport);
auto instanceIt = m_instances.find(event.m_viewportId);
AZ_Assert(instanceIt != m_instances.end(), "Attempted to call HandleInputChannelEvent on an unregistered viewport");
return instanceIt->second->HandleInputChannelEvent(inputChannel);
return instanceIt->second->HandleInputChannelEvent(event);
}
template <class TViewportControllerInstance>
void MultiViewportController<TViewportControllerInstance>::UpdateViewport(ViewportId viewport, FloatSeconds deltaTime, AZ::ScriptTimePoint time)
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
void MultiViewportController<TViewportControllerInstance, Priority>::UpdateViewport(const ViewportControllerUpdateEvent& event)
{
auto instanceIt = m_instances.find(viewport);
auto instanceIt = m_instances.find(event.m_viewportId);
AZ_Assert(instanceIt != m_instances.end(), "Attempted to call UpdateViewport on an unregistered viewport");
instanceIt->second->UpdateViewport(deltaTime, time);
instanceIt->second->UpdateViewport(event);
}
template <class TViewportControllerInstance>
void MultiViewportController<TViewportControllerInstance>::RegisterViewportContext(ViewportId viewport)
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
void MultiViewportController<TViewportControllerInstance, Priority>::RegisterViewportContext(ViewportId viewport)
{
m_instances[viewport] = AZStd::make_unique<TViewportControllerInstance>(viewport);
}
template <class TViewportControllerInstance>
void MultiViewportController<TViewportControllerInstance>::UnregisterViewportContext(ViewportId viewport)
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
void MultiViewportController<TViewportControllerInstance, Priority>::UnregisterViewportContext(ViewportId viewport)
{
m_instances.erase(viewport);
}
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
ViewportControllerPriority MultiViewportController<TViewportControllerInstance, Priority>::GetPriority() const
{
return Priority;
}
} //namespace AzFramework
@@ -32,6 +32,76 @@ namespace AzFramework
using FloatSeconds = AZStd::chrono::duration<float>;
//! Controller Priority determines when controllers receive input and update events.
//! Controller Priority is provided by the list containing a viewport controller.
//! Input channel events are received from highest to lowest priority order,
//! allowing high priority controllers to consume input events and stop their propagation.
//! Viewport update events are received from lowest to highest priority order,
//! allowing high priority controllers to be the last to update the viewport state.
//!
//! Controller lists may receive DispatchToAllPriorities events, which will in turn
//! dispatch events to all of their children in priority order.
//!
//! @see AzFramework::ViewportControllerList
//! @note Because of this behavior, a ViewportControllerList that belongs to another
//! ViewportControllerList shall not receive a DispatchToAllPriorities event, and instead
//! shall receive multiple events from its parent at all priority levels.
enum class ViewportControllerPriority : uint8_t {
Highest = 0,
High,
Normal,
Low,
Lowest,
DispatchToAllPriorities
};
//! An event dispatched to ViewportControllers when input occurs.
struct ViewportControllerInputEvent
{
//! The viewport ID this event was dispatched to.
ViewportId m_viewportId;
//! The input channel data for this event.
const AzFramework::InputChannel& m_inputChannel;
//! The priority this event was dispatched at.
ViewportControllerPriority m_priority;
ViewportControllerInputEvent(
ViewportId viewportId,
const AzFramework::InputChannel& inputChannel,
ViewportControllerPriority priority = ViewportControllerPriority::DispatchToAllPriorities
)
: m_viewportId(viewportId)
, m_inputChannel(inputChannel)
, m_priority(priority)
{
}
};
//! An event dispatched to ViewportControllers every tick.
struct ViewportControllerUpdateEvent
{
//! The viewport ID this event was dispatched to.
ViewportId m_viewportId;
//! The time since the last update event, in seconds.
FloatSeconds m_deltaTime;
//! The absolute time point of this event.
AZ::ScriptTimePoint m_time;
//! The priority this event was dispatched at.
ViewportControllerPriority m_priority;
ViewportControllerUpdateEvent(
ViewportId viewportId, FloatSeconds deltaTime,
AZ::ScriptTimePoint time,
ViewportControllerPriority priority = ViewportControllerPriority::DispatchToAllPriorities
)
: m_viewportId(viewportId)
, m_deltaTime(deltaTime)
, m_time(time)
, m_priority(priority)
{
}
};
//! The interface for a Viewport Controller which handles input events and periodic updates for one or more registered Viewports.
//! @see SingleViewportController for simple cases involving only one viewport.
//! @see MultiViewportController for cases involving multiple viewports with no shared state.
@@ -43,16 +113,25 @@ namespace AzFramework
//! Handles an input event dispatched to a given viewportContext.
//! @return A "handled" flag. If OnInputChannelEvent returns true, the event is considered handled and all further input handling
//! in the containing ViewportControllerList halts.
virtual bool HandleInputChannelEvent([[maybe_unused]]ViewportId viewport, [[maybe_unused]]const AzFramework::InputChannel& inputChannel) { return false; }
virtual bool HandleInputChannelEvent([[maybe_unused]]const ViewportControllerInputEvent& event) { return false; }
//! Called to notify this controller that its input state should be reset.
//! This is called when input events, such as key up events, may have been missed and it should be assumed that
//! all input channels are in their default (i.e. no buttons pressed or other input provided) state.
virtual void ResetInputChannels(){}
//! Updates the current state of the viewport. This should be used to update e.g. the camera transform and will be called every frame
//! for each registered viewport.
virtual void UpdateViewport([[maybe_unused]]ViewportId viewport, [[maybe_unused]]FloatSeconds deltaTime, [[maybe_unused]]AZ::ScriptTimePoint time) {}
virtual void UpdateViewport([[maybe_unused]]const ViewportControllerUpdateEvent& event) {}
//! Registers a ViewportContext to be handled by this controller.
//! The controller will receive OnInputChannelEvent and OnUpdateViewport notifications for the viewports.
virtual void RegisterViewportContext(ViewportId viewport) = 0;
//! Unregisters a viewport from being handled by this controller.
//! No further events will be received from this viewport after this is called.
virtual void UnregisterViewportContext(ViewportId viewport) = 0;
//! Gets the priority at which this controller will receive input events.
//! If set to DispatchToAllPriorities, the controller will receive events multiple times for each
//! available priority level. This typically is only needed in the case of a list of other viewport
//! controllers, each with their own priority (handled by ViewportControllerList for most cases).
virtual ViewportControllerPriority GetPriority() const { return ViewportControllerPriority::Normal; }
};
} //namespace AzFramework
@@ -16,100 +16,162 @@
namespace AzFramework
{
void ViewportControllerList::Add(ViewportControllerPtr controller, ViewportControllerList::Priority priority)
void ViewportControllerList::Add(ViewportControllerPtr controller)
{
auto controllerIt = AZStd::find_if(
m_controllers.begin(), m_controllers.end(),
[controller](const ViewportControllerData& data)
for (auto &controllerData : m_controllers)
{
return data.controller == controller;
});
if (controllerIt != m_controllers.end())
{
AZ_Assert(false, "Attempted to add a duplicate controller to a ViewportControllerList");
return;
auto& controllerList = controllerData.second;
auto controllerIt = AZStd::find(
controllerList.begin(), controllerList.end(),
controller
);
if (controllerIt != controllerList.end())
{
AZ_Assert(false, "Attempted to add a duplicate controller to a ViewportControllerList");
return;
}
}
m_controllers.push_back({controller, priority});
m_controllers[controller->GetPriority()].push_back(controller);
for (auto viewportId : m_viewports)
{
controller->RegisterViewportContext(viewportId);
}
SortControllers();
}
void ViewportControllerList::Remove(ViewportControllerPtr controller)
{
m_controllers.erase(AZStd::remove_if(
m_controllers.begin(), m_controllers.end(),
[controller](const ViewportControllerData& data)
for (auto &controllerData : m_controllers)
{
return data.controller == controller;
}));
}
void ViewportControllerList::SetPriority(ViewportControllerPtr controller, ViewportControllerList::Priority priority)
{
auto controllerIt = AZStd::find_if(
m_controllers.begin(), m_controllers.end(),
[controller](const ViewportControllerData& data)
{
return data.controller == controller;
});
if (controllerIt != m_controllers.end())
{
controllerIt->priority = priority;
auto& controllerList = controllerData.second;
controllerList.erase(AZStd::remove(controllerList.begin(), controllerList.end(), controller));
}
SortControllers();
}
bool ViewportControllerList::HandleInputChannelEvent(ViewportId viewport, const AzFramework::InputChannel& inputChannel)
bool ViewportControllerList::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
{
// Iterate in forward order, so that the lowest priority values get the first opportunity to consume the event
for (const auto& controllerInfo : m_controllers)
// If our event priority is "custom", we should dispatch at all priority levels in order
using AzFramework::ViewportControllerPriority;
if (event.m_priority == AzFramework::ViewportControllerPriority::DispatchToAllPriorities)
{
if (controllerInfo.controller->HandleInputChannelEvent(viewport, inputChannel))
AzFramework::ViewportControllerInputEvent syntheticEvent = event;
for (const auto priority : {
ViewportControllerPriority::Highest,
ViewportControllerPriority::High,
ViewportControllerPriority::Normal,
ViewportControllerPriority::Low,
ViewportControllerPriority::Lowest })
{
return true;
syntheticEvent.m_priority = priority;
if (DispatchInputChannelEvent(syntheticEvent))
{
return true;
}
}
return false;
}
else
{
// Otherwise, dispatch to controllers at our priority
return DispatchInputChannelEvent(event);
}
}
bool ViewportControllerList::DispatchInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
{
if (auto priorityListIt = m_controllers.find(event.m_priority); priorityListIt != m_controllers.end())
{
for (const auto& controller : priorityListIt->second)
{
if (controller->HandleInputChannelEvent(event))
{
return true;
}
}
}
// Also dispatch to any nested controllers with "Custom" priority
if (auto priorityListIt = m_controllers.find(ViewportControllerPriority::DispatchToAllPriorities);
priorityListIt != m_controllers.end())
{
for (const auto& controller : priorityListIt->second)
{
if (controller->HandleInputChannelEvent(event))
{
return true;
}
}
}
return false;
}
void ViewportControllerList::UpdateViewport(ViewportId viewport, FloatSeconds deltaTime, AZ::ScriptTimePoint time)
void ViewportControllerList::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
{
// Iterate in reverse order, so that the lowest priority values go last
// This lets authoritative state changes in controllers with priority "win"
for (auto controllerIt = m_controllers.rbegin(), end = m_controllers.rend(); controllerIt != end; ++controllerIt)
// If our event priority is "custom", we should dispatch at all priority levels in reverse order
// Reverse order lets high priority controllers get the last say in viewport update operations
using AzFramework::ViewportControllerPriority;
if (event.m_priority == AzFramework::ViewportControllerPriority::DispatchToAllPriorities)
{
controllerIt->controller->UpdateViewport(viewport, deltaTime, time);
AzFramework::ViewportControllerUpdateEvent syntheticEvent = event;
for (const auto priority : {
ViewportControllerPriority::Lowest,
ViewportControllerPriority::Low,
ViewportControllerPriority::Normal,
ViewportControllerPriority::High,
ViewportControllerPriority::Highest })
{
syntheticEvent.m_priority = priority;
DispatchUpdateViewport(syntheticEvent);
}
}
else
{
// Otherwise, dispatch to controllers at our priority
DispatchUpdateViewport(event);
}
}
void ViewportControllerList::DispatchUpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
{
if (auto priorityListIt = m_controllers.find(event.m_priority); priorityListIt != m_controllers.end())
{
for (const auto& controller : priorityListIt->second)
{
controller->UpdateViewport(event);
}
}
// Also dispatch to any nested controllers with "Custom" priority
if (auto priorityListIt = m_controllers.find(ViewportControllerPriority::DispatchToAllPriorities);
priorityListIt != m_controllers.end())
{
for (const auto& controller : priorityListIt->second)
{
controller->UpdateViewport(event);
}
}
}
void ViewportControllerList::RegisterViewportContext(ViewportId viewport)
{
m_viewports.insert(viewport);
for (const auto& controllerInfo : m_controllers)
for (auto& controllerData : m_controllers)
{
controllerInfo.controller->RegisterViewportContext(viewport);
for (auto& controller : controllerData.second)
{
controller->RegisterViewportContext(viewport);
}
}
}
void ViewportControllerList::UnregisterViewportContext(ViewportId viewport)
{
m_viewports.erase(viewport);
for (const auto& controllerInfo : m_controllers)
for (auto& controllerData : m_controllers)
{
controllerInfo.controller->UnregisterViewportContext(viewport);
for (auto& controller : controllerData.second)
{
controller->UnregisterViewportContext(viewport);
}
}
}
void ViewportControllerList::SortControllers()
{
AZStd::sort(
m_controllers.begin(), m_controllers.end(),
[](const ViewportControllerData& d1, const ViewportControllerData& d2)
{
return d1.priority < d2.priority;
});
}
} //namespace AzFramework
@@ -14,62 +14,49 @@
#include <AzFramework/Viewport/ViewportControllerInterface.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/containers/unordered_set.h>
namespace AzFramework
{
//! A list of ViewportControllers that allows priority-ordered dispatch to the registered ViewportControllers.
//! A list of ViewportControllers that allows priority-ordered dispatch to controllers registered to it.
//! ViewportControllerList itself is-a controller, meaning it controllers can be contained in nested lists.
class ViewportControllerList final
: public ViewportControllerInterface
{
public:
//! Controller Priority determines when controllers receive input and update events.
//! Input channel events are received from highest to lowest priority order,
//! allowing high priority controllers to consume input events and stop their propagation.
//! Viewport update events are received from lowest to highest priority order,
//! allowing high priority controllers to be the last to update the viewport state.
enum class Priority : unsigned char {
Highest = 0,
High,
Normal,
Low,
Lowest
};
//! Adds a controller to this list at the specified priority.
//! This controller will be notified of all InputChannelEvents not consumed by a higher priority controller
//! via OnInputChannelEvent.
void Add(ViewportControllerPtr controller, Priority priority = Priority::Normal);
void Add(ViewportControllerPtr controller);
//! Removes a controller from this list.
void Remove(ViewportControllerPtr controller);
//! Updates the priority level for a controller.
void SetPriority(ViewportControllerPtr controller, Priority priority);
// ViewportControllerInterface overrides
//! Dispatches an InputChannelEvent to all controllers registered to this list until
//! either a controller returns true to consume the event in OnInputChannelEvent or the controller list is exhausted.
//! InputChannelEvents are sent to controllers in priority order (from the lowest priority value to the highest).
bool HandleInputChannelEvent(ViewportId viewport, const AzFramework::InputChannel& inputChannel) override;
bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override;
//! Dispatches an update tick to all controllers registered to this list.
//! This occurs in *reverse* priority order (i.e. from the highest priority value to the lowest) so that
//! controllers with the highest registration priority may override the transforms of the controllers with the
//! lowest registration priority.
void UpdateViewport(ViewportId viewport, FloatSeconds deltaTime, AZ::ScriptTimePoint time) override;
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
//! Registers a Viewport to this list.
//! All current and added controllers will be registered with this viewport.
void RegisterViewportContext(ViewportId viewport) override;
//! Unregisters a Viewport from this list and all associated controllers.
void UnregisterViewportContext(ViewportId viewport);
//! All ViewportControllerLists have a priority of Custom to ensure
//! that they receive events at all priorities from any parent controllers.
AzFramework::ViewportControllerPriority GetPriority() const { return ViewportControllerPriority::DispatchToAllPriorities; }
private:
void SortControllers();
bool DispatchInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event);
void DispatchUpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event);
struct ViewportControllerData
{
ViewportControllerPtr controller;
Priority priority = Priority::Normal;
};
AZStd::vector<ViewportControllerData> m_controllers;
AZStd::unordered_map<AzFramework::ViewportControllerPriority, AZStd::vector<ViewportControllerPtr>> m_controllers;
AZStd::unordered_set<ViewportId> m_viewports;
};
} //namespace AzFramework
@@ -34,8 +34,9 @@ namespace AzFramework
enum TypeFlags
{
TYPE_None = 0,
TYPE_Entity = 1 << 0,
TYPE_RPI_Cullable = 1 << 1
TYPE_Entity = 1 << 0, // All entities
TYPE_NetEntity = 1 << 1, // NetBound entities
TYPE_RPI_Cullable = 1 << 2 // Cullable by the render system
};
AZ::Aabb m_boundingVolume = AZ::Aabb::CreateNull();
@@ -82,6 +82,8 @@ set(FILES
CommandLine/CommandLine.h
CommandLine/CommandRegistrationBus.h
Debug/DebugCameraBus.h
Engine/Engine.cpp
Engine/Engine.h
Viewport/ViewportBus.h
Viewport/ViewportBus.cpp
Viewport/ViewportColors.h
@@ -262,10 +264,11 @@ set(FILES
Physics/ClassConverters.cpp
Physics/ClassConverters.h
Physics/MaterialBus.h
Physics/TouchBendingBus.h
Physics/WorldEventhandler.h
Physics/ScriptCanvasPhysicsUtils.h
Physics/ScriptCanvasPhysicsUtils.cpp
ProjectManager/ProjectManager.h
ProjectManager/ProjectManager.cpp
Render/GameIntersectorComponent.h
Render/GameIntersectorComponent.cpp
Render/GeometryIntersectionBus.h
@@ -273,6 +276,14 @@ set(FILES
Render/Intersector.cpp
Render/Intersector.h
Render/IntersectorInterface.h
Spawnable/Spawnable.cpp
Spawnable/Spawnable.h
Spawnable/SpawnableAssetHandler.h
Spawnable/SpawnableAssetHandler.cpp
Spawnable/SpawnableMetaData.cpp
Spawnable/SpawnableMetaData.h
Spawnable/SpawnableSystemComponent.h
Spawnable/SpawnableSystemComponent.cpp
Terrain/TerrainDataRequestBus.h
Terrain/TerrainDataRequestBus.cpp
Platform/PlatformDefaults.h
@@ -0,0 +1,27 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/ProjectManager/ProjectManager.h>
#include <AzCore/PlatformIncl.h>
namespace AzFramework
{
namespace ProjectManager
{
bool LaunchProjectManager()
{
return false;
}
} // ProjectManager
} // AzFramework
@@ -15,6 +15,7 @@ set(FILES
AzFramework/API/ApplicationAPI_Platform.h
AzFramework/API/ApplicationAPI_Android.h
AzFramework/Application/Application_Android.cpp
AzFramework/ProjectManager/ProjectManager_Android.cpp
../Common/Unimplemented/AzFramework/Asset/AssetSystemComponentHelper_Unimplemented.cpp
AzFramework/IO/LocalFileIO_Android.cpp
../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp
@@ -0,0 +1,28 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/ProjectManager/ProjectManager.h>
#include <AzCore/PlatformIncl.h>
namespace AzFramework
{
namespace ProjectManager
{
bool LaunchProjectManager()
{
return false;
}
} // ProjectManager
} // AzFramework
@@ -0,0 +1,27 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/ProjectManager/ProjectManager.h>
#include <AzCore/PlatformIncl.h>
namespace AzFramework
{
namespace ProjectManager
{
bool LaunchProjectManager()
{
return false;
}
} // ProjectManager
} // AzFramework
@@ -16,6 +16,7 @@ set(FILES
AzFramework/API/ApplicationAPI_Linux.h
AzFramework/Application/Application_Linux.cpp
AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp
AzFramework/ProjectManager/ProjectManager_Linux.cpp
../Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp
../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp
../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp
@@ -0,0 +1,27 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/ProjectManager/ProjectManager.h>
#include <AzCore/PlatformIncl.h>
namespace AzFramework
{
namespace ProjectManager
{
bool LaunchProjectManager()
{
return false;
}
} // ProjectManager
} // AzFramework
@@ -61,8 +61,6 @@ namespace AzFramework
const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks)
{
AZ_UNUSED(windowType);
m_width = geometry.m_width;
m_height = geometry.m_height;
@@ -16,6 +16,7 @@ set(FILES
AzFramework/API/ApplicationAPI_Mac.h
AzFramework/Application/Application_Mac.mm
AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp
AzFramework/ProjectManager/ProjectManager_Mac.cpp
../Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp
../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp
../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp
@@ -0,0 +1,77 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/ProjectManager/ProjectManager.h>
#include <AzCore/PlatformIncl.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/Engine/Engine.h>
namespace AzFramework
{
namespace ProjectManager
{
bool LaunchProjectManager()
{
const char projectsScript[] = "projects.py";
AZ_Warning("ProjectManager", false, "No project provided - launching project selector.");
AZ::IO::FixedMaxPath enginePath = Engine::FindEngineRoot();
if (enginePath.empty())
{
AZ_Warning("ProjectManager", false, "Couldn't find engine root");
return false;
}
auto projectManagerPath = enginePath / "scripts" / "project_manager";
if (!AZ::IO::SystemFile::Exists((projectManagerPath / projectsScript).c_str()))
{
AZ_Warning("ProjectManager", false, "%s not found at %s!", projectsScript, projectManagerPath.c_str());
}
char executablePath[AZ_MAX_PATH_LEN];
AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executablePath, AZ_MAX_PATH_LEN);
auto exeFolder = AZ::IO::PathView(executablePath).ParentPath().Filename().Native();
AZStd::fixed_string<10> debugOption{ " " };
if (exeFolder == "debug")
{
// We need to use the debug version of the python interpreter to load up our debug version of our libraries which work with the debug version of QT living in this folder
debugOption = " debug ";
}
AZ::IO::FixedMaxPath pythonPath = enginePath / "python" / "python.cmd";
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s%s%s --executable_path=%s", pythonPath.Native().c_str(), debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath);
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi;
auto workingPath = AZ::IO::FixedMaxPath{ executablePath }.ParentPath().Native();
bool launchSuccess = ::CreateProcessA(nullptr, cmdPath.data(), nullptr, nullptr, FALSE, 0, nullptr, projectManagerPath.c_str(), &si, &pi) != 0;
if (launchSuccess)
{
AZ_TracePrintf("ProjectManagerSystemComponent", "Launched Project Manager successfully, shutting down.\n");
}
else
{
auto someError = GetLastError();
AZ_Warning("ProjectManagerSystemComponent", false, "Failed to launch project manager with error %d", someError);
}
return launchSuccess;
}
} // ProjectManager
} // AzFramework
@@ -223,6 +223,25 @@ namespace AzFramework
AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputCodeUnitUTF16Event, codeUnitUTF16);
break;
}
case WM_SYSKEYDOWN:
{
// Handle ALT+ENTER to toggle full screen unless exclsuive full screen
// mode is preferred, in which case this will be handled by the system.
if ((wParam == VK_RETURN) && (lParam & (1 << 29)))
{
bool isExclusiveFullScreenPreferred = false;
ExclusiveFullScreenRequestBus::EventResult(isExclusiveFullScreenPreferred,
nativeWindowImpl->GetWindowHandle(),
&ExclusiveFullScreenRequests::IsExclusiveFullScreenPreferred);
if (!isExclusiveFullScreenPreferred)
{
WindowRequestBus::Event(nativeWindowImpl->GetWindowHandle(), &WindowRequests::ToggleFullScreenState);
return 0;
}
}
// Send all other WM_SYSKEYDOWN messages to the default WndProc.
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
@@ -16,6 +16,7 @@ set(FILES
AzFramework/API/ApplicationAPI_Windows.h
AzFramework/Application/Application_Windows.cpp
AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp
AzFramework/ProjectManager/ProjectManager_Windows.cpp
../Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp
AzFramework/IO/LocalFileIO_Windows.cpp
../Common/WinAPI/AzFramework/Network/AssetProcessorConnection_WinAPI.cpp
@@ -0,0 +1,28 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/ProjectManager/ProjectManager.h>
#include <AzCore/PlatformIncl.h>
namespace AzFramework
{
namespace ProjectManager
{
bool LaunchProjectManager()
{
return false;
}
} // ProjectManager
} // AzFramework
@@ -15,6 +15,7 @@ set(FILES
AzFramework/API/ApplicationAPI_Platform.h
AzFramework/API/ApplicationAPI_iOS.h
AzFramework/Application/Application_iOS.mm
AzFramework/ProjectManager/ProjectManager_iOS.cpp
../Common/Unimplemented/AzFramework/Asset/AssetSystemComponentHelper_Unimplemented.cpp
../Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp
../Common/Default/AzFramework/Network/AssetProcessorConnection_Default.cpp