Skip to content

Commit

Permalink
!XI Integrating Entity changes from //ce/main to //ce/main_stabilisation
Browse files Browse the repository at this point in the history
!B (Sandbox) Fix entities without scripts being reloaded when scripts changed
!B (Sandbox) Fix case where components were duplicated after undoing entity deletion
!B (Sandbox) Fix reverting of a component's properties in the inspector recreating the entire entity
!B (Sandbox) Fix default Entity icon being shown for entities with helpers
!B (CrySchematyc) Fix Schematyc entity components being created and initialized sequentially, instead of created in one batch and then initialized after.
!B (CryEntitySystem) Fix issue where during load components being created and initialized sequentially, instead of created in one batch and then initialized after.
!B (CryEntitySystem) Fix Schematyc package not being deregistered, preventing possible crash on shutdown
!B (CryEntitySystem) Fixed newer Schematyc-based components relying on the legacy IID system - the IID function is now no longer needed for new components.

Copied from Perforce
 Change: 1539283
  • Loading branch information
Cry-59 committed Jul 27, 2017
2 parents d5320e7 + 9055e59 commit d76c582
Show file tree
Hide file tree
Showing 65 changed files with 787 additions and 828 deletions.
151 changes: 99 additions & 52 deletions Code/CryEngine/CryCommon/CryEntitySystem/IEntity.h
Original file line number Diff line number Diff line change
Expand Up @@ -788,108 +788,155 @@ struct IEntity
//! Queries an entity component implementing the specified component interface
virtual IEntityComponent* QueryComponentByInterfaceID(const CryInterfaceID& interfaceID) const = 0;

//! Create a new initialized component using interface type id to create a class using factory component class creation.
//! ComponentType must be a valid interface that can be queried with cryidof<ComponentType>()
//! Instance of the component is created by the lookup in the class registry for the first class that implements ComponentType interface,
//! If such class is not previously registered the assert will be raised and method will fail.
template<typename ComponentType>
typename std::enable_if<std::is_convertible<ComponentType, IEntityComponent>::value, ComponentType*>::type CreateComponent()
{
CRY_ASSERT_MESSAGE(cryiidof<ComponentType>() != cryiidof<IEntityComponent>(), "Component must implement an IID function returning CryGUID!");
#if !defined(SWIG)
// Helper to check for reflection in std::enable_if, since this can't be done with a constexpr function
template<class ComponentType>
struct IsComponentReflected { static constexpr bool value = Schematyc::IsReflectedType<ComponentType>(); };

ComponentType* pReturn = static_cast<ComponentType*>(CreateComponentByInterfaceID(cryiidof<ComponentType>()));
CRY_ASSERT(pReturn != nullptr); // Must return a valid component interface
return pReturn;
}
// Incorrectly implemented component, either doesn't reflect Schematyc properties or is an incorrectly configured legacy component!
template<class ComponentType, typename = void>
struct SComponentType
{
enum { kFalse = false };
static_assert(kFalse, "Component was not reflected!");
};

//! Get existing or Create a new initialized component inside the entity.
template<typename ComponentType>
typename std::enable_if<std::is_convertible<ComponentType, IEntityComponent>::value, ComponentType*>::type GetOrCreateComponent()
// New Schematyc component type
template<class ComponentType>
struct SComponentType<ComponentType, typename std::enable_if<IsComponentReflected<ComponentType>::value && std::is_convertible<ComponentType, IEntityComponent>::value>::type>
{
auto component = GetComponent<ComponentType>();
if (component)
static const CryGUID& GetGUID()
{
return component;
static const CryGUID s_guid = Schematyc::GetTypeGUID<ComponentType>();
return s_guid;
}
else

template<typename... TArgs>
static ComponentType* CreateInEntity(IEntity* pEntity, TArgs&&... args)
{
return CreateComponent<ComponentType>();
std::shared_ptr<ComponentType> pComponent = std::make_shared<ComponentType>(std::forward<TArgs>(args)...);
IEntityComponent::SInitParams initParams = IEntityComponent::SInitParams{ pEntity, CryGUID::Create(), "", &Schematyc::GetTypeDesc<ComponentType>(), EEntityComponentFlags::None, nullptr, nullptr };
if (pEntity->AddComponent(pComponent, &initParams))
{
return pComponent.get();
}

return nullptr;
}
}
};

