Agrarsense
TickManager.cpp
Go to the documentation of this file.
1// Copyright (c) 2023 FrostBit Software Lab at the Lapland University of Applied Sciences
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
6#include "TickManager.h"
7
8#include "Engine/GameViewportClient.h"
9#include "Engine.h"
10
11#include "Async/ParallelFor.h"
12
14std::vector<FTickEntry> ATickManager::FullFrameTaskFunctions;
15std::vector<FTickEntry> ATickManager::LateTickFunctions;
16std::vector<FTickEntry> ATickManager::TicksToRemove;
17
19{
20 Super::BeginPlay();
21
22 if (Instance == nullptr)
23 {
24 Instance = this;
25
26 // Subscribe to pre and post tick actor delegates
27 OnPreTickDelegate = FWorldDelegates::OnWorldPreActorTick.AddUObject(this, &ATickManager::PreTick);
28 OnPostTickDelegate = FWorldDelegates::OnWorldPostActorTick.AddUObject(this, &ATickManager::PostTick);
29 }
30 else
31 {
32 Destroy();
33 }
34}
35
36void ATickManager::EndPlay(const EEndPlayReason::Type EndPlayReason)
37{
38 Super::EndPlay(EndPlayReason);
39
40 if (Instance == this)
41 {
43 LateTickFunctions.clear();
44 TicksToRemove.clear();
45 FWorldDelegates::OnWorldPreActorTick.Remove(OnPreTickDelegate);
46 FWorldDelegates::OnWorldPostActorTick.Remove(OnPostTickDelegate);
47 Instance = nullptr;
48 }
49}
50
51FTickEntry ATickManager::AddTick(UObject* Object, std::function<void(float)> Function, ETickType Type)
52{
53 if (Instance == nullptr)
54 {
55 if (GEngine || GEngine->GameViewport)
56 {
57 UWorld* World = GEngine->GameViewport->GetWorld();
58 World->SpawnActor<ATickManager>();
59 }
60 }
61
62 FTickEntry TickEntry(Object, Function, Type);
63
64 switch (Type)
65 {
66 case ETickType::FullFrameTaskParallel:
68 break;
69 case ETickType::LateTickParallel:
71 break;
72 default:
73 UE_LOG(LogTemp, Warning, TEXT("TickManager.cpp: Unsupported ETickType in AddTick."));
74 break;
75 }
76
77 return TickEntry;
78}
79
81{
82 // Add tick entry to remove into std::vector. These get deleted at the end of the frame.
83 TicksToRemove.push_back(TickEntry);
84}
85
86void ATickManager::PreTick(UWorld* World, ELevelTick TickType, float DeltaSeconds)
87{
88 // Start FullFrameTask that runs the entire frame
89 // if the task is small, it can finish at any time
90 if (FullFrameTaskFunctions.size() != 0)
91 {
92 FullFrameTask = FFunctionGraphTask::CreateAndDispatchWhenReady([this, DeltaSeconds]()
93 {
95 }, TStatId(), nullptr, ENamedThreads::AnyBackgroundHiPriTask);
96 }
97}
98
99void ATickManager::PostTick(UWorld* World, ELevelTick TickType, float DeltaSeconds)
100{
101 // Tick all added late ticks in parallel
102 if (LateTickFunctions.size() != 0)
103 {
105 }
106
107 // Wait till all FullFrameTask ticks are completed
108 if (FullFrameTask.IsValid())
109 {
110 FTaskGraphInterface::Get().WaitUntilTaskCompletes(FullFrameTask);
111 }
112
113 FrameCleanup();
114}
115
116inline void ATickManager::TickFunctionsParallel(std::vector<FTickEntry>& functions, const float DeltaTime)
117{
118 const int32 size = functions.size();
119 ParallelFor(size, [&](int32 index)
120 {
121 FTickEntry& tickEntry = functions[index];
122 if (tickEntry.Owner != nullptr)
123 {
124 tickEntry.Tick(DeltaTime);
125 }
126 }, EParallelForFlags::Unbalanced);
127}
128
130{
131 if (TicksToRemove.size() != 0)
132 {
133 for (const FTickEntry& tickEntry : TicksToRemove)
134 {
135 ETickType Type = tickEntry.TickType;
136 switch (Type)
137 {
138 case ETickType::FullFrameTaskParallel:
140 break;
141 case ETickType::LateTickParallel:
143 break;
144 default:
145 UE_LOG(LogTemp, Warning, TEXT("TickManager.cpp: Unsupported ETickType in RemoveTick."));
146 break;
147 }
148 }
149 TicksToRemove.clear();
150 }
151
152 // Destroy this Actor if we have no ticks
153 // TODO: Should we just keep this alive?
154 if (FullFrameTaskFunctions.size() == 0 &&
155 LateTickFunctions.size() == 0)
156 {
157 if (Instance != nullptr)
158 {
159#if WITH_EDITOR
160 UE_LOG(LogTemp, Warning, TEXT("TickManager.cpp: Destroying as there are no more ticks."));
161#endif
162 Instance->Destroy();
163 Instance = nullptr;
164 }
165 }
166}
ETickType
Definition: TickManager.h:24
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
Definition: TickManager.cpp:36
FDelegateHandle OnPreTickDelegate
Definition: TickManager.h:120
static std::vector< FTickEntry > LateTickFunctions
Definition: TickManager.h:134
static std::vector< FTickEntry > TicksToRemove
Definition: TickManager.h:135
void PreTick(UWorld *World, ELevelTick TickType, float DeltaSeconds)
Definition: TickManager.cpp:86
void PostTick(UWorld *World, ELevelTick TickType, float DeltaSeconds)
Definition: TickManager.cpp:99
static void AddTickInternal(std::vector< FTickEntry > &to, const FTickEntry &newTickEntry)
Definition: TickManager.h:137
FGraphEventRef FullFrameTask
Definition: TickManager.h:130
FDelegateHandle OnPostTickDelegate
Definition: TickManager.h:123
static void RemoveTick(FTickEntry TickEntry)
Definition: TickManager.cpp:80
static ATickManager * Instance
Definition: TickManager.h:132
void FrameCleanup()
static std::vector< FTickEntry > FullFrameTaskFunctions
Definition: TickManager.h:133
virtual void BeginPlay() override
Definition: TickManager.cpp:18
void TickFunctionsParallel(std::vector< FTickEntry > &functions, const float DeltaTime)
static void RemoveTickInternal(std::vector< FTickEntry > &from, FTickEntry tickEntry)
Definition: TickManager.h:155
static FTickEntry AddTick(UObject *Object, std::function< void(float)> Function, ETickType Type)
Definition: TickManager.cpp:51
UObject * Owner
Definition: TickManager.h:49