Class: USystemsWorld
class SYSTEMS_API USystemsWorld
: public UObject;
Reflection-enabled
Specifiers:
- BlueprintType
Container that holds systems, resources and registry of components that belongs to actors.
Architecture book page explains more in depth what systems world is, but in a brief: systems world is a central point user interacts with using queries to resources and actor components. Think of it as database - actor components are records and resources are unique singleton-like data (usually config/settings or things you would call managers).
Methods
-
Actors
public: FActorsIter Actors();
Acquires lazy-iterator over all registered actors.
This works similar to
USystemsWorld::Query
but it yields only actors without their components, and it yields all actors. This method exists only for a last resort use cases - user should have a valid reason to query all actors and should always try to solve problem withUSystemsWorld::Query
.The only use case i can think of is when user needs to for example count all registered actors, but there are other use cases which can definitely be solved with regular component queries.
Common use case that would be wrong to query actors would be:
for (const auto* Actor : Systems.Actors()) { auto* ShiaActor = Cast<AShiaActor>(Actor); if (IsValid(ShiaActor)) { ShiaActor->JustDoit(); } }
User should instead for example add
UShiaComponent
actor component and query actors usingUSystemsWorld::Query
to iterate only on these actors that are marked as "Shia" actor using actor component tag:for (const auto* Actor : Systems.Query<UShiaComponent>()) { auto* ShiaActor = Cast<AShiaActor>(Actor); if (IsValid(ShiaActor)) { ShiaActor->JustDoit(); } }
Another thing is that user should avoid putting any logic into the actors itself and rather create system that performs work of
AShiaActor::JustDoIt()
method. Although sometimes, mostly in case of interacting with third-party code, user is forced to call logic of actor so in this case just marking actor with component tag would be a sufficient compromise. -
ActorsCount
public: uint32 ActorsCount() const;
Reflection-enabled
Counts all registered actors.
Useful for debugging purposes to show number of registered actors, but any other use case would and most likely should be solved with regular queries.
-
AddComponent
public: bool AddComponent( UActorComponent* Component );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Add actor component to registry.
Called in
USystemsActorComponent::BeginPlay
andUSystemsSceneComponent::BeginPlay
methods so user does not have to, but in case of user dynamically removing actor component to achieve support for behavior toggling, adding components back to registry can be achieved with this method.Note
Actor components are not registered immediately to avoid undefined behavior or even game crashes when performing this while iterating over systems world queries - rather they ar queued and registered after all systems complete their run on current game tick.
Return
True if both actor and component are valid.
Example
void ASomeActor::ToggleTagComponent(USystemsWorld& Systems, UTagComponent* Tag) { this->bTagEnabled = !this->bTagEnabled; if (this->bTagEnabled) { Systems.AddComponent(this, Tag); } else { Systems.RemoveComponent(this, Tag); } }
Arguments
-
Component
UActorComponent* Component
Component to be registered.
-
Cleanup
public: void Cleanup();
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Cleanup existing systems.
Method called in next tick after: [
class: USystemsSubsystem::ReleaseSystemsWorld
]. -
Component
public: template <class T> T* Component( AActor* Actor );
Tries to get pointer to registered actor component.
Handy shortcut for
USystemsWorld::ComponentRaw
Return
Pointer to component or
nullptr
in case component does not exist in registry.Note
T
should inherit fromUActorComponent
Example
Systems.Component<UShiaComponent>(Actor)->JustDoIt();
Arguments
-
Actor
AActor* Actor
Actor owning given component.
-
-
ComponentIndex
public: TOptional<uint32> ComponentIndex( const UActorComponent* Component ) const;
Get component registry index.
Useful when working directly with
FArchetypeSignature
, but user most likely won't have any high-level use case for that.For getting component index by its class use:
USystemsWorld::ComponentTypeIndex
Arguments
-
Component
const UActorComponent* Component
Component which index of we ask for.
-
-
ComponentRaw
public: UActorComponent* ComponentRaw( AActor* Actor, TSubclassOf<UActorComponent> Type );
Reflection-enabled
Specifiers:
- BlueprintPure
- Category = Systems
Meta Specifiers:
- DisplayName = Get Component
- DeterminesOutputType = Type
Tries to get pointer to registered actor component.
Note
Because components are registered after systems run this will always return
nullptr
whe trying to get actor component just after callingUSystemsWorld::AddComponent
Also when trying to get actor component just after calling
USystemsWorld::RemoveComponent
will return given component instead onullptr
because components get unregistered after systems run.Return
Pointer to component or
nullptr
in case component does not exist in registry.Example
Systems.ComponentRaw(Actor, UShiaComponent::StaticClass())->JustDoIt();
Arguments
-
ComponentTypeIndex
public: TOptional<uint32> ComponentTypeIndex( const UClass* Type ) const;
Get component registry index.
Useful when working directly with
FArchetypeSignature
, but user most likely won't have any high-level use case for that.For getting component index by component:
USystemsWorld::ComponentIndex
Arguments
-
Type
const UClass* Type
-
-
Components
public: template <class... T> TTuple<T*...> Components( AActor* Actor );
Gets tuple of actor components.
Handy wrapper for
USystemsWorld::Component
in case of asking for more than one actor component.Note
Works similar way to
USystemsWorld::Query
but do not put actor in its first tuple element, rather gives exactly the pointers to actor components user requests. It's worth noting that in case of component not being registered, it returnsnullptr
in tuple elements corresponding to requested actor component type.
Arguments
-
Actor
AActor* Actor
-
-
ComponentsDidChanged
public: template <class... T> bool ComponentsDidChanged() const;
Tells if components changed during last game tick.
handy wrapper for
USystemsWorld::ComponentsDidChangedRaw
. -
ComponentsDidChangedRaw
public: bool ComponentsDidChangedRaw( const FArchetypeSignature& Signature ) const;
-
ComponentsSignature
public: FArchetypeSignature ComponentsSignature( const TArrayView<UActorComponent*>& View ) const;
Get archetype signature of given set of components.
Useful when working directly with
FArchetypeSignature
, but user most likely won't have any high-level use case for that.
Arguments
-
View
const TArrayView<UActorComponent*>& View
-
-
Count
public: template <class... T> uint32 Count() const;
Counts actors that contain given archetype signature.
This is ergonomic shortcut for
USystemsWorld::CountRaw
that only counts types that should be included.Note
T
classes should inherit fromUActorComponent
!Example
const auto Result = Systems.Count<UShiaComponent>();
-
CountRaw
public: uint32 CountRaw( const FArchetypeSignature& IncludeSignature, const FArchetypeSignature& ExcludeSignature = {} ) const;
Reflection-enabled
Counts actors that contain given archetype include signature and do not contains exclude signature.
This is more performant way of counting actors with given set of components (although non-ergonomic for sure):
// Instead of this: const auto A = Systems.Query<UShiaComponent>().Count(); // You can do this: auto Signature = FArchetypeSignature(); if (const auto Index = Systems.ComponentTypeIndex(UShiaComponent::StaticClass())) { Signature.EnableBit(Index.GetValue()); } const auto B = Systems.CountRaw(Signature);
See
USystemsWorld::Count
for more ergonomic use.Note
For example if requested signature is:
<A, B>
and there are actors:1: A, B, C
and2: A, C
then only actor1: A, B, C
gets counted since only this one contains entire requested signature.
Arguments
-
IncludeSignature
const FArchetypeSignature& IncludeSignature
Archetype signature with minimal set of components that counted actors should contain.
-
ExcludeSignature
const FArchetypeSignature& ExcludeSignature = {}
Archetype signature with minimal set of components that counted actors should not contain.
-
-
DynamicQuery
public: template <class T> UDynamicQuery* DynamicQuery();
Acquires lazy-iterator to dynamically queried actor components.
Handy shortcut for
USystemsWorld::SpawnQuery
.See
UDynamicQuery
-
InstallDefaultResource
public: bool InstallDefaultResource( const UClass* Type );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Register resource object.
See
USystemsWorld::InstallResourceRaw
Return
True if resource was successfully installed (registry is not sealed).
Example
Systems.InstallDefaultResource(UInventory::StaticClass());
Arguments
-
Type
const UClass* Type
Resource class to get constructed and registered.
-
InstallDefaultSystem
public: bool InstallDefaultSystem( const UClass* Type, FInstallSystemOptions Options );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Install system.
See
USystemsWorld::InstallSystemRaw
,USystem
,FInstallSystemOptions
Return
True if system was successfully installed (registry is not sealed).
Example
Systems.InstallDefaultSystem(USomeSystem::StaticClass(), FInstallSystemOptions("Something"));
Arguments
-
InstallLambdaSystem
public: bool InstallLambdaSystem( TFunction<SystemsWorld::LambdaSystemType>&& Functor, FInstallSystemOptions Options = FInstallSystemOptions() );
Install state-less (function or lambda) system.
Stateless systems are the most common ones because usually what system does it only processes the data, so creating function/lambda systems brings more ergonomics into codebase.
Return
True if system was successfully installed (registry is not sealed).
Example
UFUNCTION() void BoidsFaceDirectionSystem(USystemsWorld& Systems); void BoidsFaceDirectionSystem(USystemsWorld& Systems) { for (auto& QueryItem : Systems.Query<UVelocityComponent, UBoidComponent>()) { auto* Actor = QueryItem.Get<0>(); const auto* Velocity = QueryItem.Get<1>(); if (Velocity->Value.IsNearlyZero() == false) { Actor->SetActorRotation(Velocity->Value.Rotation()); } } }
Systems.InstallLambdaSystem(BoidsFaceDirectionSystem, FInstallSystemOptions("BoidsFaceDirection"));
Arguments
-
InstallProxyResource
public: template <class T> bool InstallProxyResource( UObject* Resource, TFunction<SystemsWorld::LambdaFactoryType> Accessor );
Register proxy resource object.
Handy shortcut for
USystemsWorld::InstallProxyResourceRaw
Return
True if resource was successfully installed (registry is not sealed).
Example
UCLASS() class EXAMPLE_API UInventoryWrapper : public UDataAsset { GENERATED_BODY() public: UPROPERTY() UInventory* GeneratedInventory = nullptr; };
auto* Wrapper = NewObject<UInventoryWrapper>(Systems, UInventoryWrapper::StaticClass()); Systems.InstallProxyResource<UInventory>(Wrapper, [](auto* Wrapper) { return Wrapper->GeneratedInventory; });
Arguments
-
InstallProxyResourceRaw
public: bool InstallProxyResourceRaw( const UClass* Type, UObject* Resource, TFunction<SystemsWorld::LambdaFactoryType> Accessor );
Register proxy resource object.
Proxy resources are typically some wrapper objects inner resource we want to access instead of the wrapper one. Basically it does the same what
USystemsWorld::InstallResourceRaw
does, except it allows user to provide unpacking of its inner content.Return
True if resource was successfully installed (registry is not sealed).
Example
UCLASS() class EXAMPLE_API UInventoryWrapper : public UDataAsset { GENERATED_BODY() public: UPROPERTY() UInventory* GeneratedInventory = nullptr; };
Systems.InstallProxyResourceRaw(UInventory::StaticClass(), NewObject<UInventoryWrapper>(Systems, UInventoryWrapper::StaticClass()), [](auto* Wrapper) { return Wrapper->GeneratedInventory; });
Arguments
-
InstallResource
public: template <class T> bool InstallResource();
Register resource object.
Handy shortcut for
USystemsWorld::InstallDefaultResource
Return
True if resource was successfully installed (registry is not sealed).
Example
Systems.InstallResource<UInventory>();
-
InstallResourceRaw
public: bool InstallResourceRaw( UObject* Resource );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Meta Specifiers:
- DisplayName = Install Resource
Register resource object.
It accepts any object that inherits from
UObject
. Also systems world takes ownership over provided resource so its best to not pass any object that has its lifetime managed by other object.Return
True if resource was successfully installed (registry is not sealed).
Example
Systems.InstallResourceRaw(NewObject<UInventory>(Systems, UInventory::StaticClass()));
Arguments
-
Resource
UObject* Resource
Resource object to get registered and managed by this systems world.
-
InstallSystem
public: template <class T> bool InstallSystem( FInstallSystemOptions Options );
Install system.
Handy shortcut for
USystemsWorld::InstallDefaultSystem
See
USystem
,FInstallSystemOptions
Note
Make sure
T
is a class that inherits fromUSystem
!Return
True if system was successfully installed (registry is not sealed).
Example
Systems.InstallSystem<USomeSystem>(FInstallSystemOptions("Something"));
Arguments
-
Options
FInstallSystemOptions Options
System install options.
-
-
InstallSystemRaw
public: bool InstallSystemRaw( USystem* System, FInstallSystemOptions Options );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Meta Specifiers:
- DisplayName = Install System
Install system.
Usually user would want to install systems using either
USystemsWorld::InstallSystem
orUSystemsWorld::InstallLambdaSystem
but in case of valid reasons user can install system by its instance.Note
In case of
FInstallSystemOptions::Label
being empty, it will generate random label from new GUID.See
USystem
,FInstallSystemOptions
Return
True if system was successfully installed (registry is not sealed).
Example
Systems.InstallSystemRaw( NewObject<USomeSystem>(Systems, USomeSystem::StaticClass()), FInstallSystemOptions("Something"));
Arguments
-
IsSealed
public: bool IsSealed() const;
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Tells if systems world is sealed.
Sealed systems world means that it has completed its setup phase and is ready to run or already running.
-
LastChangedComponents
public: const FArchetypeSignature& LastChangedComponents() const;
Reflection-enabled
Returns signature of component types that changed during last game tick.
Useful for more use cases where user needs to cache and perform more advanced change detection between game ticks.
-
LastChangedResources
public: const TSet<uint32>& LastChangedResources() const;
Returns a set of unique type IDs of all resources that changed in last game tick.
Useful for more advanced use cases where user needs to ask for all changes anyway and compare them with some cached set of previously stored changes.
-
MarkComponentChanged
public: void MarkComponentChanged( UActorComponent* Component );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Marks component as changed.
Note
This will mark component type, not component instance, as changed. The need for component instance here is purely to ensure we do not mark components we do not have access to.
Arguments
-
Component
UActorComponent* Component
-
MarkResourceChanged
public: void MarkResourceChanged( UObject* Resource );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Marks given resource as changed.
Useful if user wants to create reactive systems and/or UI that should only trigger when given resource changes. The reason why user has to manually mark resources as changed is for optimizations purposes, to mark deliberate changes in resources instead of marking them automatically, to avoid a lot of boilerplate of that automation, when most of the times systems and UI do not require to ask for changes.
Use
USystemsWorld::ResourceDidChanged
to ask if some resource has changed.
Arguments
-
Resource
UObject* Resource
-
Process
public: void Process();
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Process systems world.
It performs:
- unregistering of removed components and/or actors.
- registering of added components and/or actors.
- run systems logic.
In case of registry not being sealed at the time of calling this method, none of steps above are gonna be performed.
This method is called automatically for global systems world managed by
USystemsSubsystem
, but in case of user managing systems world on their own, user can do:auto* Systems = NewObject<USystemsWorld>(this, USystemsWorld::StaticClass()); // [Systems world setup...] Systems->Process();
-
ProxyResource
public: template <typename T> T* ProxyResource();
-
ProxyResourceRaw
public: UObject* ProxyResourceRaw( const UClass* Type );
Tries to get pointer to proxy resource by its type.
See:
Return
Pointer to proxy resource or
nullptr
in case resource does not exist in registry.Example
auto* Inventory = Cast<UInventory>(Systems.ProxyResourceRaw(UInventory::StaticClass())); Inventory->AddItem(FItem{FItemType::Sword});
Arguments
-
Type
const UClass* Type
Resource type.
-
-
Query
public: template <class... T> TQuery<T...> Query();
Acquires lazy-iterator to query actor components.
More about iterators in this architecture book page.
Queries allow to yield tuples of actor and their components, and only those that comply to given query signature, so there is no iteration over any actor that do not have given component types - actors and components are registered to buckets called archetypes, and archetypes are unique as long as their signature is unique. Signature is constructed from types provided to query, as well as from types registered to systems world that belong to the same actor. Systems architecture focuses on performing queries as fast as possible and not iterating over actors that do not need to be queried was a priority.
See
TQuery
Note
Returned query iterator has always actor put as first item of item tuple and then follow requested components. So
Systems->Query<A, B, C>()
iterator will yield given tupleTTuple<AActor*, A*, B*, C*>
Example
const auto Count = static_cast<int>(Systems.Query<UBoidComponent>().Count()); const auto Difference = Count - EXPECTED_POPULATION_NUMBER; if (Difference > 0) { for (auto& QueryItem : Systems.Query<UBoidComponent>().Take(Difference)) { auto* Actor = QueryItem.Get<0>(); Actor->Destroy(); } }
-
RegisterComponent
public: template <class T> bool RegisterComponent();
Register component type.
Templated shortcut for
USystemsWorld::RegisterComponentRaw
See
UActorComponent
Return
True if component was successfully installed (registry is not sealed and registry haven't reached its capacity).
Note
T
has to be a component that inherits fromUActorComponent
Example
Systems.RegisterComponent<USomeComponent>();
-
RegisterComponentRaw
public: bool RegisterComponentRaw( const UClass* Type );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Meta Specifiers:
- DisplayName = Register Component
Register component type.
Prior to
FArchetypeSignature
being usable for queries and other architecture parts, it has to be able to identify components and for that they has to be registered by their class.See
UActorComponent
Return
True if component was successfully installed (registry is not sealed and registry haven't reached its capacity).
Example
Systems.RegisterComponentRaw(USomeComponent::StaticClass());
Arguments
-
Type
const UClass* Type
Class of component that has to inherit from
UActorComponent
-
RemoveComponent
public: bool RemoveComponent( UActorComponent* Component );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Remove actor component from registry.
Called in
USystemsActorComponent::EndPlay
andUSystemsSceneComponent::EndPlay
methods so user does not have to, but in case of user dynamically adding actor component to achieve support for behavior toggling, removing components from registry can be achieved with this method.Note
Actor components are not unregistered immediately to avoid undefined behavior or eve game crashes when performing this while iterating over systems world queries - rather the are queued and unregistered after all systems complete their run on current game tick.
Return
True if both actor and component are valid.
Example
void ASomeActor::ToggleTagComponent(USystemsWorld& Systems, UTagComponent* Tag) { this->bTagEnabled = !this->bTagEnabled; if (this->bTagEnabled) { Systems.AddComponent(this, Tag); } else { Systems.RemoveComponent(this, Tag); } }
Arguments
-
Component
UActorComponent* Component
Component to be unregistered.
-
Resource
public: template <typename T> T* Resource();
Tries to get pointer to resource by its type.
See:
USystemsWorld::InstallResourceRaw
.USystemsWorld::InstallResource
.USystemsWorld::InstallDefaultResource
.
Return
Pointer to resource or
nullptr
in case resource does not exist in registry.Example
Systems.Resource<UInventory>()->AddItem(FItem{FItemType::Sword});
-
ResourceDidChanged
public: template <class T> bool ResourceDidChanged() const;
Tells if given resource type did changed in last game tick.
Handy wrapper for
USystemsWorld::ResourceDidChangedRaw
. -
ResourceDidChangedRaw
public: bool ResourceDidChangedRaw( const UClass* Type ) const;
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Tells if given resource type did changed in last game tick.
See
USystemsWorld::MarkResourceChanged
.
Arguments
-
Type
const UClass* Type
-
ResourceRaw
public: UObject* ResourceRaw( const UClass* Type );
Reflection-enabled
Specifiers:
- BlueprintPure
- Category = Systems
Meta Specifiers:
- DisplayName = Get Resource
- DeterminesOutputType = Type
Tries to get pointer to resource by its class.
See:
USystemsWorld::InstallResourceRaw
.USystemsWorld::InstallResource
.USystemsWorld::InstallDefaultResource
.
Return
Pointer to resource or
nullptr
in case resource does not exist in registry.Example
auto* Inventory = Cast<UInventory>(Systems.ResourceRaw(UInventory::StaticClass())); Inventory->AddItem(FItem{FItemType::Sword});
Arguments
-
Type
const UClass* Type
Resource class.
-
SealAndInitialize
public: void SealAndInitialize();
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Seal registry and initialize installed systems.
Method called by:
USystemsSubsystem::AcquireSystemsWorld
.When user does not use
USystemsSubsystem
as global systems world registry, or wants to handle systems world on their own, user should call this method after systems world setup (registering components, installation of systems and resources) and then call this method.Note
After calling this method, no further successful system or resource installation i possible, so make sure to install systems world components before sealing systems world!
Example
auto* Systems = NewObject<USystemsWorld>(this, USystemsWorld::StaticClass()); if (IsValid(Systems) == false) { Systems->InstallResource<USomeResource>(); Systems->InstallLambdaSystem(SomeSystem, FInstallSystemOptions("Something")); Systems->SealAndInitialize(); }
-
SpawnQuery
public: UDynamicQuery* SpawnQuery( const UClass* BundleType );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Meta Specifiers:
- DisplayName = Query
- DevelopmentOnly
Acquires lazy-iterator to dynamically queried actor components.
Because user cannot use templated types in blueprints, dynamic queries are a way to query systems world in blueprints. Also dynamic queries do not implement lazy-iterators so they are definitely not an ergonomic way to iterate over actor components and should be avoided in favor of
USystems::Query
.See
UDynamicQuery
Arguments
-
BundleType
const UClass* BundleType
-
TaggedQuery
public: template <class... T> TTaggedQuery<T...> TaggedQuery();
Acquires lazy-iterator to query actor components with additional tag components.
The difference between
TQuery
is that tagged queries allows to request existence of additional components on actor, ones that are not required for query to access - useful when user do not require any data of given components.See
TTaggedQuery
Example
for (auto& QueryItem : Systems.TaggedQuery<UVelocityComponent>().With<UBoidComponent>().Iter()) { auto* Actor = QueryItem.Get<0>(); const auto* Velocity = QueryItem.Get<1>(); const auto Position = Actor->GetActorLocation(); Actor->SetActorLocation(Position + Velocity->Value * DletaTime); }
Documentation built with Unreal-Doc
v1.0.8 tool by PsichiX