diff --git a/Include/Misc/PipeDebug.h b/Include/Misc/PipeDebug.h index 4a9e9fa5..6cf49c36 100644 --- a/Include/Misc/PipeDebug.h +++ b/Include/Misc/PipeDebug.h @@ -176,14 +176,14 @@ namespace p DebugECSContext ecs; DebugReflectContext reflect; - EntityContext* ctx = nullptr; + IdContext* ctx = nullptr; bool initialized = false; bool isFirstDebug = true; DebugContext() = default; - DebugContext(EntityContext& ctx) : ctx{&ctx} {} + DebugContext(IdContext& ctx) : ctx{&ctx} {} }; bool BeginDebug(DebugContext& Context); @@ -221,7 +221,7 @@ namespace p // For internal use only - EntityContext& GetDebugCtx() + IdContext& GetDebugCtx() { return *currentContext->ctx; } @@ -552,7 +552,7 @@ namespace p #pragma region ECS i32 DebugECSInspector::uniqueIdCounter = 0; - using DrawNodeAccess = TAccessRef; + using DrawNodeAccess = TIdScopeRef; namespace details { bool ChooseTypePopup(const char* label, ImGuiTextFilter& filter, TypeId& selectedTypeId) @@ -1282,7 +1282,7 @@ namespace p return false; } - if (!P_EnsureMsg(context.ctx, "Debug Context does not contain a valid EntityContext.")) + if (!P_EnsureMsg(context.ctx, "Debug Context does not contain a valid IdContext.")) { return false; } diff --git a/Include/Pipe/Core/EnumFlags.h b/Include/Pipe/Core/EnumFlags.h index 04a8e358..e0c01399 100644 --- a/Include/Pipe/Core/EnumFlags.h +++ b/Include/Pipe/Core/EnumFlags.h @@ -7,73 +7,91 @@ namespace p { + template + constexpr bool HasAllFlags(I value, I flags) noexcept + { + return (value & flags) == flags; + } + + template + constexpr bool HasAnyFlags(I value, I flags) noexcept + { + return (value & flags) != 0; + } + + template + constexpr bool HasFlag(I value, I flag) noexcept + { + return HasAllFlags(value, flag); + } + namespace EnumOperators { // Bitwise operators: ~, |, &, ^, |=, &=, ^= using namespace magic_enum::bitwise_operators; - template - constexpr UnderlyingType operator*(E value) noexcept requires(IsEnum) + template + constexpr UnderlyingType operator*(E value) noexcept { return static_cast>(value); } - template - constexpr E operator|(E lhs, E rhs) noexcept requires(IsEnum) + template + constexpr E operator|(E lhs, E rhs) noexcept { return static_cast( static_cast>(lhs) | static_cast>(rhs)); } } // namespace EnumOperators - template - constexpr bool HasAllFlags(E value, E flags) noexcept requires(IsEnum) + template + constexpr bool HasAllFlags(E value, E flags) noexcept { return (static_cast>(value) & static_cast>(flags)) == static_cast>(flags); } - template - constexpr bool HasAnyFlags(E value, E flags) noexcept requires(IsEnum) + template + constexpr bool HasAnyFlags(E value, E flags) noexcept { return (static_cast>(value) & static_cast>(flags)) != 0; } - template> - constexpr bool HasAllFlags(R value, E flags) noexcept requires(IsEnum) + template> + constexpr bool HasAllFlags(R value, E flags) noexcept { return (static_cast(value) & static_cast>(flags)) == static_cast>(flags); } - template> - constexpr bool HasAnyFlags(R value, E flags) noexcept requires(IsEnum) + template> + constexpr bool HasAnyFlags(R value, E flags) noexcept { return (static_cast(value) & static_cast>(flags)) != 0; } - template - constexpr bool HasFlag(E value, E flag) noexcept requires(IsEnum) + template + constexpr bool HasFlag(E value, E flag) noexcept { return HasAllFlags(value, flag); } - template> - constexpr bool HasFlag(R value, E flag) noexcept requires(IsEnum) + template> + constexpr bool HasFlag(R value, E flag) noexcept { return HasAllFlags(value, flag); } - template - void AddFlags(E& value, E flags) noexcept requires(IsEnum) + template + void AddFlags(E& value, E flags) noexcept { auto rawValue = static_cast>(value); rawValue |= static_cast>(flags); value = static_cast(rawValue); } - template - void RemoveFlags(E& value, E flags) noexcept requires(IsEnum) + template + void RemoveFlags(E& value, E flags) noexcept { auto rawValue = static_cast>(value); rawValue &= ~static_cast>(flags); diff --git a/Include/Pipe/Core/Templates.h b/Include/Pipe/Core/Templates.h index a67f6fb9..2cf537d1 100644 --- a/Include/Pipe/Core/Templates.h +++ b/Include/Pipe/Core/Templates.h @@ -11,85 +11,6 @@ namespace p { - template - struct TTypeList - { - using type = TTypeList; - - static constexpr auto size = sizeof...(Type); - }; - - template - constexpr TTypeList operator+(TTypeList, TTypeList) - { - return {}; - } - - template - struct TTypeListIterator; - - template - struct TTypeListIterator> - : TTypeListIterator> - {}; - - template - struct TTypeListIterator<0u, TTypeList> - { - /*! @brief Searched type. */ - using type = Type; - }; - - template - struct TJoinList; - - template - struct TJoinList, TTypeList> - { - using Type = TTypeList; - }; - - template - struct TJoinList, BTypes...> - { - using Type = TTypeList; - }; - - template - using JoinList = TJoinList; - - - /** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ - template - using TTypeListIndex = typename TTypeListIterator::type; - - - namespace Internal - { - template - struct TTypeListContains; - - template - struct TTypeListContains> - : std::disjunction...> - {}; - - template - struct TTypeListContains> : std::disjunction...> - {}; - } // namespace Internal - - template - constexpr bool ListContains() - { - return Internal::TTypeListContains::value; - } - - template struct TPair { @@ -198,7 +119,7 @@ namespace p using TTuple = std::tuple; - namespace Internal + namespace Detail { template struct TTupleContains; @@ -210,11 +131,209 @@ namespace p template struct TTupleContains> : std::disjunction...> {}; - } // namespace Internal + } // namespace Detail template constexpr bool TupleContains() { - return Internal::TTupleContains::value; + return Detail::TTupleContains::value; + } + + + template + struct TTypeList; + + namespace Detail + { + template + struct TIsTypeList : FalseType + {}; + template + struct TIsTypeList> : TrueType + {}; + + template + struct TTypeListUnique + { + using Type = ResultList; + }; + + template + struct TTypeListUnique + { + using NextList = Select(), ResultList, + typename ResultList::template Append>; + using Type = typename TTypeListUnique::Type; + }; + + template typename Predicate> + struct TFilter; + + template typename Predicate> + struct TFilter, Predicate> + { + using Type = TTypeList<>; // Empty result + }; + + template typename Predicate> + struct TFilter, Predicate> + { + // Filter the remaining types (Tail...) + using FilteredTail = typename TFilter, Predicate>::Type; + // Include Head if predicate is true; otherwise, use FilteredTail directly + using Type = Select::value, + typename FilteredTail::template Prepend, // Prepend Head to FilteredTail + FilteredTail // Skip Head + >; + }; + }; // namespace Detail + + + template + concept IsTypeList = Detail::TIsTypeList::value; + + + template + struct TTypeList + { + using type = TTypeList; + + static constexpr auto size = sizeof...(T); + + + template + static consteval bool Contains() + { + return (std::is_same_v || ...); + } + + private: + template + struct TAppend + { + using Type = TTypeList; + }; + template + struct TAppend> + { + using Type = TTypeList; + }; + template + struct TPrepend + { + using Type = TTypeList; + }; + template + struct TPrepend> + { + using Type = TTypeList; + }; + + template + struct TAppendUnique : public Detail::TTypeListUnique, S...> + {}; + template + struct TAppendUnique> + : public Detail::TTypeListUnique, S...> + {}; + + template + struct TPrependUnique : public Detail::TTypeListUnique, T...> + {}; + template + struct TPrependUnique> + : public Detail::TTypeListUnique, T...> + {}; + + template + struct TFirst : TypeIdentity + {}; + template + struct TFirst : TypeIdentity + {}; + + + public: + template class W> + using Wrap = TTypeList...>; + + template class W> + using WrapPtr = TTypeList*...>; + + template class W> + using WrapConstPtr = TTypeList*...>; + + template class W> + using WrapRef = TTypeList&...>; + + template class W> + using WrapConstRef = TTypeList&...>; + + template class M> + using Map = TTypeList::Type...>; + + template + using Append = TAppend::Type; + + template + using Prepend = TPrepend::Type; + + template + using AppendUnique = TAppendUnique::Type; + + template + using PrependUnique = TPrependUnique::Type; + + using Deduplicate = typename Detail::template TTypeListUnique, T...>::Type; + + // Conversion + template class U> + using To = U; + + template + using First = typename TFirst::Type; + + template typename Predicate> + using Filter = Detail::TFilter, Predicate>::Type; + + static constexpr auto Call(auto predicate) + { + return predicate.template operator()(); + } + static constexpr void ForEach(auto predicate) + { + (predicate.template operator()(), ...); + } + }; + + template + constexpr TTypeList operator+(TTypeList, TTypeList) + { + return {}; } + + + template + struct TTypeListIterator; + + template + struct TTypeListIterator> + : TTypeListIterator> + {}; + + template + struct TTypeListIterator<0u, TTypeList> + { + /*! @brief Searched type. */ + using Type = T; + }; + + + /** + * @brief Helper type. + * @tparam Index Index of the type to return. + * @tparam List Type list to search into. + */ + template + using TTypeListIndex = typename TTypeListIterator::Type; } // namespace p diff --git a/Include/Pipe/Core/TypeTraits.h b/Include/Pipe/Core/TypeTraits.h index 52ec43fa..3cbafb2f 100644 --- a/Include/Pipe/Core/TypeTraits.h +++ b/Include/Pipe/Core/TypeTraits.h @@ -9,41 +9,61 @@ namespace p { + template + struct TypeIdentity + { + using Type = T; + }; + + template + struct Constant + { + static constexpr T value = v; + using ValueType = T; + using Type = Constant; + constexpr operator T() const noexcept + { + return value; + } + }; + using TrueType = Constant; + using FalseType = Constant; + namespace details { template - struct TIsRValueReference : std::false_type + struct TIsRValueReference : FalseType {}; template - struct TIsRValueReference : std::true_type + struct TIsRValueReference : TrueType {}; template - struct TIsLValueReference : std::false_type + struct TIsLValueReference : FalseType {}; template - struct TIsLValueReference : std::true_type + struct TIsLValueReference : TrueType {}; template - struct TIsChar : std::false_type + struct TIsChar : FalseType {}; template<> - struct TIsChar : std::true_type + struct TIsChar : TrueType {}; template<> - struct TIsChar : std::true_type + struct TIsChar : TrueType {}; template<> - struct TIsChar : std::true_type + struct TIsChar : TrueType {}; template<> - struct TIsChar : std::true_type + struct TIsChar : TrueType {}; // determine whether _Ty can be copy-initialized with {} template - struct TIsImplicitlyDefaultConstructible : std::false_type + struct TIsImplicitlyDefaultConstructible : FalseType {}; template @@ -51,7 +71,7 @@ namespace p template struct TIsImplicitlyDefaultConstructible({}))>> : std::true_type + std::void_t({}))>> : TrueType {}; } // namespace details @@ -294,10 +314,10 @@ namespace p template - struct HasInlineCapacityMember : std::false_type + struct HasInlineCapacityMember : FalseType {}; template - struct HasInlineCapacityMember : std::true_type + struct HasInlineCapacityMember : TrueType {}; template diff --git a/Include/PipeECS.h b/Include/PipeECS.h index dab482c1..377ec8fe 100644 --- a/Include/PipeECS.h +++ b/Include/PipeECS.h @@ -1,7 +1,6 @@ // Copyright 2015-2026 Piperift. All Rights Reserved. #pragma once -#include "Pipe/Core/Broadcast.h" #include "Pipe/Core/Map.h" #include "Pipe/Core/PageBuffer.h" #include "Pipe/Core/Templates.h" @@ -24,7 +23,7 @@ namespace p //////////////////////////////// // FORWARD DECLARATIONS // - struct EntityContext; + struct IdContext; //////////////////////////////// @@ -162,25 +161,56 @@ namespace p /** * Resolve an entity id from an string. * The expected format is {}:{} where first is the index and second is the version. - * If a context is provided, providing the index alone as a number will resolve it slast + * If a context is provided, providing the index alone as a number will resolve its last * valid version */ - P_API Id IdFromString(String str, EntityContext* context); + P_API Id IdFromString(String str, IdContext* context); #pragma endregion Ids #pragma region Components + // clang-format off + template + concept StoresLastModified = !IsEmpty && HasAnyTypeStaticFlags(TF_ECS_StoreLastModified) + && (IsCopyConstructible || IsMoveConstructible); + // clang-format on + + template + struct CMdfdWithLast + { + P_STRUCT(CMdfdWithLast, TF_NotSerialized) + + P_PROP(Last) + T Last; + }; + + struct CMdfdWithoutLast + {}; + /** * Modified component * Optionally, a component can be marked modified when written. This can be used when * filtering. */ template - struct CMdfd + struct CMdfd : public Select, CMdfdWithLast, CMdfdWithoutLast> { P_STRUCT(CMdfd, TF_NotSerialized) + + using Type = T; }; + template + static constexpr bool IsMdfdType() requires(!HasTypeMember) + { + return false; + } + template + static constexpr bool IsMdfdType() requires(HasTypeMember) + { + return IsSame, Component>; + } + /** * Removed component * Optionally, an entity can be marked removed instead of actually removed and then flushed @@ -282,7 +312,7 @@ namespace p using Super = Reader; P_STRUCT(EntityReader) - EntityContext& context; + IdContext& context; // While serializing we create ids as Ids appear and link them. TArray ids; @@ -290,8 +320,7 @@ namespace p public: - EntityReader(const p::Reader& parent, EntityContext& context) - : Reader(parent), context{context} + EntityReader(const p::Reader& parent, IdContext& context) : Reader(parent), context{context} {} void SerializeEntities(p::TArray& entities, TFunction onReadPools); @@ -308,7 +337,7 @@ namespace p } const TArray& GetIds() const; - EntityContext& GetContext(); + IdContext& GetContext(); protected: TypeId ProvideTypeId() const override @@ -323,7 +352,7 @@ namespace p using Super = Writer; P_STRUCT(EntityWriter) - EntityContext& context; + IdContext& context; // While serializing we create ids as Ids appear and link them. TArray ids; @@ -332,9 +361,7 @@ namespace p public: - EntityWriter(const Writer& parent, EntityContext& context) - : Writer(parent), context{context} - {} + EntityWriter(const Writer& parent, IdContext& context) : Writer(parent), context{context} {} void SerializeEntities(const TArray& entities, TFunction onWritePools, bool includeChildren = true); @@ -544,9 +571,6 @@ namespace p i32 lastRemovedIndex = NO_INDEX; PoolRemovePolicy removePolicy; - TBroadcast> onAdd; - TBroadcast> onRemove; - ComponentPool(TypeId typeId, PoolRemovePolicy removePolicy, Arena& arena); ComponentPool(const ComponentPool& other); @@ -554,21 +578,6 @@ namespace p ComponentPool& operator=(const ComponentPool& other) noexcept; ComponentPool& operator=(ComponentPool&& other) noexcept; - void OnAdded(TView ids) - { - if (!ids.IsEmpty()) - { - onAdd.Broadcast(ids); - } - } - - void OnRemoved(TView ids) - { - if (!ids.IsEmpty()) - { - onRemove.Broadcast(ids); - } - } public: virtual ~ComponentPool() {} @@ -614,16 +623,6 @@ namespace p return idList; } - TBroadcast>& OnAdd() - { - return onAdd; - } - - TBroadcast>& OnRemove() - { - return onRemove; - } - protected: Index EmplaceId(const Id id, bool forceBack); @@ -648,7 +647,7 @@ namespace p public: - TPool(p::EntityContext& ctx, Arena& arena = GetCurrentArena()) + TPool(p::IdContext& ctx, Arena& arena = GetCurrentArena()) : ComponentPool(p::GetTypeId(), PoolRemovePolicy::InPlace, arena), data{arena} {} TPool(const TPool& other) : ComponentPool(other), data{*other.arena} @@ -736,10 +735,8 @@ namespace p { data.Reserve(index + 1u); T* const value = data.Insert(index, p::Forward(args)...); - OnAdded({id}); return *value; } - OnAdded({id}); } } @@ -777,7 +774,6 @@ namespace p } } } - OnAdded(ids); } template @@ -826,12 +822,6 @@ namespace p } ++from; } - OnAdded(ids); - } - - T& GetOrAdd(const Id id) requires(!p::IsEmpty) - { - return Has(id) ? Get(id) : Add(id); } bool Remove(Id id) override @@ -847,7 +837,6 @@ namespace p void RemoveUnsafe(Id id) override { P_Check(Has(id)); - OnRemoved({id}); if (removePolicy == PoolRemovePolicy::InPlace) { Pop(id); @@ -860,7 +849,6 @@ namespace p i32 Remove(TView ids) override { - OnRemoved(ids); i32 removed = 0; if (removePolicy == PoolRemovePolicy::InPlace) { @@ -889,7 +877,6 @@ namespace p void RemoveUnsafe(TView ids) override { - OnRemoved(ids); if (removePolicy == PoolRemovePolicy::InPlace) { for (Id id : ids) @@ -960,12 +947,20 @@ namespace p void Reserve(sizet size) { idList.Reserve(size); - if (size > Size()) + if constexpr (!p::IsEmpty) { - data.Reserve(size); + if (size > Size()) + { + data.Reserve(size); + } } } + void ReserveMore(sizet size) + { + Reserve(Size() + size); + } + void Shrink() { idList.Shrink(); @@ -1059,13 +1054,13 @@ namespace p template<> struct P_API TPool : public IPool { - friend EntityContext; + friend IdContext; using T = CRemoved; p::IdRegistry* idRegistry = nullptr; public: - TPool(p::EntityContext& ctx, Arena& arena = GetCurrentArena()); + TPool(p::IdContext& ctx, Arena& arena = GetCurrentArena()); TPool(const TPool& other) = delete; TPool(TPool&& other) = delete; TPool& operator=(const TPool& other) @@ -1160,175 +1155,319 @@ namespace p //////////////////////////////// -// CONTEXT +// OPERATIONS // -#pragma region Context - enum class IdRemovePolicy : u8 +#pragma region Operations + /** + * IdOperations contains shared logic to view and edit components and statics in Contexts and + * Scopes This class assumes GetPool and AssurePool are present in Parent + */ + template + struct TIdOperations { - Instant, - Deferred - }; + const Parent& AsParent() const + { + return *static_cast(this); + } - struct P_API SortLessStatics - { - bool operator()(const OwnPtr& a, const OwnPtr& b) const + template + CopyConst>, Component>& AssurePool() const { - return a.GetId() < b.GetId(); - } // namespace p + return AsParent().template AssurePool(); + } - bool operator()(TypeId a, const OwnPtr& b) const + template + CopyConst>, Component>* GetPool() const { - return a < b.GetId(); + return AsParent().template GetPool(); } - bool operator()(const OwnPtr& a, TypeId b) const + IdContext& GetContext() const { - return a.GetId() < b; + return AsParent().GetContext(); } - }; - struct P_API EntityContext - { - private: - IdRegistry idRegistry; - mutable TArray pools; - TArray statics; - IdRemovePolicy removePolicy = IdRemovePolicy::Instant; + template + i32 Size() const + { + return GetPool()->Size(); + } + bool IsValid(Id id) const + { + return GetContext().IsValid(id); + } - public: - EntityContext(); - ~EntityContext() + template + bool Has(Id id) const { - Reset(); + const auto* pool = GetPool(); + return pool && pool->Has(id); + } + template + bool Has(Id id) const requires(sizeof...(Component) > 1) + { + return (Has(id) && ...); } - explicit EntityContext(const EntityContext& other) noexcept; - explicit EntityContext(EntityContext&& other) noexcept; - EntityContext& operator=(const EntityContext& other) noexcept; - EntityContext& operator=(EntityContext&& other) noexcept; -#pragma region Entities - // Reflection helpers - void* AddDefault(TypeId typeId, Id id); - void Remove(TypeId typeId, Id id); + template + void Modify(TView ids, TPool* pool = nullptr) const + { + auto& mdfdPool = AssurePool>(); + if constexpr (StoresLastModified) + { + if (!pool) + { + pool = GetPool(); + if (!pool) + { + return; + } + } + + mdfdPool.ReserveMore(ids.Size()); + for (Id id : ids) + { + if (!mdfdPool.Has(id)) // If we store value, we only add if it it wasn't + // modified already + { + Component* comp = pool->TryGet(id); + if constexpr (IsMoveConstructible) + { + mdfdPool.Add( + id, comp ? CMdfd{p::Move(*comp)} : CMdfd{}); + } + else + { + mdfdPool.Add(id, comp ? CMdfd{*comp} : CMdfd{}); + } + } + } + } + else + { + mdfdPool.Add(ids.begin(), ids.end(), CMdfd{}); + } + } - // Adds Component to an entity (if the entity doesnt have it already) - template - decltype(auto) Add(Id id, C&& value = {}) const requires(IsSame>) + template + bool IsModified(Id id) const { - P_Check(IsValid(id)); - return AssurePool().Add(id, p::Forward(value)); + return Has>>(id); } - template - decltype(auto) Add(Id id, const C& value) const requires(IsSame>) + + template + decltype(auto) Add(Id id, Component&& value = {}) const requires(IsMutable) { P_Check(IsValid(id)); - return AssurePool().Add(id, value); + auto& pool = AssurePool(); + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnAdd)) + { + Modify(id, &pool); + } + return pool.Add(id, p::Forward(value)); } - // Adds Component to an entity (if the entity doesnt have it already) - template - void Add(Id id) requires(sizeof...(Component) > 1) + template + decltype(auto) Add(Id id, const Component& value) const requires(IsMutable) { P_Check(IsValid(id)); - (Add(id), ...); + auto& pool = AssurePool(); + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnAdd)) + { + Modify(id, &pool); + } + return pool.Add(id, value); } - // Add Component to many entities (if they dont have it already) - template - decltype(auto) AddN(TView ids, const Component& value = {}) + // Add component to an entities (if they dont have it already) + template + void Add(Id id) const requires((IsMutable && ...) && sizeof...(Component) > 1) { - return AssurePool().Add(ids.begin(), ids.end(), value); + (Add(id), ...); } - // Add Components to many entities (if they don't have it already) - template - void AddN(TView ids) requires(sizeof...(Component) > 1) + // Add component to many entities (if they dont have it already) + template + decltype(auto) AddN(TView ids, const Component& value = {}) const { - (Add(ids), ...); + auto& pool = AssurePool(); + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnAdd)) + { + Modify(ids, &pool); + } + return pool.Add(ids.begin(), ids.end(), value); } template void AddN(TView ids, const TView& values) { P_Check(ids.Size() == values.Size()); - AssurePool().Add(ids.begin(), ids.end(), values.begin()); + auto& pool = AssurePool(); + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnAdd)) + { + Modify(ids, &pool); + } + pool.Add(ids.begin(), ids.end(), values.begin()); + } + + // Add components to many entities (if they dont have it already) + template + void AddN(TView ids) const + requires((IsMutable && ...) && sizeof...(Component) > 1) + { + (AddN(ids), ...); } template - void Remove(const Id id) + void Remove(const Id id) const requires(IsMutable) { if (auto* pool = GetPool()) { + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnRm)) + { + Modify(id, pool); + } pool->Remove(id); } } template - void Remove(const Id id) requires(sizeof...(Component) > 1) + void Remove(const Id id) const requires(sizeof...(Component) > 1) { (Remove(id), ...); } template - void Remove(TView ids) + void Remove(TView ids) const requires(IsMutable) { if (auto* pool = GetPool()) { + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnRm)) + { + Modify(ids, pool); + } pool->Remove(ids); } - - if constexpr (HasAnyTypeStaticFlags(TF_ECS_AutoModify)) - { - AssurePool>().Add(ids.begin(), ids.end(), {}); - } } template - void Remove(TView ids) requires(sizeof...(Component) > 1) + void Remove(TView ids) const requires(sizeof...(Component) > 1) { (Remove(ids), ...); } template - Component& Get(const Id id) const + Component& Get(Id id) const { auto* const pool = GetPool(); P_Check(pool); + if constexpr (IsMutable + && HasAnyTypeStaticFlags(TF_ECS_ModifyOnGet)) + { + Modify(id, pool); + } return pool->Get(id); } - template - TTuple Get(const Id id) const requires(sizeof...(Component) > 1) + + template + Component* TryGet(Id id) const { - return std::forward_as_tuple(Get(id)...); + auto* const pool = GetPool(); + P_Check(pool); + Component* value = pool->TryGet(id); + if constexpr (IsMutable + && HasAnyTypeStaticFlags(TF_ECS_ModifyOnGet)) + { + if (value) + { + Modify(id, pool); + } + } + return value; } + template - Component* TryGet(const Id id) const + Component& GetOrAdd(Id id) const requires(IsMutable) { - auto* const pool = GetPool(); - return pool ? pool->TryGet(id) : nullptr; + auto& pool = AssurePool(); + + if (pool.Has(id)) + { + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnGet)) + { + Modify(id, *pool); + } + return pool.Get(id); + } + else + { + if constexpr (HasAnyTypeStaticFlags(TF_ECS_ModifyOnAdd)) + { + Modify(id, *pool); + } + return pool.Add(id); + } } + template - TTuple TryGet(const Id id) const requires(sizeof...(Component) > 1) + void ClearPool() const { - return std::forward_as_tuple(TryGet(id)...); + (GetPool()->Clear(), ...); } + }; +#pragma endregion Operations - template - Component& GetOrAdd(Id id) + +//////////////////////////////// +// CONTEXT +// +#pragma region Context + enum class IdRemovePolicy : u8 + { + Instant, + Deferred + }; + + struct P_API SortLessStatics + { + bool operator()(const OwnPtr& a, const OwnPtr& b) const + { + return a.GetId() < b.GetId(); + } // namespace p + + bool operator()(TypeId a, const OwnPtr& b) const { - return AssurePool().GetOrAdd(id); + return a < b.GetId(); } - template - bool Has(Id id) const + bool operator()(const OwnPtr& a, TypeId b) const { - const auto* pool = GetPool(); - return pool && pool->Has(id); + return a.GetId() < b; } + }; - template - bool Has(Id id) const requires(sizeof...(Component) >= 2) + struct P_API IdContext : public TIdOperations + { + private: + IdRegistry idRegistry; + mutable TArray pools; + TArray statics; + IdRemovePolicy removePolicy = IdRemovePolicy::Instant; + + + public: + IdContext(); + ~IdContext() { - return (Has(id) && ...); + Reset(); } + explicit IdContext(const IdContext& other) noexcept; + explicit IdContext(IdContext&& other) noexcept; + IdContext& operator=(const IdContext& other) noexcept; + IdContext& operator=(IdContext&& other) noexcept; + +#pragma region Entities + // Reflection helpers + void* AddByTypeId(TypeId typeId, Id id); + void RemoveByTypeId(TypeId typeId, Id id); const IdRegistry& GetIdRegistry() const { @@ -1381,27 +1520,20 @@ namespace p void Reset(bool keepStatics = false); - template - TBroadcast>& OnAdd() + IdContext& GetContext() const { - return AssurePool().OnAdd(); - } - - template - TBroadcast>& OnRemove() - { - return AssurePool().OnRemove(); + return *const_cast(this); } // Finds or creates a pool template TPool>& AssurePool() const; - IPool* GetPool(TypeId componentId) const; - void GetPools(TView componentIds, TArray& outPools) const; - void GetPools(TView componentIds, TArray& outPools) const + IPool* GetPool(TypeId typeId) const; + void GetPools(TView typeIds, TArray& outPools) const; + void GetPools(TView typeIds, TArray& outPools) const { - GetPools(componentIds, reinterpret_cast&>(outPools)); + GetPools(typeIds, reinterpret_cast&>(outPools)); } template @@ -1467,8 +1599,8 @@ namespace p #pragma endregion Statics private: - void CopyFrom(const EntityContext& other); - void MoveFrom(EntityContext&& other); + void CopyFrom(const IdContext& other); + void MoveFrom(IdContext&& other); static OwnPtr& FindOrAddStaticPtr( TArray& statics, const TypeId typeId, bool* bAdded = nullptr); @@ -1480,105 +1612,83 @@ namespace p //////////////////////////////// -// ACCESSES +// ID SCOPES // -#pragma region Accesses - enum class AccessMode : u8 - { - Read, - Write - }; - - struct TypeAccess - { - TypeId typeId = TypeId::None(); - AccessMode mode = AccessMode::Read; - - constexpr TypeAccess() = default; - constexpr TypeAccess(TypeId typeId, AccessMode mode) : typeId{typeId}, mode{mode} {} - }; - - template - struct TTypeAccess : TypeAccess - { - using Type = Mut; - - constexpr TTypeAccess() : TypeAccess(GetTypeId(), inMode) {} - }; - +#pragma region IdScopes template - struct TRead : public TTypeAccess - {}; - - template - struct TWrite : public TTypeAccess - {}; - - template - struct TTypeAccessInfo - { - using Type = Mut; - static constexpr AccessMode mode = AccessMode::Read; - }; - template - requires Derived - struct TTypeAccessInfo + struct TIsAutoModified { - using Type = typename T::Type; - static constexpr AccessMode mode = T().mode; + static constexpr bool value = HasAnyTypeStaticFlags(TF_ECS_ModifyOnEdit); }; - template - using AsComponent = typename TTypeAccessInfo::Type; - template - struct TAccess + // Base for TIdScope. Assumes all types are mutable (not const) + template + struct TIdScopeBase : public TIdOperations> { - template - friend struct TAccess; - - using Components = TTypeList; - using RawComponents = TTypeList...>; + template + friend struct TIdScopeBase; private: - TypeId typeId; - EntityContext& context; - TTuple>*...> pools; + using ModifyWrites = W::template Filter::template Wrap; + using ModifyReads = TTypeList::template Filter::template Wrap; + public: + using WDependencies = W::template Append; + using RDependencies = TTypeList::template Append; + using RWDependencies = RDependencies::template Append::Deduplicate; + using Pools = RWDependencies::template WrapPtr; + using Tuple = Pools::template To; + + protected: + IdContext& context; + Tuple pools; public: - TAccess(EntityContext& context) - : context{context}, pools{&context.AssurePool>()...} + TIdScopeBase(IdContext& context) + : context{context}, pools(RWDependencies::Call([&context] { + return Tuple{&context.AssurePool()...}; + })) {} - TAccess(const TAccess& other) : context{other.context}, pools{other.pools} {} + TIdScopeBase(const TIdScopeBase& other) : context{other.context}, pools{other.pools} {} - // Construct a child access (super-set) from another access + // Construct a child scope (super-set) from another scope template - TAccess(const TAccess& other) : context{other.context} + TIdScopeBase(const TIdScopeBase& other) : context{other.context} { - using Other = TAccess; + using Other = TIdScopeBase; + + constexpr bool validReads = RWDependencies::Call([]() { + return (Other::template IsReadable() && ...); + }); + + constexpr bool validWrites = WDependencies::Call([]() { + return (Other::template IsWritable() && ...); + }); - constexpr bool validConstants = (Other::template HasType() && ...); - constexpr bool validMutables = - ((Other::template IsWritable() || TTypeAccessInfo::mode != AccessMode::Write) - && ...); - static_assert(validConstants, "Parent access lacks dependencies from this access."); static_assert( - validMutables, "Parent access lacks *mutable* dependencies from this access."); + validReads, "Parent scope lacks read dependencies required by this scope."); + static_assert( + validWrites, "Parent scope lacks *write* dependencies required by this scope."); - if constexpr (validConstants && validMutables) + // Prevent compiler errors, we already have static_asserts + if constexpr (validReads && validWrites) { - pools = {std::get>*>(other.pools)...}; + pools = RWDependencies::Call([&other] { + return Tuple{std::get*>(other.pools)...}; + }); } } - template - TPool>* GetPool() const requires(IsMutable) + + template + TPool>* GetPool() const requires(IsMutable) { - static_assert(IsWritable(), "Can't modify components of this type"); - if constexpr (IsWritable()) // Prevent missleading errors if condition fails + static_assert(IsWritable(), "Can't modify components of this type"); + if constexpr (IsWritable()) // Prevent missleading errors if condition + // fails { - return std::get>*>(pools); + return std::get>*>(pools); } else { @@ -1586,13 +1696,14 @@ namespace p } } - template - const TPool>* GetPool() const requires(IsConst) + template + const TPool>* GetPool() const requires(IsConst) { - static_assert(IsReadable(), "Can't read components of this type"); - if constexpr (IsReadable()) // Prevent missleading errors if condition fails + static_assert(IsReadable(), "Can't read components of this type"); + if constexpr (IsReadable()) // Prevent missleading errors if condition + // fails { - return std::get>*>(pools); + return std::get>*>(pools); } else { @@ -1600,184 +1711,93 @@ namespace p } } - template - TPool>& AssurePool() const requires(IsMutable) - { - return *GetPool(); - } - - template - const TPool>& AssurePool() const requires(IsConst) - { - return *GetPool(); - } - - bool IsValid(Id id) const - { - return context.IsValid(id); - } - - template - bool Has(Id id) const requires(sizeof...(C) >= 1) - { - return (GetPool()->Has(id) && ...); - } - - template - decltype(auto) Add(Id id, C&& value = {}) const requires(IsSame>) - { - return GetPool()->Add(id, p::Forward(value)); - } - template - decltype(auto) Add(Id id, const C& value) const requires(IsSame>) - { - return GetPool()->Add(id, value); - } - - // Add component to an entities (if they dont have it already) - template - void Add(Id id) const requires((IsSame> && ...) && sizeof...(C) > 1) - { - (Add(id), ...); - } - - // Add component to many entities (if they dont have it already) - template - decltype(auto) AddN(TView ids, const C& value = {}) const - { - return GetPool()->Add(ids.begin(), ids.end(), value); - } - - // Add components to many entities (if they dont have it already) - template - void AddN(TView ids) const - requires((IsSame> && ...) && sizeof...(C) > 1) - { - (AddN(ids), ...); - } - - - template - void Remove(const Id id) const requires(IsSame>) - { - if (auto* pool = GetPool()) - { - pool->Remove(id); - } - } - template - void Remove(const Id id) const requires(sizeof...(C) > 1) - { - (Remove(id), ...); - } - template - void Remove(TView ids) const requires(IsSame>) - { - if (auto* pool = GetPool()) - { - pool->Remove(ids); - } - } - template - void Remove(TView ids) const requires(sizeof...(C) > 1) + template + TPool& AssurePool() const requires(IsMutable) { - (Remove(ids), ...); + return *GetPool(); } - template - C& Get(Id id) const + template + const TPool>& AssurePool() const requires(IsConst) { - return GetPool()->Get(id); + return *GetPool(); } - template - C* TryGet(Id id) const - { - return GetPool()->TryGet(id); - } - template - C& GetOrAdd(Id id) const requires(IsMutable) + IdContext& GetContext() const { - return GetPool()->GetOrAdd(id); - } - - i32 Size() const - { - static_assert(sizeof...(T) == 1, "Can only get the size of single component accesses"); - return GetPool()->Size(); + return context; } - template - i32 Size() const + template + static constexpr bool IsMdfdType() requires(!HasTypeMember) { - return GetPool()->Size(); + return false; } - - template - void ClearPool() const + template + static constexpr bool IsMdfdType() requires(HasTypeMember) { - GetPool()->Clear(); + return IsSame, Component>; } - template - void ClearPool() const requires(sizeof...(C) > 1) + template + static constexpr bool IsReadable() { - (ClearPool(), ...); + return RWDependencies::template Contains>(); } - EntityContext& GetContext() const + template + static constexpr bool IsWritable() { - return context; + return IsMutable && WDependencies::template Contains(); } + }; - template - static constexpr bool HasType() - { - return ListContains>(); - } + template + struct Writes : public TTypeList + {}; - template - static constexpr bool IsReadable() - { - return HasType(); - } + template + struct TIdScope : public TIdScopeBase, Mut...> + { + using TIdScopeBase, Mut...>::TIdScopeBase; + }; - template - static constexpr bool IsWritable() - { - return IsMutable && ListContains>>(); - } + template + struct TIdScope, R...> : public TIdScopeBase...>, Mut...> + { + using TIdScopeBase...>, Mut...>::TIdScopeBase; }; + template - using TAccessRef = const TAccess&; + using TIdScopeRef = const TIdScope&; - struct Access + struct IdScope : public TIdOperations { protected: - EntityContext& ast; - TArray types; + IdContext& context; + // TArray types; TArray pools; public: - Access(EntityContext& ast, const TArray& types) : ast{ast} {} + IdScope(IdContext& ctx, const TArray& types) : context{ctx} {} template - Access(TAccessRef access) : ast{access.ast} + IdScope(TIdScopeRef scope) : context{scope.context} {} - template - TPool>* GetPool() const requires(IsMutable) + template + TPool>* GetPool() const requires(IsMutable) { return nullptr; } - template - const TPool>* GetPool() const requires(IsConst) + template + const TPool>* GetPool() const requires(IsConst) { return nullptr; } @@ -1789,7 +1809,7 @@ namespace p return 0; } }; -#pragma endregion Accesses +#pragma endregion IdScopees //////////////////////////////// @@ -1868,21 +1888,21 @@ namespace p /** * Remove ids containing a component from 'ids'. Does not guarantee order. * - * @param access from where to access pools + * @param scope from where to scope pools * @param ids array that will be modified * @param shouldShrink if true, the ids array will be shrink at the end * @see ExcludeIdsWithStable(), ExcludeIdsWithout() */ - template - void ExcludeIdsWith(const AccessType& access, TArray& ids, const bool shouldShrink = true) + template + void ExcludeIdsWith(const Scope& scope, TArray& ids, const bool shouldShrink = true) { - ExcludeIdsWith(&access.template AssurePool(), ids, shouldShrink); + ExcludeIdsWith(&scope.template AssurePool(), ids, shouldShrink); } - template - void ExcludeIdsWith(const AccessType& access, TArray& ids, const bool shouldShrink = true) - requires(sizeof...(C) > 1) + template + void ExcludeIdsWith(const Scope& scope, TArray& ids, const bool shouldShrink = true) + requires(sizeof...(Component) > 1) { - (ExcludeIdsWith(access, ids, shouldShrink), ...); + (ExcludeIdsWith(scope, ids, shouldShrink), ...); } template @@ -1904,82 +1924,79 @@ namespace p /** * Remove ids containing a component from 'ids'. Guarantees order. * - * @param access from where to access pools + * @param scope from where to scope pools * @param ids array that will be modified * @param shouldShrink if true, the ids array will be shrink at the end * @see ExcludeIdsWith(), ExcludeIdsWithoutStable() */ - template - void ExcludeIdsWithStable( - const AccessType& access, TArray& ids, const bool shouldShrink = true) + template + void ExcludeIdsWithStable(const Scope& scope, TArray& ids, const bool shouldShrink = true) { - ExcludeIdsWithStable(&access.template AssurePool(), ids, shouldShrink); + ExcludeIdsWithStable(&scope.template AssurePool(), ids, shouldShrink); } - template - void ExcludeIdsWithStable(const AccessType& access, TArray& ids, - const bool shouldShrink = true) requires(sizeof...(C) > 1) + template + void ExcludeIdsWithStable(const Scope& scope, TArray& ids, const bool shouldShrink = true) + requires(sizeof...(Component) > 1) { - (ExcludeIdsWithStable(access, ids, shouldShrink), ...); + (ExcludeIdsWithStable(scope, ids, shouldShrink), ...); } /** * Remove ids NOT containing a component from 'ids'. Does not guarantee order. * - * @param access from where to access pools + * @param scope from where to scope pools * @param ids array that will be modified * @param shouldShrink if true, the ids array will be shrink at the end * @see ExcludeIdsWithoutStable(), ExcludeIdsWith() */ - template - void ExcludeIdsWithout( - const AccessType& access, TArray& ids, const bool shouldShrink = true) + template + void ExcludeIdsWithout(const Scope& scope, TArray& ids, const bool shouldShrink = true) { - ExcludeIdsWithout(&access.template AssurePool(), ids, shouldShrink); + ExcludeIdsWithout(&scope.template AssurePool(), ids, shouldShrink); } - template - void ExcludeIdsWithout(const AccessType& access, TArray& ids, - const bool shouldShrink = true) requires(sizeof...(C) > 1) + template + void ExcludeIdsWithout(const Scope& scope, TArray& ids, const bool shouldShrink = true) + requires(sizeof...(Component) > 1) { - (ExcludeIdsWithout(access, ids, shouldShrink), ...); + (ExcludeIdsWithout(scope, ids, shouldShrink), ...); } /** * Remove ids NOT containing a component from 'ids'. Guarantees order. * - * @param access from where to access pools + * @param scope from where to scope pools * @param ids array that will be modified * @param shouldShrink if true, the ids array will be shrink at the end * @see ExcludeIdsWithout(), ExcludeIdsWithStable() */ - template + template void ExcludeIdsWithoutStable( - const AccessType& access, TArray& ids, const bool shouldShrink = true) + const Scope& scope, TArray& ids, const bool shouldShrink = true) { - ExcludeIdsWithoutStable(&access.template AssurePool(), ids, shouldShrink); + ExcludeIdsWithoutStable(&scope.template AssurePool(), ids, shouldShrink); } - template - void ExcludeIdsWithoutStable(const AccessType& access, TArray& ids, - const bool shouldShrink = true) requires(sizeof...(C) > 1) + template + void ExcludeIdsWithoutStable(const Scope& scope, TArray& ids, + const bool shouldShrink = true) requires(sizeof...(Component) > 1) { - (ExcludeIdsWithoutStable(access, ids, shouldShrink), ...); + (ExcludeIdsWithoutStable(scope, ids, shouldShrink), ...); } /** * Remove ids that are invalid. * - * @param access + * @param scope * @param ids array that will be modified * @param shouldShrink if true, the ids array will be shrink at the end * @see ExcludeIdsInvalidStable() */ - template - void ExcludeIdsInvalid( - const AccessType& access, TArray& ids, const bool shouldShrink = true) + template + void ExcludeIdsInvalid(const Scope& scope, TArray& ids, const bool shouldShrink = true) { ids.RemoveIfSwap( - [&access](Id id) { - return !access.IsValid(id); + [&scope](Id id) { + return !scope.IsValid(id); }, shouldShrink); } @@ -1987,55 +2004,55 @@ namespace p /** * Remove ids that are invalid. Guarantees order. * - * @param access + * @param scope * @param ids array that will be modified * @param shouldShrink if true, the ids array will be shrink at the end * @see ExcludeIdsInvalid() */ - template + template void ExcludeIdsInvalidStable( - const AccessType& access, TArray& ids, const bool shouldShrink = true) + const Scope& scope, TArray& ids, const bool shouldShrink = true) { ids.RemoveIf( - [&access](Id id) { - return !access.IsValid(id); + [&scope](Id id) { + return !scope.IsValid(id); }, shouldShrink); } /** Find ids containing a component from a list 'source' into 'results'. */ - template - void FindIdsWith(const AccessType& access, const TView& source, TArray& results) + template + void FindIdsWith(const Scope& scope, const TView& source, TArray& results) { - FindIdsWith(&access.template AssurePool(), source, results); + FindIdsWith(&scope.template AssurePool(), source, results); } - template - void FindIdsWith(const AccessType& access, const TView& source, TArray& results) - requires(sizeof...(C) > 1) + template + void FindIdsWith(const Scope& scope, const TView& source, TArray& results) + requires(sizeof...(Component) > 1) { - FindIdsWith({&access.template AssurePool()...}, source, results); + FindIdsWith({&scope.template AssurePool()...}, source, results); } - template - TArray FindIdsWith(const AccessType& access, const TView& source) + template + TArray FindIdsWith(const Scope& scope, const TView& source) { TArray results; - FindIdsWith(access, source, results); + FindIdsWith(scope, source, results); return Move(results); } /** Find ids NOT containing a component from a list 'source' into 'results'. */ - template - void FindIdsWithout(const AccessType& access, const TArray& source, TArray& results) + template + void FindIdsWithout(const Scope& scope, const TArray& source, TArray& results) { - FindIdsWithout(&access.template AssurePool(), source, results); + FindIdsWithout(&scope.template AssurePool(), source, results); } - template - TArray FindIdsWithout(const AccessType& access, const TArray& source) + template + TArray FindIdsWithout(const Scope& scope, const TArray& source) { TArray results; - FindIdsWithout(access, source, results); + FindIdsWithout(scope, source, results); return Move(results); } @@ -2043,18 +2060,18 @@ namespace p * Find and remove ids containing a component from list 'source' into 'results'. * Does not guarantee order. */ - template - void ExtractIdsWith(const AccessType& access, TArray& source, TArray& results, - const bool shouldShrink = true) + template + void ExtractIdsWith( + const Scope& scope, TArray& source, TArray& results, const bool shouldShrink = true) { - ExtractIdsWith(&access.template AssurePool(), source, results); + ExtractIdsWith(&scope.template AssurePool(), source, results); } - template + template TArray ExtractIdsWith( - const AccessType& access, TArray& source, const bool shouldShrink = true) + const Scope& scope, TArray& source, const bool shouldShrink = true) { TArray results; - ExtractIdsWith(access, source, results); + ExtractIdsWith(scope, source, results); return Move(results); } @@ -2062,18 +2079,18 @@ namespace p * Find and remove ids containing a component from list 'source' into 'results'. * Guarantees order. */ - template - void ExtractIdsWithStable(const AccessType& access, TArray& source, TArray& results, - const bool shouldShrink = true) + template + void ExtractIdsWithStable( + const Scope& scope, TArray& source, TArray& results, const bool shouldShrink = true) { - ExtractIdsWithStable(&access.template AssurePool(), source, results); + ExtractIdsWithStable(&scope.template AssurePool(), source, results); } - template + template TArray ExtractIdsWithStable( - const AccessType& access, TArray& source, const bool shouldShrink = true) + const Scope& scope, TArray& source, const bool shouldShrink = true) { TArray results; - ExtractIdsWithStable(access, source, results); + ExtractIdsWithStable(scope, source, results); return Move(results); } @@ -2081,18 +2098,18 @@ namespace p * Find and remove ids containing a component from list 'source' into 'results'. * Does not guarantee order. */ - template - void ExtractIdsWithout(const AccessType& access, TArray& source, TArray& results, - const bool shouldShrink = true) + template + void ExtractIdsWithout( + const Scope& scope, TArray& source, TArray& results, const bool shouldShrink = true) { - ExtractIdsWithout(&access.template AssurePool(), source, results); + ExtractIdsWithout(&scope.template AssurePool(), source, results); } - template + template TArray ExtractIdsWithout( - const AccessType& access, TArray& source, const bool shouldShrink = true) + const Scope& scope, TArray& source, const bool shouldShrink = true) { TArray results; - ExtractIdsWithout(access, source, results); + ExtractIdsWithout(scope, source, results); return Move(results); } @@ -2100,18 +2117,18 @@ namespace p * Find and remove ids not containing a component from list 'source' into 'results'. * Guarantees order. */ - template - void ExtractIdsWithoutStable(const AccessType& access, TArray& source, TArray& results, - const bool shouldShrink = true) + template + void ExtractIdsWithoutStable( + const Scope& scope, TArray& source, TArray& results, const bool shouldShrink = true) { - ExtractIdsWithoutStable(&access.template AssurePool(), source, results); + ExtractIdsWithoutStable(&scope.template AssurePool(), source, results); } - template + template TArray ExtractIdsWithoutStable( - const AccessType& access, TArray& source, const bool shouldShrink = true) + const Scope& scope, TArray& source, const bool shouldShrink = true) { TArray results; - ExtractIdsWithoutStable(access, source, results); + ExtractIdsWithoutStable(scope, source, results); return Move(results); } @@ -2119,29 +2136,29 @@ namespace p /** * Find all ids containing all of the components * - * @param access from where to access pools + * @param scope from where to scope pools * @param ids array where matching ids will be added * @see FindAllIdsWithAny() */ - template - void FindAllIdsWith(const AccessType& access, TArray& ids) requires(sizeof...(C) >= 1) + template + void FindAllIdsWith(const Scope& scope, TArray& ids) requires(sizeof...(Component) >= 1) { - FindAllIdsWith({access.template GetPool()...}, ids); + FindAllIdsWith({scope.template GetPool()...}, ids); } /** * Find all ids containing all of the components * - * @param access from where to access pools + * @param scope from where to scope pools * @return ids array with matching ids * @see FindAllIdsWithAny() */ - template - TArray FindAllIdsWith(const AccessType& access) requires(sizeof...(C) >= 1) + template + TArray FindAllIdsWith(const Scope& scope) requires(sizeof...(Component) >= 1) { TArray ids; - FindAllIdsWith(access, ids); + FindAllIdsWith(scope, ids); return Move(ids); } @@ -2149,44 +2166,44 @@ namespace p * Find all ids containing any of the components. * Includes possible duplicates * - * @param access from where to access pools + * @param scope from where to scope pools * @param ids array where matching ids will be added * @see FindAllIdsWith() */ - template - void FindAllIdsWithAny(const AccessType& access, TArray& ids) requires(sizeof...(C) >= 1) + template + void FindAllIdsWithAny(const Scope& scope, TArray& ids) requires(sizeof...(Component) >= 1) { - FindAllIdsWithAny({access.template GetPool()...}, ids); + FindAllIdsWithAny({scope.template GetPool()...}, ids); } /** * Find all ids containing any of the components. * Prevents duplicates * - * @param access from where to access pools + * @param scope from where to scope pools * @param ids array where matching ids will be added * @see FindAllIdsWithAnyUnique() */ - template - void FindAllIdsWithAnyUnique(const AccessType& access, TArray& ids) - requires(sizeof...(C) >= 1) + template + void FindAllIdsWithAnyUnique(const Scope& scope, TArray& ids) + requires(sizeof...(Component) >= 1) { - FindAllIdsWithAnyUnique({access.template GetPool()...}, ids); + FindAllIdsWithAnyUnique({scope.template GetPool()...}, ids); } /** * Find all ids containing any of the components. * Includes possible duplicates * - * @param access from where to access pools + * @param scope from where to scope pools * @return ids array with matching ids * @see FindAllIdsWith() */ - template - TArray FindAllIdsWithAny(const AccessType& access) requires(sizeof...(C) >= 1) + template + TArray FindAllIdsWithAny(const Scope& scope) requires(sizeof...(Component) >= 1) { TArray ids; - FindAllIdsWithAny(access, ids); + FindAllIdsWithAny(scope, ids); return Move(ids); } @@ -2194,22 +2211,22 @@ namespace p * Find all ids containing any of the components. * Prevents duplicates * - * @param access from where to access pools + * @param scope from where to scope pools * @return ids array with matching ids * @see FindAllIdsWithAny() */ - template - TArray FindAllIdsWithAnyUnique(const AccessType& access) requires(sizeof...(C) >= 1) + template + TArray FindAllIdsWithAnyUnique(const Scope& scope) requires(sizeof...(Component) >= 1) { TArray ids; - FindAllIdsWithAnyUnique(access, ids); + FindAllIdsWithAnyUnique(scope, ids); return Move(ids); } - template - Id GetFirstIdWith(const AccessType& access) + template + Id GetFirstIdWith(const Scope& scope) { - return GetFirstIdWith({access.template GetPool()...}); + return GetFirstIdWith({scope.template GetPool()...}); } #pragma endregion Filtering @@ -2220,12 +2237,12 @@ namespace p #pragma region Editing // Create - P_API Id AddId(EntityContext& ctx); - P_API void AddId(EntityContext& ctx, TView Ids); + P_API Id AddId(IdContext& ctx); + P_API void AddId(IdContext& ctx, TView Ids); // Remove - P_API bool RmId(EntityContext& ctx, TView ids, RmIdFlags flags = RmIdFlags::None); - P_API bool FlushDeferredRemovals(EntityContext& ctx); + P_API bool RmId(IdContext& ctx, TView ids, RmIdFlags flags = RmIdFlags::None); + P_API bool FlushDeferredRemovals(IdContext& ctx); #pragma endregion Editing @@ -2236,23 +2253,23 @@ namespace p // Link a list of nodes at the end of the parent children list P_API void AttachId( - TAccessRef, TWrite> access, Id parent, TView children); + TIdScopeRef> scope, Id parent, TView children); // Link a list of nodes after prevChild in the list of children nodes - P_API void AttachIdAfter(TAccessRef, TWrite> access, Id parent, - TView childrenIds, Id prevChild); - P_API void TransferIdChildren(TAccessRef, TWrite> access, - TView childrenIds, Id destination); - // TODO: void TransferAllChildren(Tree& ast, Id origin, Id destination); - P_API void DetachIdParent(TAccessRef, TWrite> access, + P_API void AttachIdAfter( + TIdScopeRef> scope, Id parent, TView childrenIds, Id prevChild); + P_API void TransferIdChildren( + TIdScopeRef> scope, TView childrenIds, Id destination); + // TODO: void TransferAllChildren(IdContext& context, Id origin, Id destination); + P_API void DetachIdParent(TIdScopeRef> scope, TView childrenIds, bool keepComponents); - P_API void DetachIdChildren(TAccessRef, TWrite> access, - TView parents, bool keepComponents = false); + P_API void DetachIdChildren(TIdScopeRef> scope, TView parents, + bool keepComponents = false); /** Obtain direct children ids from the provided parent Id. Examples: * - Children of A (where A->B->C) is B. * - Children of A (where A->B, A->C) are B and C. */ - P_API const TArray* GetIdChildren(TAccessRef access, Id node); + P_API const TArray* GetIdChildren(TIdScopeRef scope, Id node); /** Obtain direct children ids from the provided parent Ids. Examples: * - Children of A (where A->B->C) is B. @@ -2260,7 +2277,7 @@ namespace p * - Children of A and B (where A->B->C) are B, C. */ P_API void GetIdChildren( - TAccessRef access, TView nodes, TArray& outChildrenIds); + TIdScopeRef scope, TView nodes, TArray& outChildrenIds); /** Obtain all children ids from the provided parent Ids. Examples: * - All children of A (where A->B->C) are B and C. @@ -2268,25 +2285,25 @@ namespace p * - All children of A and B (where A->B->C->D) are B, C, D, C, D (duplicates are not * handled). */ - P_API void GetAllIdChildren(TAccessRef access, TView parentIds, + P_API void GetAllIdChildren(TIdScopeRef scope, TView parentIds, TArray& outChildrenIds, u32 depth = 1); - P_API Id GetIdParent(TAccessRef access, Id childId); + P_API Id GetIdParent(TIdScopeRef scope, Id childId); P_API void GetIdParent( - TAccessRef access, TView childrenIds, TArray& outParents); + TIdScopeRef scope, TView childrenIds, TArray& outParents); P_API void GetAllIdParents( - TAccessRef access, TView childrenIds, TArray& outParents); + TIdScopeRef scope, TView childrenIds, TArray& outParents); /** * Find a parent id matching a delegate */ - P_API Id FindIdParent(TAccessRef access, Id child, const TFunction& callback); - P_API void FindIdParents(TAccessRef access, TView childrenIds, + P_API Id FindIdParent(TIdScopeRef scope, Id child, const TFunction& callback); + P_API void FindIdParents(TIdScopeRef scope, TView childrenIds, TArray& outParents, const TFunction& callback); - // void Copy(Tree& ast, t TArray& nodes, TArray& outNewNodes); - // void CopyDeep(Tree& ast, const TArray& rootNodes, TArray& outNewRootNodes); - // void CopyAndTransferAllChildrenDeep(Tree& ast, Id root, Id otherRoot); + // void Copy(IdContext& context, t TArray& nodes, TArray& outNewNodes); + // void CopyDeep(IdContext& context, const TArray& rootNodes, TArray& outNewRootNodes); + // void CopyAndTransferAllChildrenDeep(IdContext& context, Id root, Id otherRoot); /** * Iterates children nodes making sure child->parent links are correct or fixed @@ -2295,7 +2312,7 @@ namespace p * @parents: where to look for children to fix up * @return true if an incorrect link was found and fixed */ - P_API bool FixParentIdLinks(TAccessRef, CParent> access, TView parents); + P_API bool FixParentIdLinks(TIdScopeRef, CParent> scope, TView parents); /** * Iterates children nodes looking for invalid child->parent links @@ -2304,9 +2321,9 @@ namespace p * @parents: where to look for children * @return true if an incorrect link was found */ - P_API bool ValidateParentIdLinks(TAccessRef access, TView parents); + P_API bool ValidateParentIdLinks(TIdScopeRef scope, TView parents); - P_API void GetRootIds(TAccessRef access, TArray& outRoots); + P_API void GetRootIds(TIdScopeRef scope, TArray& outRoots); #pragma endregion Hierarchy @@ -2352,7 +2369,7 @@ namespace p BeginObject(); for (i32 i = 0; i < ids.Size(); ++i) { - const Id node = ids[i]; + const Id id = ids[i]; key.clear(); Strings::FormatTo(key, "{}", i); @@ -2360,12 +2377,12 @@ namespace p { if constexpr (!IsEmpty) { - T& comp = pool.GetOrAdd(node); + T& comp = pool.Has(id) ? pool.Get(id) : pool.Add(id); Serialize(comp); } else { - pool.Add(node); + pool.Add(id); } Leave(); } @@ -2375,7 +2392,8 @@ namespace p { if constexpr (!IsEmpty) { - T& comp = pool.GetOrAdd(ids[0]); + const Id id = ids[0]; + T& comp = pool.Has(id) ? pool.Get(id) : pool.Add(id); Serialize(comp); } else @@ -2390,23 +2408,23 @@ namespace p template inline void EntityWriter::SerializePool() { - TArray> componentIds; // TODO: Make sure this is needed + TArray> typeIds; // TODO: Make sure this is needed auto* pool = context.GetPool(); if (pool) { - componentIds.Reserve(Min(i32(pool->Size()), ids.Size())); + typeIds.Reserve(Min(i32(pool->Size()), ids.Size())); for (i32 i = 0; i < ids.Size(); ++i) { const Id id = ids[i]; if (pool->Has(id)) { - componentIds.Add({i, id}); + typeIds.Add({i, id}); } } } - if (componentIds.IsEmpty()) + if (typeIds.IsEmpty()) { return; } @@ -2420,7 +2438,7 @@ namespace p { String key; BeginObject(); - for (auto id : componentIds) + for (auto id : typeIds) { key.clear(); Strings::FormatTo(key, "{}", id.first); @@ -2443,7 +2461,7 @@ namespace p } else { - Serialize(pool->Get(componentIds.First().second)); + Serialize(pool->Get(typeIds.First().second)); } } Leave(); @@ -2453,7 +2471,7 @@ namespace p template - inline TPool>& EntityContext::AssurePool() const + inline TPool>& IdContext::AssurePool() const { const TypeId componentId = RegisterTypeId>(); @@ -2475,17 +2493,17 @@ namespace p } template - inline PoolInstance EntityContext::CreatePoolInstance() const + inline PoolInstance IdContext::CreatePoolInstance() const { constexpr TypeId componentId = GetTypeId>(); - auto& self = const_cast(*this); + auto& self = const_cast(*this); PoolInstance instance{componentId, MakeUnique>>(self)}; return Move(instance); } template - inline Static& EntityContext::SetStatic() + inline Static& IdContext::SetStatic() { OwnPtr& ptr = FindOrAddStaticPtr(statics, GetTypeId()); ptr = MakeOwned(); @@ -2493,7 +2511,7 @@ namespace p } template - inline Static& EntityContext::SetStatic(Static&& value) + inline Static& IdContext::SetStatic(Static&& value) { OwnPtr& ptr = FindOrAddStaticPtr(statics, GetTypeId()); ptr = MakeOwned(p::Forward(value)); @@ -2501,7 +2519,7 @@ namespace p } template - inline Static& EntityContext::SetStatic(const Static& value) + inline Static& IdContext::SetStatic(const Static& value) { OwnPtr& ptr = FindOrAddStaticPtr(statics, GetTypeId()); ptr = MakeOwned(value); @@ -2509,7 +2527,7 @@ namespace p } template - inline Static& EntityContext::GetOrSetStatic() + inline Static& IdContext::GetOrSetStatic() { bool bAdded = false; OwnPtr& ptr = FindOrAddStaticPtr(statics, GetTypeId(), &bAdded); @@ -2521,7 +2539,7 @@ namespace p } template - inline Static& EntityContext::GetOrSetStatic(Static&& value) + inline Static& IdContext::GetOrSetStatic(Static&& value) { bool bAdded = false; OwnPtr& ptr = FindOrAddStaticPtr(statics, GetTypeId(), &bAdded); @@ -2533,7 +2551,7 @@ namespace p } template - inline Static& EntityContext::GetOrSetStatic(const Static& value) + inline Static& IdContext::GetOrSetStatic(const Static& value) { bool bAdded = false; OwnPtr& ptr = FindOrAddStaticPtr(statics, GetTypeId(), &bAdded); diff --git a/Include/PipeECSFwd.h b/Include/PipeECSFwd.h index 41df992f..ccb25959 100644 --- a/Include/PipeECSFwd.h +++ b/Include/PipeECSFwd.h @@ -25,23 +25,17 @@ namespace p::ecs struct SortLessStatics; - struct EntityContext; + struct IdContext; + + template + struct TTypeList; // TODO: Move to a TemplatesFwd header + + struct IdScope; - enum class AccessMode : u8; - struct TypeAccess; - template - struct TTypeAccess; - template - struct TRead; - template - struct TWrite; - template - struct TTypeAccessInfo; template - struct TAccess; + struct TIdScope; template - using TAccessRef = const TAccess&; - struct Access; + using TIdScopeRef = const TIdScope&; struct CChild; struct CParent; diff --git a/Include/PipeReflect.h b/Include/PipeReflect.h index 61e3b51e..de637773 100644 --- a/Include/PipeReflect.h +++ b/Include/PipeReflect.h @@ -198,8 +198,17 @@ namespace p TF_Object = 1 << 4, TF_Container = 1 << 6, - TF_ECS_AutoModify = 1 << 7 // -> In ECS, should this type be marked modified - // automatically when added, written or removed? + // -> In ECS, should this type's last value be stored in the CMdfd component before being + // removed? + TF_ECS_StoreLastModified = 1 << 7, + // -> In ECS, should this type be marked modified automatically on add? + TF_ECS_ModifyOnAdd = 1 << 8, + // -> In ECS, should this type be marked modified automatically on get? + TF_ECS_ModifyOnGet = 1 << 9, + // -> In ECS, should this type be marked modified automatically on remove? + TF_ECS_ModifyOnRm = 1 << 10, + // -> In ECS, should this type be marked modified automatically on add, get or remove? + TF_ECS_ModifyOnEdit = TF_ECS_ModifyOnAdd | TF_ECS_ModifyOnGet | TF_ECS_ModifyOnRm, // Any other flags up to 64 bytes are available to the user }; @@ -352,7 +361,7 @@ namespace p { if constexpr (HasStaticFlags()) { - return (T::staticFlags & flags) == flags; + return HasAllFlags(T::staticFlags, flags); } return false; } @@ -361,7 +370,7 @@ namespace p { if constexpr (HasStaticFlags()) { - return (T::staticFlags & flags) > 0; + return HasAnyFlags(T::staticFlags, flags); } return false; } diff --git a/Src/PipeECS.cpp b/Src/PipeECS.cpp index 82dc04fa..e9a7347a 100644 --- a/Src/PipeECS.cpp +++ b/Src/PipeECS.cpp @@ -6,10 +6,12 @@ #include "Pipe/Core/Limits.h" #include "Pipe/Core/Set.h" +#include + namespace p { - Id IdFromString(String str, EntityContext* context) + Id IdFromString(String str, IdContext* context) { if (str == "NoId") { @@ -255,7 +257,7 @@ namespace p return ids; } - EntityContext& EntityReader::GetContext() + IdContext& EntityReader::GetContext() { return context; } @@ -326,7 +328,7 @@ namespace p void EntityWriter::RemoveIgnoredEntities(TArray& entities) { - TAccess access{context}; + TIdScope access{context}; for (i32 i = 0; i < entities.Size(); ++i) { if (access.Has(entities[i])) @@ -547,7 +549,7 @@ namespace p }; } - TPool::TPool(p::EntityContext& ctx, Arena& arena) + TPool::TPool(p::IdContext& ctx, Arena& arena) : IPool(p::GetTypeId()), idRegistry{&ctx.GetIdRegistry()} {} @@ -638,33 +640,33 @@ namespace p } - EntityContext::EntityContext() + IdContext::IdContext() { AssurePool(); } - EntityContext::EntityContext(const EntityContext& other) noexcept + IdContext::IdContext(const IdContext& other) noexcept { CopyFrom(other); } - EntityContext::EntityContext(EntityContext&& other) noexcept + IdContext::IdContext(IdContext&& other) noexcept { MoveFrom(Move(other)); } - EntityContext& EntityContext::operator=(const EntityContext& other) noexcept + IdContext& IdContext::operator=(const IdContext& other) noexcept { Reset(); CopyFrom(other); return *this; } - EntityContext& EntityContext::operator=(EntityContext&& other) noexcept + IdContext& IdContext::operator=(IdContext&& other) noexcept { Reset(); MoveFrom(Move(other)); return *this; } - void* EntityContext::AddDefault(TypeId typeId, Id id) + void* IdContext::AddByTypeId(TypeId typeId, Id id) { if (IPool* pool = GetPool(typeId)) { @@ -673,7 +675,7 @@ namespace p return nullptr; } - void EntityContext::Remove(TypeId typeId, Id id) + void IdContext::RemoveByTypeId(TypeId typeId, Id id) { if (IPool* pool = GetPool(typeId)) { @@ -681,15 +683,15 @@ namespace p } } - IPool* EntityContext::GetPool(TypeId componentId) const + IPool* IdContext::GetPool(TypeId componentId) const { const i32 index = pools.FindSorted(PoolInstance{componentId, {}}); return index != NO_INDEX ? pools[index].GetPool() : nullptr; } - void EntityContext::GetPools(TView componentIds, TArray& outPools) const + void IdContext::GetPools(TView typeIds, TArray& outPools) const { - for (const TypeId componentId : componentIds) + for (const TypeId componentId : typeIds) { const i32 index = pools.FindSorted(PoolInstance{componentId, {}}); if (index != NO_INDEX) @@ -699,7 +701,7 @@ namespace p } } - void EntityContext::CopyFrom(const EntityContext& other) + void IdContext::CopyFrom(const IdContext& other) { // Copy entities idRegistry = other.idRegistry; @@ -719,7 +721,7 @@ namespace p // TODO: Cache pools } - void EntityContext::MoveFrom(EntityContext&& other) + void IdContext::MoveFrom(IdContext&& other) { idRegistry = Move(other.idRegistry); pools = Move(other.pools); @@ -731,17 +733,17 @@ namespace p // TODO: Cache pools } - bool EntityContext::IsValid(Id id) const + bool IdContext::IsValid(Id id) const { return idRegistry.IsValid(id); } - bool EntityContext::WasRemoved(Id id) const + bool IdContext::WasRemoved(Id id) const { return idRegistry.WasRemoved(id); } - bool EntityContext::IsOrphan(const Id id) const + bool IdContext::IsOrphan(const Id id) const { for (const auto& instance : pools) { @@ -753,21 +755,21 @@ namespace p return true; } - void* EntityContext::TryGetStatic(TypeId typeId) + void* IdContext::TryGetStatic(TypeId typeId) { const i32 index = statics.FindSorted(typeId); return index != NO_INDEX ? statics[index].Get() : nullptr; } - const void* EntityContext::TryGetStatic(TypeId typeId) const + const void* IdContext::TryGetStatic(TypeId typeId) const { const i32 index = statics.FindSorted(typeId); return index != NO_INDEX ? statics[index].Get() : nullptr; } - bool EntityContext::HasStatic(TypeId typeId) const + bool IdContext::HasStatic(TypeId typeId) const { return statics.FindSorted(typeId) != NO_INDEX; } - bool EntityContext::RemoveStatic(TypeId typeId) + bool IdContext::RemoveStatic(TypeId typeId) { const i32 index = statics.FindSorted(typeId); if (index != NO_INDEX) @@ -778,7 +780,7 @@ namespace p return false; } - void EntityContext::Reset(bool keepStatics) + void IdContext::Reset(bool keepStatics) { idRegistry = {}; pools.Clear(); @@ -788,7 +790,7 @@ namespace p } } - OwnPtr& EntityContext::FindOrAddStaticPtr( + OwnPtr& IdContext::FindOrAddStaticPtr( TArray& statics, const TypeId typeId, bool* bAdded) { i32 index = statics.LowerBound(typeId); @@ -1100,7 +1102,7 @@ namespace p } - void RemoveChildFromCParent(TAccessRef> access, Id parent, Id child) + void RemoveChildFromCParent(TIdScopeRef> access, Id parent, Id child) { if (auto* cParent = access.TryGet(parent)) { @@ -1113,16 +1115,16 @@ namespace p } - Id AddId(EntityContext& ctx) + Id AddId(IdContext& ctx) { return ctx.GetIdRegistry().Create(); } - void AddId(EntityContext& ctx, TView ids) + void AddId(IdContext& ctx, TView ids) { ctx.GetIdRegistry().Create(ids); } - bool RmId(EntityContext& ctx, TView ids, RmIdFlags flags) + bool RmId(IdContext& ctx, TView ids, RmIdFlags flags) { TArray allIds; // Only used when removing children. Here for scope purposes. if (!HasFlag(flags, p::RmIdFlags::KeepChildren)) @@ -1147,7 +1149,7 @@ namespace p } } - bool FlushDeferredRemovals(EntityContext& ctx) + bool FlushDeferredRemovals(IdContext& ctx) { TView ids = ctx.GetIdRegistry().GetDeferredRemovals(); for (auto& pool : ctx.GetPools()) @@ -1158,8 +1160,7 @@ namespace p } - void AttachId( - TAccessRef, TWrite> access, Id parent, TView children) + void AttachId(TIdScopeRef> access, Id parent, TView children) { children.Each([&access, parent](Id childId) { if (auto* cChild = access.TryGet(childId)) @@ -1181,8 +1182,8 @@ namespace p access.GetOrAdd(parent).children.Append(children); } - void AttachIdAfter(TAccessRef, TWrite> access, Id parent, - TView childrenIds, Id prevChild) + void AttachIdAfter( + TIdScopeRef> access, Id parent, TView childrenIds, Id prevChild) { childrenIds.Each([&access, parent](Id child) { if (auto* cChild = access.TryGet(child)) @@ -1205,15 +1206,15 @@ namespace p childrenList.Insert(prevIndex, childrenIds); } - void TransferIdChildren(TAccessRef, TWrite> access, - TView childrenIds, Id destination) + void TransferIdChildren( + TIdScopeRef> access, TView childrenIds, Id destination) { DetachIdParent(access, childrenIds, true); AttachId(access, destination, childrenIds); } - void DetachIdParent(TAccessRef, TWrite> access, - TView childrenIds, bool keepComponents) + void DetachIdParent(TIdScopeRef> access, TView childrenIds, + bool keepComponents) { TArray parents; parents.Reserve(childrenIds.Size()); @@ -1275,8 +1276,8 @@ namespace p } } - void DetachIdChildren(TAccessRef, TWrite> access, - TView parents, bool keepComponents) + void DetachIdChildren( + TIdScopeRef> access, TView parents, bool keepComponents) { if (keepComponents) { @@ -1306,14 +1307,14 @@ namespace p } } - const TArray* GetIdChildren(TAccessRef access, Id node) + const TArray* GetIdChildren(TIdScopeRef access, Id node) { auto* cParent = access.TryGet(node); return cParent ? &cParent->children : nullptr; } void GetIdChildren( - TAccessRef access, TView parentIds, TArray& outChildrenIds) + TIdScopeRef access, TView parentIds, TArray& outChildrenIds) { parentIds.Each([&access, &outChildrenIds](Id id) { if (const auto* cParent = access.TryGet(id)) @@ -1323,7 +1324,7 @@ namespace p }); } - void GetAllIdChildren(TAccessRef access, TView parentIds, + void GetAllIdChildren(TIdScopeRef access, TView parentIds, TArray& outChildrenIds, u32 depth) { P_Check(depth > 0); @@ -1339,7 +1340,7 @@ namespace p } } - Id GetIdParent(TAccessRef access, Id childId) + Id GetIdParent(TIdScopeRef access, Id childId) { if (const auto* cChild = access.TryGet(childId)) { @@ -1348,7 +1349,8 @@ namespace p return NoId; } - void GetIdParent(TAccessRef access, TView childrenIds, TArray& outParents) + void GetIdParent( + TIdScopeRef access, TView childrenIds, TArray& outParents) { outParents.Clear(false); for (Id childId : childrenIds) @@ -1361,7 +1363,7 @@ namespace p } } void GetAllIdParents( - TAccessRef access, TView childrenIds, TArray& outParents) + TIdScopeRef access, TView childrenIds, TArray& outParents) { outParents.Clear(false); @@ -1377,7 +1379,7 @@ namespace p } } - Id FindIdParent(TAccessRef access, Id childId, const TFunction& callback) + Id FindIdParent(TIdScopeRef access, Id childId, const TFunction& callback) { while (!IsNone(childId)) { @@ -1389,7 +1391,7 @@ namespace p } return NoId; } - void FindIdParents(TAccessRef access, TView childrenIds, + void FindIdParents(TIdScopeRef access, TView childrenIds, TArray& outParentIds, const TFunction& callback) { outParentIds.Clear(false); @@ -1419,7 +1421,7 @@ namespace p } - bool FixParentIdLinks(TAccessRef, CParent> access, TView parents) + bool FixParentIdLinks(TIdScopeRef, CParent> access, TView parents) { bool fixed = false; for (Id parentId : parents) @@ -1447,7 +1449,7 @@ namespace p return fixed; } - bool ValidateParentIdLinks(TAccessRef access, TView parents) + bool ValidateParentIdLinks(TIdScopeRef access, TView parents) { for (Id parentId : parents) { @@ -1466,7 +1468,7 @@ namespace p return true; } - void GetRootIds(TAccessRef access, TArray& outRoots) + void GetRootIds(TIdScopeRef access, TArray& outRoots) { outRoots = FindAllIdsWith(access); ExcludeIdsWith(access, outRoots); diff --git a/Tests/Containers/Arrays.spec.cpp b/Tests/Containers/Arrays.spec.cpp index d48954f6..b69e0f8f 100644 --- a/Tests/Containers/Arrays.spec.cpp +++ b/Tests/Containers/Arrays.spec.cpp @@ -319,6 +319,7 @@ go_bandit([]() { AssertThat(data[0], Equals(0)); }); }); + describe("Append", []() { it("Can append defaulted", [&]() { TInlineArray data; @@ -384,6 +385,7 @@ go_bandit([]() { AssertThat(data.Data(), Equals(data.GetInlineBuffer())); }); }); + describe("Assign", []() { it("Can assign defaulted", [&]() { TInlineArray data; @@ -449,6 +451,7 @@ go_bandit([]() { AssertThat(data.Data(), Equals(data.GetInlineBuffer())); }); }); + describe("Insert", []() { it("Can insert at empty", [&]() { TInlineArray data; @@ -585,6 +588,7 @@ go_bandit([]() { AssertThat(data[11], Equals(3)); }); }); + describe("Remove", []() { it("Can remove at index", []() { TInlineArray data{1, 2, 3, 4}; @@ -659,54 +663,54 @@ go_bandit([]() { AssertThat(data.RemoveAtSwap(0, 2), Equals(true)); // Remove first AssertThat(data, Equals(TInlineArray{6})); }); - }); - it("Can RemoveLast", [&]() { - TArray data{1, 4, 6}; - data.RemoveLast(); - AssertThat(data.Size(), Equals(2)); - AssertThat(data[0], Equals(1)); - AssertThat(data[1], Equals(4)); - AssertThat(data.Capacity(), Equals(2)); - }); + it("Can RemoveLast", [&]() { + TArray data{1, 4, 6}; + data.RemoveLast(); + AssertThat(data.Size(), Equals(2)); + AssertThat(data[0], Equals(1)); + AssertThat(data[1], Equals(4)); + AssertThat(data.Capacity(), Equals(2)); + }); - it("Can RemoveLast N", [&]() { - TArray dataA{1, 4, 6}; - dataA.RemoveLast(2); - AssertThat(dataA.Size(), Equals(1)); - AssertThat(dataA[0], Equals(1)); - AssertThat(dataA.Capacity(), Equals(1)); - - TArray dataB{1, 4, 6}; - dataB.RemoveLast(3); - AssertThat(dataB.Size(), Equals(0)); - AssertThat(dataB.Capacity(), Equals(0)); - }); + it("Can RemoveLast N", [&]() { + TArray dataA{1, 4, 6}; + dataA.RemoveLast(2); + AssertThat(dataA.Size(), Equals(1)); + AssertThat(dataA[0], Equals(1)); + AssertThat(dataA.Capacity(), Equals(1)); - it("Can RemoveIf", [&]() { - TArray data{1, 4, 5, 6}; + TArray dataB{1, 4, 6}; + dataB.RemoveLast(3); + AssertThat(dataB.Size(), Equals(0)); + AssertThat(dataB.Capacity(), Equals(0)); + }); - AssertThat(data.Size(), Equals(4)); + it("Can RemoveIf", [&]() { + TArray data{1, 4, 5, 6}; - data.RemoveIf([](i32 v) { - return v == 1 || v == 6; + AssertThat(data.Size(), Equals(4)); + + data.RemoveIf([](i32 v) { + return v == 1 || v == 6; + }); + AssertThat(data.Size(), Equals(2)); + AssertThat(data[0], Equals(4)); + AssertThat(data[1], Equals(5)); }); - AssertThat(data.Size(), Equals(2)); - AssertThat(data[0], Equals(4)); - AssertThat(data[1], Equals(5)); - }); - it("Can RemoveIfSwap", [&]() { - TArray data{1, 4, 5, 6}; + it("Can RemoveIfSwap", [&]() { + TArray data{1, 4, 5, 6}; - AssertThat(data.Size(), Equals(4)); + AssertThat(data.Size(), Equals(4)); - data.RemoveIfSwap([](i32 v) { - return v == 1 || v == 6; + data.RemoveIfSwap([](i32 v) { + return v == 1 || v == 6; + }); + AssertThat(data.Size(), Equals(2)); + AssertThat(data[0], Equals(5)); + AssertThat(data[1], Equals(4)); }); - AssertThat(data.Size(), Equals(2)); - AssertThat(data[0], Equals(5)); - AssertThat(data[1], Equals(4)); }); it("Can Sort", [&]() { @@ -744,5 +748,34 @@ go_bandit([]() { AssertThat(data.AddUniqueSorted(36), Equals(6)); AssertThat(data.Size(), Equals(7)); }); + + describe("Iterate", []() { + it("Can iterate empty", [&]() { + TInlineArray data1{}; + i32 counter = 0; + for (i32 v : data1) + { + ++counter; + } + AssertThat(counter, Equals(0)); + TArray data2{}; + counter = 0; + for (i32 v : data2) + { + ++counter; + } + AssertThat(counter, Equals(0)); + }); + + it("Can iterate empty", [&]() { + TInlineArray data{}; + i32 counter = 0; + for (i32 v : data) + { + ++counter; + } + AssertThat(counter, Equals(0)); + }); + }); }); }); diff --git a/Tests/ECS/Access.spec.cpp b/Tests/ECS/Access.spec.cpp deleted file mode 100644 index a4ef8efe..00000000 --- a/Tests/ECS/Access.spec.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015-2026 Piperift. All Rights Reserved. - -#include -#include - - -using namespace snowhouse; -using namespace bandit; -using namespace p; - - -struct TypeA -{}; -struct TypeB -{}; - - -go_bandit([]() { - describe("ECS.Access", []() { - describe("Templated", []() { - it("Can cache pools", [&]() { - EntityContext ctx; - TAccess, TypeB> access{ctx}; - - AssertThat(access.GetPool(), Equals(ctx.GetPool())); - AssertThat(access.GetPool(), Equals(ctx.GetPool())); - AssertThat(access.GetPool(), Equals(ctx.GetPool())); - }); - - it("Can check if contained", [&]() { - EntityContext ctx; - TPool& pool = ctx.AssurePool(); - TAccess> access{ctx}; - TAccess accessConst{ctx}; - Id id = NoId; - AssertThat(access.Has(id), Is().False()); - AssertThat(accessConst.Has(id), Is().False()); - - id = AddId(ctx); - AssertThat(access.Has(id), Is().False()); - AssertThat(accessConst.Has(id), Is().False()); - - ctx.Add(id); - AssertThat(access.Has(id), Is().True()); - AssertThat(accessConst.Has(id), Is().True()); - - TAccess access2{ctx}; - ctx.Add(id); - AssertThat(access2.Has(id), Is().True()); - }); - - it("Can initialize superset", [&]() { - EntityContext ctx; - TPool& typePool = ctx.AssurePool(); - - TAccess, TWrite> access1{ctx}; - TAccess> superset1{access1}; - AssertThat(superset1.GetPool(), Equals(&typePool)); - - TAccess, TWrite> access2{ctx}; - TAccess superset2{access2}; - AssertThat(superset2.GetPool(), Equals(&typePool)); - - TAccess, TWrite> access3{ctx}; - TAccess superset3{access3}; - AssertThat(superset1.GetPool(), Equals(&typePool)); - }); - }); - }); -}); diff --git a/Tests/ECS/Components.spec.cpp b/Tests/ECS/Components.spec.cpp index 24e57cde..c511ecc7 100644 --- a/Tests/ECS/Components.spec.cpp +++ b/Tests/ECS/Components.spec.cpp @@ -63,7 +63,7 @@ u32 TestComponent::destructed = 0; go_bandit([]() { describe("ECS.Components", []() { it("Can add one component", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); AssertThat(ctx.Has(id), Is().False()); AssertThat(ctx.TryGet(id), Equals(nullptr)); @@ -79,7 +79,7 @@ go_bandit([]() { }); it("Can remove one component", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.Add(id); @@ -95,7 +95,7 @@ go_bandit([]() { }); it("Can add many components", [&]() { - EntityContext ctx; + IdContext ctx; TArray ids{3}; AddId(ctx, ids); ctx.AddN(ids, NonEmptyComponent{2}); @@ -109,7 +109,7 @@ go_bandit([]() { }); it("Can remove many components", [&]() { - EntityContext ctx; + IdContext ctx; TArray ids{3}; AddId(ctx, ids); ctx.AddN(ids, NonEmptyComponent{2}); @@ -135,7 +135,7 @@ go_bandit([]() { }); it("Components are removed after node is deleted", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.Add(id); @@ -149,7 +149,7 @@ go_bandit([]() { }); it("Components are removed after node is deleted (deferred)", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.Add(id); @@ -169,7 +169,7 @@ go_bandit([]() { }); it("Components keep state when added", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.AddN(id, NonEmptyComponent{2}); AssertThat(ctx.TryGet(id), !Equals(nullptr)); @@ -177,14 +177,14 @@ go_bandit([]() { }); it("Can copy registry", []() { - EntityContext ctxa; + IdContext ctxa; Id id = AddId(ctxa); ctxa.Add(id); Id id2 = AddId(ctxa); ctxa.AddN(id2, NonEmptyComponent{2}); - EntityContext ctxb{ctxa}; + IdContext ctxb{ctxa}; AssertThat(ctxb.Has(id), Is().True()); AssertThat(ctxb.Has(id), Is().True()); AssertThat(ctxb.TryGet(id), !Equals(nullptr)); @@ -195,7 +195,7 @@ go_bandit([]() { }); it("Can check components", [&]() { - EntityContext ctx; + IdContext ctx; Id id = NoId; AssertThat(ctx.Has(id), Is().False()); AssertThat(ctx.Has(id), Is().False()); @@ -213,7 +213,7 @@ go_bandit([]() { NonEmptyComponent::destructed = 0; TestComponent::destructed = 0; - EntityContext ctx; + IdContext ctx; TArray ids{3}; AddId(ctx, ids); ctx.AddN(ids, NonEmptyComponent{2}); @@ -234,7 +234,7 @@ go_bandit([]() { }); it("Components are removed with the entity", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.Add(id); RmId(ctx, id, p::RmIdFlags::Instant); @@ -247,7 +247,7 @@ go_bandit([]() { }); it("Components are removed with the entity (deferred)", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.Add(id); RmId(ctx, id); @@ -266,7 +266,7 @@ go_bandit([]() { }); it("Can access components on recicled entities", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.Add(id); RmId(ctx, id); @@ -279,7 +279,7 @@ go_bandit([]() { }); it("Can access CRemoved", [&]() { - EntityContext ctx; + IdContext ctx; Id id = AddId(ctx); ctx.Add(id); RmId(ctx, id); diff --git a/Tests/ECS/ECS.spec.cpp b/Tests/ECS/ECS.spec.cpp index 9eec9d05..5dbb4e91 100644 --- a/Tests/ECS/ECS.spec.cpp +++ b/Tests/ECS/ECS.spec.cpp @@ -19,88 +19,49 @@ struct ATypeB go_bandit([]() { describe("ECS", []() { - it("Can copy tree", [&]() { - static EntityContext* ctxPtr = nullptr; - static bool calledAdd; + it("Can copy context", [&]() { + static IdContext* ctxPtr = nullptr; - EntityContext origin; + IdContext origin; Id id = AddId(origin); - calledAdd = false; - ctxPtr = &origin; - origin.OnAdd().Bind([&origin](auto ids) { - for (Id id : ids) - { - AssertThat(origin.Has(id), Equals(true)); - } - AssertThat(ctxPtr, Equals(&origin)); - calledAdd = true; - }); + ctxPtr = &origin; origin.Add(id); - AssertThat(calledAdd, Equals(true)); - EntityContext target{origin}; + IdContext target{origin}; AssertThat(origin.IsValid(id), Equals(true)); AssertThat(origin.Has(id), Equals(true)); AssertThat(target.IsValid(id), Equals(true)); AssertThat(target.Has(id), Equals(true)); - calledAdd = false; - ctxPtr = ⌖ - target.OnAdd().Bind([&target](auto ids) { - for (Id id : ids) - { - AssertThat(target.Has(id), Equals(true)); - } - AssertThat(ctxPtr, Equals(&target)); - calledAdd = true; - }); + ctxPtr = ⌖ target.Add(id); - AssertThat(calledAdd, Equals(true)); + AssertThat(target.Has(id), Equals(true)); }); - it("Can move tree", [&]() { - static EntityContext* ctxPtr = nullptr; - static bool calledAdd; + it("Can move context", [&]() { + static IdContext* ctxPtr = nullptr; - EntityContext origin; + IdContext origin; Id id = AddId(origin); - calledAdd = false; - ctxPtr = &origin; - origin.OnAdd().Bind([&origin](auto ids) { - for (Id id : ids) - { - AssertThat(origin.Has(id), Equals(true)); - } - AssertThat(ctxPtr, Equals(&origin)); - calledAdd = true; - }); + ctxPtr = &origin; origin.Add(id); - AssertThat(calledAdd, Equals(true)); + AssertThat(origin.Has(id), Equals(true)); - EntityContext target{Move(origin)}; + IdContext target{Move(origin)}; AssertThat(origin.IsValid(id), Equals(false)); AssertThat(target.IsValid(id), Equals(true)); AssertThat(target.Has(id), Equals(true)); - calledAdd = false; - ctxPtr = ⌖ - target.OnAdd().Bind([&target](auto ids) { - for (Id id : ids) - { - AssertThat(target.Has(id), Equals(true)); - } - AssertThat(ctxPtr, Equals(&target)); - calledAdd = true; - }); + ctxPtr = ⌖ target.Add(id); - AssertThat(calledAdd, Equals(true)); + AssertThat(target.Has(id), Equals(true)); }); it("Can assure pool", [&]() { - EntityContext origin; + IdContext origin; TPool& pool = origin.AssurePool(); AssertThat(pool.Size(), Equals(0)); }); diff --git a/Tests/ECS/Filtering.spec.cpp b/Tests/ECS/Filtering.spec.cpp index 28c9c982..d56759bb 100644 --- a/Tests/ECS/Filtering.spec.cpp +++ b/Tests/ECS/Filtering.spec.cpp @@ -34,7 +34,7 @@ struct TypeC go_bandit([]() { - EntityContext ctx; + IdContext ctx; Id id1; Id id2; Id id3; @@ -57,7 +57,7 @@ go_bandit([]() { describe("FindAllIdsWith/FindAllIdsWithAny", [&]() { it("Can get list matching all", [&]() { - TAccess access{ctx}; + TIdScope access{ctx}; TArray typeIds = FindAllIdsWith(access); AssertThat(typeIds.Contains(id1), Is().True()); AssertThat(typeIds.Contains(id2), Is().True()); @@ -70,7 +70,7 @@ go_bandit([]() { }); it("Can get list matching any", [&]() { - TAccess access{ctx}; + TIdScope access{ctx}; TArray typeIds = FindAllIdsWithAny(access); AssertThat(typeIds.Contains(id1), Is().True()); AssertThat(typeIds.Contains(id2), Is().True()); @@ -83,7 +83,7 @@ go_bandit([]() { }); it("Doesn't list removed ids", [&]() { - TAccess access{ctx}; + TIdScope access{ctx}; RmId(ctx, id2, RmIdFlags::Instant); // Remove first in the pool RmId(ctx, id3, RmIdFlags::Instant); // Remove last in the pool RmId(ctx, id4, RmIdFlags::Instant); // Remove last in the pool @@ -94,7 +94,7 @@ go_bandit([]() { }); it("Doesn't list (deferred) removed ids", [&]() { - TAccess access{ctx}; + TIdScope access{ctx}; RmId(ctx, id2); // Remove first in the pool RmId(ctx, id3); // Remove last in the pool RmId(ctx, id4); // Remove last in the pool @@ -109,7 +109,7 @@ go_bandit([]() { describe("ExcludeIdsWith", [&]() { it("Removes ids containing component", [&]() { - TAccess access{ctx}; + TIdScope access{ctx}; TArray typeIds = FindAllIdsWithAny(access); ExcludeIdsWith(access, typeIds); @@ -119,7 +119,7 @@ go_bandit([]() { }); it("Removes ids not containing component", [&]() { - TAccess access{ctx}; + TIdScope access{ctx}; TArray typeIds = FindAllIdsWithAny(access); ExcludeIdsWithout(access, typeIds); @@ -129,7 +129,7 @@ go_bandit([]() { }); it("Removes ids containing multiple component", [&]() { - TAccess access{ctx}; + TIdScope access{ctx}; TArray typeIds = FindAllIdsWithAny(access); ExcludeIdsWith(access, typeIds); @@ -143,7 +143,7 @@ go_bandit([]() { it("Finds ids containing a component from a list", [&]() { TArray source{id1, id2, id3}; - TAccess access{ctx}; + TIdScope access{ctx}; TArray typeIds = FindIdsWith(access, source); AssertThat(typeIds.Contains(id1), Is().True()); AssertThat(typeIds.Contains(id2), Is().True()); @@ -153,7 +153,7 @@ go_bandit([]() { it("Finds ids not containing a component from a list", [&]() { TArray source{id1, id2, id3}; - TAccess access{ctx}; + TIdScope access{ctx}; TArray ids = FindIdsWithout(access, source); AssertThat(ids.Contains(id1), Is().False()); AssertThat(ids.Contains(id2), Is().False()); @@ -165,7 +165,7 @@ go_bandit([]() { it("Finds and removes ids containing a component from a list", [&]() { TArray source{id1, id2, id3}; - TAccess access{ctx}; + TIdScope access{ctx}; TArray ids = ExtractIdsWith(access, source); AssertThat(ids.Contains(id1), Is().True()); AssertThat(ids.Contains(id2), Is().True()); @@ -178,7 +178,7 @@ go_bandit([]() { it("Finds and removes ids not containing a component from a list", [&]() { TArray source{id1, id2, id3}; - TAccess access{ctx}; + TIdScope access{ctx}; TArray ids = ExtractIdsWithout(access, source); AssertThat(ids.Contains(id1), Is().False()); AssertThat(ids.Contains(id2), Is().False()); diff --git a/Tests/ECS/IdScopes.spec.cpp b/Tests/ECS/IdScopes.spec.cpp new file mode 100644 index 00000000..0fa8da0c --- /dev/null +++ b/Tests/ECS/IdScopes.spec.cpp @@ -0,0 +1,135 @@ +// Copyright 2015-2026 Piperift. All Rights Reserved. + +#include +#include + + +using namespace snowhouse; +using namespace bandit; +using namespace p; + + +struct TypeA +{}; +struct TypeB +{ + bool data; // Not empty type +}; +struct TypeC +{ + P_STRUCT(TypeC, TF_ECS_ModifyOnEdit) + + bool data; // Not empty type +}; + + +go_bandit([]() { + describe("ECS.IdScopes", []() { + describe("Templated", []() { + it("Can cache pools", [&]() { + IdContext ctx; + TIdScope> scope{ctx}; + + AssertThat(scope.GetPool(), Equals(ctx.GetPool())); + AssertThat(scope.GetPool(), Equals(ctx.GetPool())); + AssertThat(scope.GetPool(), Equals(ctx.GetPool())); + }); + + it("Can check if contained", [&]() { + IdContext ctx; + TPool& pool = ctx.AssurePool(); + TIdScope> scope{ctx}; + TIdScope scopeConst{ctx}; + Id id = NoId; + AssertThat(scope.Has(id), Is().False()); + AssertThat(scopeConst.Has(id), Is().False()); + + id = AddId(ctx); + AssertThat(scope.Has(id), Is().False()); + AssertThat(scopeConst.Has(id), Is().False()); + + ctx.Add(id); + AssertThat(scope.Has(id), Is().True()); + AssertThat(scopeConst.Has(id), Is().True()); + + TIdScope scope2{ctx}; + ctx.Add(id); + AssertThat(scope2.Has(id), Is().True()); + }); + + it("Can initialize superset", [&]() { + IdContext ctx; + TPool& typePool = ctx.AssurePool(); + + TIdScope> scope1{ctx}; + TIdScope> superset1{scope1}; + AssertThat(superset1.GetPool(), Equals(&typePool)); + + TIdScope> scope2{ctx}; + TIdScope superset2{scope2}; + AssertThat(superset2.GetPool(), Equals(&typePool)); + + TIdScope> scope3{ctx}; + TIdScope superset3{scope3}; + AssertThat(superset1.GetPool(), Equals(&typePool)); + }); + + it("Can mark modify", [&]() { + IdContext ctx; + Id id = AddId(ctx); + TIdScope>> scope1{ctx}; + AssertThat(scope1.Has>(id), Is().False()); + scope1.Modify(id); + AssertThat(scope1.Has>(id), Is().True()); + AssertThat(scope1.IsModified(id), Is().True()); + + scope1.Remove>(id); + AssertThat(scope1.Has>(id), Is().False()); + AssertThat(scope1.IsModified(id), Is().False()); + + scope1.Modify(id); + AssertThat(scope1.Has>(id), Is().True()); + AssertThat(scope1.IsModified(id), Is().True()); + }); + + it("Can mark modify automatically", [&]() { + IdContext ctx; + Id id = AddId(ctx); + using MyScope = TIdScope, CMdfd>; + MyScope scope{ctx}; + AssertThat(MyScope::WDependencies::Contains>(), Is().True()); + AssertThat(MyScope::WDependencies::Contains>(), Is().False()); + AssertThat(MyScope::RWDependencies::Contains>(), Is().True()); + AssertThat(MyScope::RWDependencies::Contains>(), Is().True()); + + scope.Add(id); // Type B should be auto modified + AssertThat(scope.IsModified(id), Is().True()); + scope.Add(id); // Type B should not be auto modified + AssertThat(scope.IsModified(id), Is().False()); + + scope.ClearPool>(); + AssertThat(scope.IsModified(id), Is().False()); + + scope.Has(id); // Has should never mark modify + AssertThat(scope.IsModified(id), Is().False()); + + scope.Get(id); + AssertThat(scope.IsModified(id), Is().False()); + scope.Get(id); + AssertThat(scope.IsModified(id), Is().True()); + scope.Add(id); // Type B should not be auto modified + AssertThat(scope.IsModified(id), Is().False()); + + scope.ClearPool>(); + + scope.Remove(id); + AssertThat(scope.Has(id), Is().False()); + AssertThat(scope.IsModified(id), Is().True()); + + scope.Remove(id); // Type B should not be auto modified + AssertThat(scope.Has(id), Is().False()); + AssertThat(scope.IsModified(id), Is().False()); + }); + }); + }); +}); diff --git a/Tests/ECS/Statics.spec.cpp b/Tests/ECS/Statics.spec.cpp index 39d1f35e..8d8a3bb4 100644 --- a/Tests/ECS/Statics.spec.cpp +++ b/Tests/ECS/Statics.spec.cpp @@ -27,7 +27,7 @@ struct StaticTypeThree go_bandit([]() { describe("ECS.Statics", []() { it("Can set an static", [&]() { - EntityContext ast; + IdContext ast; AssertThat(ast.HasStatic(), Equals(false)); auto& var = ast.SetStatic({4}); AssertThat(var.i, Equals(4)); @@ -35,7 +35,7 @@ go_bandit([]() { AssertThat(ast.HasStatic(), Equals(false)); }); it("Can set two statics", [&]() { - EntityContext ast; + IdContext ast; AssertThat(ast.HasStatic(), Equals(false)); AssertThat(ast.HasStatic(), Equals(false)); auto& var1 = ast.SetStatic({4}); @@ -46,7 +46,7 @@ go_bandit([]() { AssertThat(ast.HasStatic(), Equals(true)); }); it("Can replace an static", [&]() { - EntityContext ast; + IdContext ast; AssertThat(ast.HasStatic(), Equals(false)); ast.SetStatic({4}); ast.SetStatic({2}); @@ -54,14 +54,14 @@ go_bandit([]() { AssertThat(ast.HasStatic(), Equals(true)); }); it("Can get or set an static", [&]() { - EntityContext ast; + IdContext ast; // Can set AssertThat(ast.GetOrSetStatic({4}).i, Equals(4)); // Can get AssertThat(ast.GetOrSetStatic({10}).i, Equals(4)); }); it("Can remove an static", [&]() { - EntityContext ast; + IdContext ast; ast.SetStatic(); AssertThat(ast.HasStatic(), Equals(true)); AssertThat(ast.RemoveStatic(), Is().True()); @@ -71,7 +71,7 @@ go_bandit([]() { }); it("Can get statics", [&]() { - EntityContext ast; + IdContext ast; ast.SetStatic({4}); ast.SetStatic({2}); AssertThat(ast.GetStatic().i, Equals(4));