14#include "CoreMinimal.h"
67 template <
typename T,
typename Composition>
69 &&
requires(std::decay_t<T>& t, Composition&& parent)
71 t.OnComponentRegistered(parent);
75 template <
typename T,
typename Composition>
78 template <
typename T,
typename Composition>
226 uint64 LastAddedComponentHash = 0;
227 mutable TMap<uint64, FAny> Components;
228 mutable TMap<uint64, TArray<uint64>> ComponentAliases;
230 bool HasExactComponent(uint64 typeHash)
const;
231 bool HasComponentAliasUnchecked(uint64 typeHash)
const;
232 bool HasComponentAlias(uint64 typeHash)
const;
233 void AddComponentAlias(uint64 mainType, uint64 validAs);
235 template <
typename Val
idAs>
236 void AddComponentAlias(uint64 mainType)
238 Components[mainType].WithAlias<ValidAs>();
239 AddComponentAlias(mainType, TTypeHash<ValidAs>);
241 if constexpr (CHasBases<ValidAs>)
245 AddComponentAlias(mainType, TTypeHash<Base>);
250 ranges::any_view<FAny*> GetExactComponent(uint64 typeHash)
const;
251 ranges::any_view<FAny*> GetAliasedComponents(uint64 typeHash)
const;
252 ranges::any_view<FAny*> GetComponentsPrivate(uint64 typeHash)
const;
272 template <
typename MainType,
typename Self>
277 ASSERT_CRASH(!self.HasExactComponent(TTypeHash<MainType>),
279 TEXT_"{0} cannot be added because another component already exists under that type.",
283 "Try wrapping your component in an empty derived type, and register it with its base type {0} as its"
284 " alias. Later on both the current and the already existing component can be accessed via"
285 " `GetComponents<{0}>()` which returns a range of all matching components.",
290 self.Components.Add(TTypeHash<MainType>,
FAny(newComponent, facilities));
291 self.LastAddedComponentHash = TTypeHash<MainType>;
293 if constexpr (CHasBases<MainType>)
298 self.AddComponentAlias(TTypeHash<MainType>, TTypeHash<Base>);
302 if constexpr (CCompatibleExplicitComponent<MainType, Self>)
303 newComponent->OnComponentRegistered(self);
317 template <CDefaultInitializable MainType,
typename Self>
318 requires CCompatibleComponent<MainType, Self>
321 Forward<Self>(self).template AddComponent<MainType, Self>(
new MainType(), facilities);
336 template <
typename... ValidAs>
339 ASSERT_CRASH(LastAddedComponentHash != 0 && Components.Contains(LastAddedComponentHash),
340 ->WithMessage(
TEXT_"Component aliases were listed, but no components were added before.")
341 ->WithDetails(
TEXT_"Make sure `AddAlias` or `WithAlias` is called after `AddComponent` / `WithComponent`.")
343 (AddComponentAlias<ValidAs>(LastAddedComponentHash), ...);
367 template <
typename MainType, CSharedFromThis Self>
371 Forward<Self>(self).template AddComponent<MainType, Self>(newComponent, facilities);
372 return StaticCastSharedRef<std::decay_t<Self>>(self.AsShared());
391 template <CDefaultInitializable MainType, CSharedFromThis Self>
392 requires CCompatibleComponent<MainType, Self>
395 Forward<Self>(self).template AddComponent<MainType, Self>(facilities);
396 return StaticCastSharedRef<std::decay_t<Self>>(self.AsShared());
420 template <
typename MainType,
typename Self>
421 requires (CCompatibleComponent<MainType, Self> && !CSharedFromThis<Self>)
424 Forward<Self>(self).template AddComponent<MainType, Self>(newComponent, facilities);
425 return Forward<Self>(self);
444 template <CDefaultInitializable MainType,
typename Self>
445 requires (CCompatibleComponent<MainType, Self> && !CSharedFromThis<Self>)
448 Forward<Self>(self).template AddComponent<MainType, Self>(facilities);
449 return Forward<Self>(self);
486 template <
typename Val
idAs, CSharedFromThis Self>
489 Forward<Self>(self).template AddAlias<ValidAs>();
490 return StaticCastSharedRef<std::decay_t<Self>>(self.AsShared());
527 template <
typename Val
idAs,
typename Self>
528 requires (!CSharedFromThis<Self>)
531 Forward<Self>(self).template AddAlias<ValidAs>();
532 return Forward<Self>(self);
565 template <CSharedFromThis Self,
typename... ValidAs>
568 Forward<Self>(self).template AddAlias<ValidAs...>();
569 return StaticCastSharedRef<std::decay_t<Self>>(self.AsShared());
602 template <
typename Self,
typename... ValidAs>
603 requires (!CSharedFromThis<Self>)
606 Forward<Self>(self).template AddAlias<ValidAs...>();
607 return Forward<Self>(self);
621 template <
typename T>
624 namespace rv = ranges::views;
625 return GetComponentsPrivate(TTypeHash<T>)
626 | rv::transform([](
FAny* component) {
return component->
TryGet<T>(); })
642 template <
typename T>
660 template <
typename T>
682 template <
typename T>
685 const T* result = TryGetComponent<T>();
686 ASSERT_CRASH(result, ->WithMessageF(
TEXT_"Component {0} was unavailable.", TTypeName<T>));
706 template <
typename T>
709 T* result = TryGetComponent<T>();
710 ASSERT_CRASH(result, ->WithMessageF(
TEXT_"Component {0} was unavailable.", TTypeName<T>));
#define ASSERT_CRASH(condition,...)
Use this instead of check macro if the checked expression shouldn't be ignored in shipping builds....
Bring modern declarative range operations like views and actions to the Unreal C++ arsenal....
Use leading TEXT_ without parenthesis for Unreal compatible text literals.
#define TEXT_
A convenience alternative to Unreal's own TEXT macro but this one doesn't require parenthesis around ...
A base class which can bring type based class-composition to a derived class.
decltype(auto) WithComponent(this Self &&self, TAnyTypeFacilities< MainType > const &facilities={})
Add a default constructed component to this composable class with a fluent API.
T & GetComponent()
Get the first component matching~ or aliased by the given type.
auto WithAlias(this Self &&self)
Add a type, the last added component is convertible to and may be used to get the last component amon...
decltype(auto) WithAlias(this Self &&self)
Add a type, the last added component is convertible to and may be used to get the last component amon...
decltype(auto) With(this Self &&self, TTypes< ValidAs... > &&)
Add a list of types the last added component is convertible to and may be used to get the last compon...
const T * TryGetComponent() const
Get the first component matching~ or aliased by the given type.
void AddAlias()
Add a list of types the last added component is convertible to and may be used to get the last compon...
decltype(auto) WithComponent(this Self &&self, MainType *newComponent, TAnyTypeFacilities< MainType > const &facilities={})
Add a component to this composable class with a fluent API.
void AddComponent(this Self &&self, TAnyTypeFacilities< MainType > const &facilities={})
Add a default constructed component to this composable class.
ranges::any_view< T * > GetComponents() const
Get all components added matching~ or aliased by the given type.
auto With(this Self &&self, TTypes< ValidAs... > &&)
Add a list of types the last added component is convertible to and may be used to get the last compon...
T const & GetComponent() const
Get the first component matching~ or aliased by the given type.
auto WithComponent(this Self &&self, MainType *newComponent, TAnyTypeFacilities< MainType > const &facilities={})
Add a component to this composable class with a fluent API.
auto WithComponent(this Self &&self, TAnyTypeFacilities< MainType > const &facilities={})
Add a default constructed component to this composable class with a fluent API.
T * TryGetComponent()
Get the first component matching~ or aliased by the given type.
void AddComponent(this Self &&self, MainType *newComponent, TAnyTypeFacilities< MainType > const &facilities={})
Add a component to this composable class.
void ForEachExplicitBase(Function &&function)
Namespace containing utilities and base classes for type composition.
decltype(auto) FirstOrDefault(Input &&range)
Get's the first element of a range or return the default value for the element type....
FORCEINLINE auto FilterValid()
A simplistic but type-safe and RAII compliant storage for anything. Enclosed data is owned by this ty...
Give the opportunity to customize object lifespan operations for FAny by either specializing this tem...
This template is used in IComponent|FAny::With(TAlias<...>) so it can have deduced this type and expl...
Inherit from this empty interface to signal that the inheriting class knows that it's a component and...
Inherit from this empty interface to signal that the inheriting class knows that it's a component and...