Skip to content

Commit

Permalink
Added SetComponent chaining
Browse files Browse the repository at this point in the history
  • Loading branch information
richardbiely committed Jul 2, 2022
1 parent ae01f6c commit bac3fa8
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 18 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ w.SetComponent<Velocity>(e, {0, 0, 2});
auto velNew = w.GetComponent<Velocity>(e);
```

In case there are more different components on your entity you would like to change the value of you can achive it via SetComponent chaining:
```cpp
// Change Velocity's value.
w.SetComponent<Velocity>(e, {0, 0, 2}).
SetComponent<Position>({0, 100, 0}).
SetComponent...;
```
### Checking if component is attached to entity
```cpp
// Check if entity e has Velocity.
Expand Down
61 changes: 43 additions & 18 deletions include/gaia/ecs/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@
namespace gaia {
namespace ecs {

//----------------------------------------------------------------------

struct ComponentSetter {
Chunk* m_pChunk;
size_t m_idx;

template <typename TComponent>
ComponentSetter& SetComponent(typename DeduceComponent<TComponent>::Type&& data) {
if constexpr (IsGenericComponent<TComponent>::value) {
using U = typename detail::ExtractComponentType_Generic<TComponent>::Type;
m_pChunk->template SetComponent<TComponent>(m_idx, std::forward<U>(data));
return *this;
} else {
using U = typename detail::ExtractComponentType_Generic<TComponent>::Type;
m_pChunk->template SetComponent<TComponent>(std::forward<U>(data));
return *this;
}
}
};

//----------------------------------------------------------------------

class GAIA_API World final {
friend class ECSSystem;
friend class ECSSystemManager;
Expand Down Expand Up @@ -786,7 +808,7 @@ namespace gaia {
return entityContainer;
}

void RemoveComponent_Internal(ComponentType type, Entity entity, const ComponentInfo* infoToRemove) {
ComponentSetter RemoveComponent_Internal(ComponentType type, Entity entity, const ComponentInfo* infoToRemove) {
auto& entityContainer = m_entities[entity.id()];
auto* pChunk = entityContainer.pChunk;
auto& archetype = const_cast<Archetype&>(pChunk->header.owner);
Expand All @@ -805,6 +827,8 @@ namespace gaia {
if (auto newArchetype = FindArchetype_RemoveComponents(&archetype, type, infoToRemove))
MoveEntity(entity, *newArchetype);
#endif

return ComponentSetter{pChunk, entityContainer.idx};
}

void Init() {
Expand Down Expand Up @@ -1046,30 +1070,34 @@ namespace gaia {
Attaches a new component to \param entity.
\warning It is expected the component is not there yet and that \param
entity is valid. Undefined behavior otherwise.
\return ComponentSetter object.
*/
template <typename TComponent>
void AddComponent(Entity entity) {
ComponentSetter AddComponent(Entity entity) {
VerifyComponent<TComponent>();
GAIA_ASSERT(IsEntityValid(entity));

if constexpr (IsGenericComponent<TComponent>::value) {
using U = typename detail::ExtractComponentType_Generic<TComponent>::Type;
const auto* info = m_componentCache.GetOrCreateComponentInfo<U>();
AddComponent_Internal(ComponentType::CT_Generic, entity, info);
auto& entityContainer = AddComponent_Internal(ComponentType::CT_Generic, entity, info);
return ComponentSetter{entityContainer.pChunk, entityContainer.idx};
} else {
using U = typename detail::ExtractComponentType_NonGeneric<TComponent>::Type;
const auto* info = m_componentCache.GetOrCreateComponentInfo<U>();
AddComponent_Internal(ComponentType::CT_Chunk, entity, info);
auto& entityContainer = AddComponent_Internal(ComponentType::CT_Chunk, entity, info);
return ComponentSetter{entityContainer.pChunk, entityContainer.idx};
}
}

/*!
Attaches a component to \param entity. Also sets its value.
\warning It is expected the component is not there yet and that
\param entity is valid. Undefined behavior otherwise.
\return ComponentSetter object.
*/
template <typename TComponent>
void AddComponent(Entity entity, typename DeduceComponent<TComponent>::Type&& data) {
ComponentSetter AddComponent(Entity entity, typename DeduceComponent<TComponent>::Type&& data) {
VerifyComponent<TComponent>();
GAIA_ASSERT(IsEntityValid(entity));

Expand All @@ -1079,56 +1107,53 @@ namespace gaia {
auto& entityContainer = AddComponent_Internal(ComponentType::CT_Generic, entity, info);
auto* pChunk = entityContainer.pChunk;
pChunk->template SetComponent<TComponent>(entityContainer.idx, std::forward<U>(data));
return ComponentSetter{entityContainer.pChunk, entityContainer.idx};
} else {
using U = typename detail::ExtractComponentType_NonGeneric<TComponent>::Type;
const auto* info = m_componentCache.GetOrCreateComponentInfo<U>();
auto& entityContainer = AddComponent_Internal(ComponentType::CT_Chunk, entity, info);
auto* pChunk = entityContainer.pChunk;
pChunk->template SetComponent<TComponent>(std::forward<U>(data));
return ComponentSetter{entityContainer.pChunk, entityContainer.idx};
}
}

/*!
Removes a component from \param entity.
\warning It is expected the component is not there yet and that
\param entity is valid. Undefined behavior otherwise.
\return ComponentSetter object.
*/
template <typename TComponent>
void RemoveComponent(Entity entity) {
ComponentSetter RemoveComponent(Entity entity) {
VerifyComponent<TComponent>();
GAIA_ASSERT(IsEntityValid(entity));

if constexpr (IsGenericComponent<TComponent>::value) {
using U = typename detail::ExtractComponentType_Generic<TComponent>::Type;
const auto* info = m_componentCache.GetOrCreateComponentInfo<U>();
RemoveComponent_Internal(ComponentType::CT_Generic, entity, info);
return RemoveComponent_Internal(ComponentType::CT_Generic, entity, info);
} else {
using U = typename detail::ExtractComponentType_NonGeneric<TComponent>::Type;
const auto* info = m_componentCache.GetOrCreateComponentInfo<U>();
RemoveComponent_Internal(ComponentType::CT_Chunk, entity, info);
return RemoveComponent_Internal(ComponentType::CT_Chunk, entity, info);
}
}

/*!
Sets the value of component on \param entity.
\warning It is expected the component was added to \param entity already. Undefined behavior otherwise.
\param entity is valid. Undefined behavior otherwise.
\return ComponentSetter object.
*/
template <typename TComponent>
void SetComponent(Entity entity, typename DeduceComponent<TComponent>::Type&& data) {
ComponentSetter SetComponent(Entity entity, typename DeduceComponent<TComponent>::Type&& data) {
VerifyComponent<TComponent>();
GAIA_ASSERT(IsEntityValid(entity));

auto& entityContainer = m_entities[entity.id()];
auto* pChunk = entityContainer.pChunk;

if constexpr (IsGenericComponent<TComponent>::value) {
using U = typename detail::ExtractComponentType_Generic<TComponent>::Type;
pChunk->template SetComponent<TComponent>(entityContainer.idx, std::forward<U>(data));
} else {
using U = typename detail::ExtractComponentType_NonGeneric<TComponent>::Type;
pChunk->template SetComponent<TComponent>(std::forward<U>(data));
}
return ComponentSetter{entityContainer.pChunk, entityContainer.idx}.SetComponent<TComponent>(
std::forward<typename DeduceComponent<TComponent>::Type>(data));
}

/*!
Expand Down

0 comments on commit bac3fa8

Please sign in to comment.