//! Create a new initialized component using a new operator of the class type
// Legacy entity components
template<class ComponentType>
typename std::enable_if<!Schematyc::IsReflectedType<ComponentType>() && std::is_convertible<ComponentType, IEntityComponent>::value, ComponentType*>::type CreateComponentClass()
struct SComponentType<ComponentType, typename std::enable_if<!IsComponentReflected<ComponentType>::value && std::is_convertible<ComponentType, IEntityComponent>::value>::type>
{
std::shared_ptr<ComponentType> pComponent = std::make_shared<ComponentType>();
if (AddComponent(pComponent))
static const CryGUID& GetGUID()
{
return pComponent.get();
return cryiidof<ComponentType>();
}

return nullptr;
template<typename... TArgs>
static ComponentType* CreateInEntity(IEntity* pEntity, TArgs&&... args)
{
std::shared_ptr<ComponentType> pComponent = std::make_shared<ComponentType>(std::forward<TArgs>(args)...);
if (pEntity->AddComponent(pComponent))
{
static_cast<IEntityComponent*>(pComponent.get())->Initialize();

return pComponent.get();
}

return nullptr;
}
};

//! Creates a new entity component of type ComponentType from a registered factory and adds it to the entity.
//! ComponentType must be a valid IEntityComponent implementation.
//! \returns A pointer to the newly created component, otherwise nullptr (and likely an assertion).
template<typename ComponentType>
ComponentType* CreateComponent()
{
return static_cast<ComponentType*>(CreateComponentByInterfaceID(SComponentType<ComponentType>::GetGUID()));
}

//! Get existing or Create a new initialized component using the new operator of the class type, typeid of the component is null guid.
template<class ComponentType>
typename std::enable_if<!Schematyc::IsReflectedType<ComponentType>() && std::is_convertible<ComponentType, IEntityComponent>::value, ComponentType*>::type GetOrCreateComponentClass()
//! Get existing or Create a new initialized component inside the entity.
//! \param bCheckHierarchy Whether or not we should traverse the inheritance hierarchy for all components, otherwise performs a (much faster) equality check to see if the implementation is ComponentType
template<typename ComponentType>
ComponentType* GetOrCreateComponent(bool bCheckHierarchy = true)
{
ComponentType* pComponent = GetComponent<ComponentType>();
if (pComponent)
if (ComponentType* pComponent = GetComponent<ComponentType>(bCheckHierarchy))
{
return pComponent;
}
else
{
return CreateComponentClass<ComponentType>();
return CreateComponent<ComponentType>();
}
}


//! Helper template function to simplify finding the first component implementing the specified component type
//! This will traverse the inheritance tree, and is therefore slower than GetComponentByImplementation which simply does an equality check.
//! ex: auto pScriptProxy = pEntity->GetComponent<IEntityScriptComponent>();
//! \param bCheckHierarchy Whether or not we should traverse the inheritance hierarchy for all components, otherwise performs a (much faster) equality check to see if the implementation is ComponentType
template<typename ComponentType>
typename std::enable_if<std::is_convertible<ComponentType, IEntityComponent>::value, ComponentType*>::type GetComponent() const
ComponentType* GetComponent(bool bCheckHierarchy = true) const
{
return static_cast<ComponentType*>(QueryComponentByInterfaceID(cryiidof<ComponentType>()));
if (bCheckHierarchy)
{
return static_cast<ComponentType*>(QueryComponentByInterfaceID(SComponentType<ComponentType>::GetGUID()));
}
else
{
return static_cast<ComponentType*>(GetComponentByTypeId(SComponentType<ComponentType>::GetGUID()));
}

return nullptr;
}

//! Helper template function to simplify finding all components implementing the specified component type
//! This will traverse the inheritance tree, and is therefore slower than GetComponentsByImplementation which simply does an equality check.
//! \param components DynArray into which any found components will be stored
//! \param bCheckHierarchy Whether or not we should traverse the inheritance hierarchy for all components, otherwise performs a (much faster) equality check to see if the implementation is ComponentType
template<typename ComponentType>
typename std::enable_if<std::is_convertible<ComponentType, IEntityComponent>::value, void>::type GetComponents(DynArray<ComponentType*>& components) const
void GetAllComponents(DynArray<ComponentType*>& components, bool bCheckHierarchy = true) const
{
// Hack to avoid copy of vectors, seeing as the interface querying guarantees that the pointers inside are compatible
DynArray<IEntityComponent*>* pRawComponents = (DynArray<IEntityComponent*>*)(void*)&components;
QueryComponentsByInterfaceID(cryiidof<ComponentType>(), *pRawComponents);
if (bCheckHierarchy)
{
QueryComponentsByInterfaceID(SComponentType<ComponentType>::GetGUID(), *pRawComponents);
}
else
{
GetComponentsByTypeId(SComponentType<ComponentType>::GetGUID(), *pRawComponents);
}

// Static cast all types from IEntityComponent* to ComponentType*
for (auto it = pRawComponents->begin(); it != pRawComponents->end(); ++it)
{
*it = static_cast<ComponentType*>((IEntityComponent*)(void*)*it);
}
}

