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
-
Actorspublic: FActorsIter Actors();
Acquires lazy-iterator over all registered actors.
This works similar to
USystemsWorld::Querybut 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
UShiaComponentactor component and query actors usingUSystemsWorld::Queryto 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. -
ActorsCountpublic: 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.
-
AddComponentpublic: bool AddComponent( UActorComponent* Component );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Add actor component to registry.
Called in
USystemsActorComponent::BeginPlayandUSystemsSceneComponent::BeginPlaymethods 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
-
ComponentUActorComponent* ComponentComponent to be registered.
-
Cleanuppublic: void Cleanup();
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Cleanup existing systems.
Method called in next tick after: [
class: USystemsSubsystem::ReleaseSystemsWorld]. -
Componentpublic: template <class T> T* Component( AActor* Actor );
Tries to get pointer to registered actor component.
Handy shortcut for
USystemsWorld::ComponentRawReturn
Pointer to component or
nullptrin case component does not exist in registry.Note
Tshould inherit fromUActorComponentExample
Systems.Component<UShiaComponent>(Actor)->JustDoIt();
Arguments
-
ActorAActor* ActorActor owning given component.
-
-
ComponentIndexpublic: 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
-
Componentconst UActorComponent* ComponentComponent which index of we ask for.
-
-
ComponentRawpublic: 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
nullptrwhe trying to get actor component just after callingUSystemsWorld::AddComponentAlso when trying to get actor component just after calling
USystemsWorld::RemoveComponentwill return given component instead onullptrbecause components get unregistered after systems run.Return
Pointer to component or
nullptrin case component does not exist in registry.Example
Systems.ComponentRaw(Actor, UShiaComponent::StaticClass())->JustDoIt();
Arguments
-
ComponentTypeIndexpublic: 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
-
Typeconst UClass* Type
-
-
Componentspublic: template <class... T> TTuple<T*...> Components( AActor* Actor );
Gets tuple of actor components.
Handy wrapper for
USystemsWorld::Componentin case of asking for more than one actor component.Note
Works similar way to
USystemsWorld::Querybut 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 returnsnullptrin tuple elements corresponding to requested actor component type.
Arguments
-
ActorAActor* Actor
-
-
ComponentsDidChangedpublic: template <class... T> bool ComponentsDidChanged() const;
Tells if components changed during last game tick.
handy wrapper for
USystemsWorld::ComponentsDidChangedRaw. -
ComponentsDidChangedRawpublic: bool ComponentsDidChangedRaw( const FArchetypeSignature& Signature ) const; -
ComponentsSignaturepublic: 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
-
Viewconst TArrayView<UActorComponent*>& View
-
-
Countpublic: template <class... T> uint32 Count() const;
Counts actors that contain given archetype signature.
This is ergonomic shortcut for
USystemsWorld::CountRawthat only counts types that should be included.Note
Tclasses should inherit fromUActorComponent!Example
const auto Result = Systems.Count<UShiaComponent>(); -
CountRawpublic: 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::Countfor more ergonomic use.Note
For example if requested signature is:
<A, B>and there are actors:1: A, B, Cand2: A, Cthen only actor1: A, B, Cgets counted since only this one contains entire requested signature.
Arguments
-
IncludeSignatureconst FArchetypeSignature& IncludeSignatureArchetype signature with minimal set of components that counted actors should contain.
-
ExcludeSignatureconst FArchetypeSignature& ExcludeSignature = {}Archetype signature with minimal set of components that counted actors should not contain.
-
-
DynamicQuerypublic: template <class T> UDynamicQuery* DynamicQuery();
Acquires lazy-iterator to dynamically queried actor components.
Handy shortcut for
USystemsWorld::SpawnQuery.See
UDynamicQuery -
InstallDefaultResourcepublic: bool InstallDefaultResource( const UClass* Type );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Register resource object.
See
USystemsWorld::InstallResourceRawReturn
True if resource was successfully installed (registry is not sealed).
Example
Systems.InstallDefaultResource(UInventory::StaticClass());
Arguments
-
Typeconst UClass* TypeResource class to get constructed and registered.
-
InstallDefaultSystempublic: bool InstallDefaultSystem( const UClass* Type, FInstallSystemOptions Options );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Install system.
See
USystemsWorld::InstallSystemRaw,USystem,FInstallSystemOptionsReturn
True if system was successfully installed (registry is not sealed).
Example
Systems.InstallDefaultSystem(USomeSystem::StaticClass(), FInstallSystemOptions("Something"));
Arguments
-
InstallLambdaSystempublic: 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
-
InstallProxyResourcepublic: template <class T> bool InstallProxyResource( UObject* Resource, TFunction<SystemsWorld::LambdaFactoryType> Accessor );
Register proxy resource object.
Handy shortcut for
USystemsWorld::InstallProxyResourceRawReturn
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
-
InstallProxyResourceRawpublic: 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::InstallResourceRawdoes, 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
-
InstallResourcepublic: template <class T> bool InstallResource();
Register resource object.
Handy shortcut for
USystemsWorld::InstallDefaultResourceReturn
True if resource was successfully installed (registry is not sealed).
Example
Systems.InstallResource<UInventory>(); -
InstallResourceRawpublic: 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
-
ResourceUObject* ResourceResource object to get registered and managed by this systems world.
-
InstallSystempublic: template <class T> bool InstallSystem( FInstallSystemOptions Options );
Install system.
Handy shortcut for
USystemsWorld::InstallDefaultSystemSee
USystem,FInstallSystemOptionsNote
Make sure
Tis a class that inherits fromUSystem!Return
True if system was successfully installed (registry is not sealed).
Example
Systems.InstallSystem<USomeSystem>(FInstallSystemOptions("Something"));
Arguments
-
OptionsFInstallSystemOptions OptionsSystem install options.
-
-
InstallSystemRawpublic: 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::InstallSystemorUSystemsWorld::InstallLambdaSystembut in case of valid reasons user can install system by its instance.Note
In case of
FInstallSystemOptions::Labelbeing empty, it will generate random label from new GUID.See
USystem,FInstallSystemOptionsReturn
True if system was successfully installed (registry is not sealed).
Example
Systems.InstallSystemRaw( NewObject<USomeSystem>(Systems, USomeSystem::StaticClass()), FInstallSystemOptions("Something"));
Arguments
-
IsSealedpublic: 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.
-
LastChangedComponentspublic: 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.
-
LastChangedResourcespublic: 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.
-
MarkComponentChangedpublic: 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
-
ComponentUActorComponent* Component
-
MarkResourceChangedpublic: 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::ResourceDidChangedto ask if some resource has changed.
Arguments
-
ResourceUObject* Resource
-
Processpublic: 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(); -
ProxyResourcepublic: template <typename T> T* ProxyResource(); -
ProxyResourceRawpublic: UObject* ProxyResourceRaw( const UClass* Type );
Tries to get pointer to proxy resource by its type.
See:
Return
Pointer to proxy resource or
nullptrin case resource does not exist in registry.Example
auto* Inventory = Cast<UInventory>(Systems.ProxyResourceRaw(UInventory::StaticClass())); Inventory->AddItem(FItem{FItemType::Sword});
Arguments
-
Typeconst UClass* TypeResource type.
-
-
Querypublic: 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
TQueryNote
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(); } } -
RegisterComponentpublic: template <class T> bool RegisterComponent();
Register component type.
Templated shortcut for
USystemsWorld::RegisterComponentRawSee
UActorComponentReturn
True if component was successfully installed (registry is not sealed and registry haven't reached its capacity).
Note
Thas to be a component that inherits fromUActorComponentExample
Systems.RegisterComponent<USomeComponent>(); -
RegisterComponentRawpublic: bool RegisterComponentRaw( const UClass* Type );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Meta Specifiers:
- DisplayName = Register Component
Register component type.
Prior to
FArchetypeSignaturebeing 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
UActorComponentReturn
True if component was successfully installed (registry is not sealed and registry haven't reached its capacity).
Example
Systems.RegisterComponentRaw(USomeComponent::StaticClass());
Arguments
-
Typeconst UClass* TypeClass of component that has to inherit from
UActorComponent
-
RemoveComponentpublic: bool RemoveComponent( UActorComponent* Component );
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Remove actor component from registry.
Called in
USystemsActorComponent::EndPlayandUSystemsSceneComponent::EndPlaymethods 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
-
ComponentUActorComponent* ComponentComponent to be unregistered.
-
Resourcepublic: 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
nullptrin case resource does not exist in registry.Example
Systems.Resource<UInventory>()->AddItem(FItem{FItemType::Sword}); -
ResourceDidChangedpublic: template <class T> bool ResourceDidChanged() const;
Tells if given resource type did changed in last game tick.
Handy wrapper for
USystemsWorld::ResourceDidChangedRaw. -
ResourceDidChangedRawpublic: 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
-
Typeconst UClass* Type
-
ResourceRawpublic: 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
nullptrin case resource does not exist in registry.Example
auto* Inventory = Cast<UInventory>(Systems.ResourceRaw(UInventory::StaticClass())); Inventory->AddItem(FItem{FItemType::Sword});
Arguments
-
Typeconst UClass* TypeResource class.
-
SealAndInitializepublic: void SealAndInitialize();
Reflection-enabled
Specifiers:
- BlueprintCallable
- Category = Systems
Seal registry and initialize installed systems.
Method called by:
USystemsSubsystem::AcquireSystemsWorld.When user does not use
USystemsSubsystemas 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(); } -
SpawnQuerypublic: 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
-
BundleTypeconst UClass* BundleType
-
TaggedQuerypublic: template <class... T> TTaggedQuery<T...> TaggedQuery();
Acquires lazy-iterator to query actor components with additional tag components.
The difference between
TQueryis 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
TTaggedQueryExample
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