//! Helper template function to simplify finding the first component of the specified component type, ignores inherited interfaces and classes!
template<typename ComponentType>
typename std::enable_if<std::is_convertible<ComponentType, IEntityComponent>::value, ComponentType*>::type GetComponentByImplementation() const
//! Create a new initialized component using a new operator of the class type.
template<class ComponentType, typename... TArgs>
ComponentType* CreateComponentClass(TArgs&&... args)
{
return static_cast<ComponentType*>(GetComponentByTypeId(cryiidof<ComponentType>()));
return SComponentType<ComponentType>::CreateInEntity(this, std::forward<TArgs>(args)...);
}

//! Helper template function to simplify finding all components of the specified component type, ignores inherited interfaces and classes!
template<typename ComponentType>
typename std::enable_if<std::is_convertible<ComponentType, IEntityComponent>::value, void>::type GetComponentsByImplementation(DynArray<ComponentType*>& components) const
//! Get existing or Create a new initialized component using the new operator of the class type, typeid of the component is null guid.
template<class ComponentType, typename... TArgs>
ComponentType* GetOrCreateComponentClass(TArgs&&... args)
{
// Hack to avoid copy of vectors, seeing as the interface querying guarantees that the pointers inside are compatible
DynArray<IEntityComponent*>* pRawComponents = (DynArray<IEntityComponent*>*)(void*)&components;
GetComponentsByTypeId(cryiidof<ComponentType>(), *pRawComponents);
// Static cast all types from IEntityComponent* to ComponentType*
for (auto it = pRawComponents->begin(); it != pRawComponents->end(); ++it)
if (ComponentType* pComponent = GetComponent<ComponentType>())
{
*it = static_cast<ComponentType*>((IEntityComponent*)(void*)*it);
return pComponent;
}
else
{
return CreateComponentClass<ComponentType>(std::forward<TArgs>(args)...);
}
}
#endif // !defined(SWIG)

//! Creates instances of the components contained in the other entity
//! Also copies over properties for all the components created.
Expand Down
11 changes: 9 additions & 2 deletions Code/CryEngine/CryCommon/CryEntitySystem/IEntityComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ class CEntityComponentClassDesc : public Schematyc::CClassDesc
m_interactions.emplace_back(type, guid);
}

template<class T>
inline void AddComponentInteraction(SEntityComponentRequirements::EType type)
{
m_interactions.emplace_back(type, Schematyc::GetTypeGUID<T>());
}

inline bool IsCompatibleWith(const CryGUID& guid) const
{
for (const SEntityComponentRequirements& dependency : m_interactions)
Expand Down Expand Up @@ -502,11 +508,12 @@ struct IEntityComponent : public ICryUnknown
//////////////////////////////////////////////////////////////////////////

protected:
friend IEntity;
friend class CEntity;
// Needs access to OnShutDown to maintain legacy game object extension shutdown behavior
friend class CGameObject;
// Needs access to Run, remove when the function is gone
friend class CEntityObject;
// Needs access to Initialize
friend Schematyc::CObject;

// Host Entity pointer
IEntity* m_pEntity = nullptr;
Expand Down
17 changes: 17 additions & 0 deletions Code/CryEngine/CryCommon/CrySchematyc/Reflection/TypeDesc.inl
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,15 @@ public:
}
};

template<typename TYPE> class CSimpleTypeDesc : public CTypeDesc<TYPE>
{
public:
inline CSimpleTypeDesc()
{
ReflectType(static_cast<CTypeDesc<TYPE>&>(*this));
}
};

} // Helpers

template<typename TYPE> constexpr bool IsReflectedType()
Expand All @@ -516,4 +525,12 @@ template<typename TYPE> inline const CTypeDesc<TYPE>& GetTypeDesc()
return s_desc;
}

template<typename TYPE> inline CryGUID GetTypeGUID()
{
SCHEMATYC_VERIFY_TYPE_IS_REFLECTED(TYPE);

static const Helpers::CSimpleTypeDesc<TYPE> s_desc;
return s_desc.GetGUID();
}

} // Schematyc
5 changes: 5 additions & 0 deletions Code/CryEngine/CryEntitySystem/CryEntityDLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ class CEngineModule_EntitySystem : public IEntitySystemEngineModule

virtual ~CEngineModule_EntitySystem()
{
if (gEnv->pSchematyc)
{
gEnv->pSchematyc->GetEnvRegistry().DeregisterPackage("A37D36D5-2AB1-4B48-9353-3DEC93A4236A"_cry_guid);
}

GetISystem()->GetISystemEventDispatcher()->RemoveListener(&g_system_event_listener_entity);
SAFE_RELEASE(gEnv->pEntitySystem);
}
Expand Down
Loading

0 comments on commit d76c582

Please sign in to comment.