-
Notifications
You must be signed in to change notification settings - Fork 352
Expand file tree
/
Copy pathFlowSubsystem.h
More file actions
456 lines (377 loc) · 22.3 KB
/
FlowSubsystem.h
File metadata and controls
456 lines (377 loc) · 22.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors
#pragma once
#include "GameFramework/Actor.h"
#include "GameplayTagContainer.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "FlowComponent.h"
#include "FlowSubsystem.generated.h"
class IFlowDataPinValueSupplierInterface;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSimpleFlowEvent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSimpleFlowComponentEvent, UFlowComponent*, Component);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FTaggedFlowComponentEvent, UFlowComponent*, Component, const FGameplayTagContainer&, Tags);
DECLARE_DELEGATE_OneParam(FNativeFlowAssetEvent, class UFlowAsset*);
/**
* Flow Subsystem
* - manages lifetime of Flow Graphs
* - connects Flow Graphs with actors containing the Flow Component
* - convenient base for project-specific systems
*/
UCLASS()
class FLOW_API UFlowSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
UFlowSubsystem();
friend class UFlowAsset;
friend class UFlowComponent;
friend class UFlowNode_SubGraph;
protected:
/* All asset templates with active instances */
UPROPERTY()
TArray<TObjectPtr<UFlowAsset>> InstancedTemplates;
/* Assets instanced by object from another system, i.e. World Settings or Player Controller */
UPROPERTY()
TMap<TObjectPtr<UFlowAsset>, TWeakObjectPtr<UObject>> RootInstances;
/* Assets instanced by Sub Graph nodes */
UPROPERTY()
TMap<TObjectPtr<UFlowNode_SubGraph>, TObjectPtr<UFlowAsset>> InstancedSubFlows;
#if !UE_BUILD_SHIPPING
public:
/* Called after creating the first instance of given Flow Asset */
static FNativeFlowAssetEvent OnInstancedTemplateAdded;
/* Called just before removing the last instance of given Flow Asset */
static FNativeFlowAssetEvent OnInstancedTemplateRemoved;
#endif
protected:
UPROPERTY()
TObjectPtr<UFlowSaveGame> LoadedSaveGame;
public:
virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem")
virtual void AbortActiveFlows();
/* Start the root Flow, graph that will eventually instantiate next Flow Graphs through the SubGraph node */
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem", meta = (DefaultToSelf = "Owner"))
virtual void StartRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const TScriptInterface<IFlowDataPinValueSupplierInterface> DataPinValueSupplier, const bool bAllowMultipleInstances = true);
virtual UFlowAsset* CreateRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const bool bAllowMultipleInstances = true, const FString& NewInstanceName = FString());
/* Finish Policy value is read by Flow Node
* Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted
* Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed */
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem", meta = (DefaultToSelf = "Owner"))
virtual void FinishRootFlow(UObject* Owner, UFlowAsset* TemplateAsset, const EFlowFinishPolicy FinishPolicy);
/* Finish Policy value is read by Flow Node
* Nodes have opportunity to terminate themselves differently if Flow Graph has been aborted
* Example: Spawn node might despawn all actors if Flow Graph is aborted, not completed */
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem", meta = (DefaultToSelf = "Owner"))
virtual void FinishAllRootFlows(UObject* Owner, const EFlowFinishPolicy FinishPolicy);
protected:
UFlowAsset* CreateSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedInstanceName = FString(), const bool bPreloading = false);
void RemoveSubFlow(UFlowNode_SubGraph* SubGraphNode, const EFlowFinishPolicy FinishPolicy);
public:
UFlowAsset* CreateFlowInstance(const TWeakObjectPtr<UObject> Owner, UFlowAsset* LoadedFlowAsset, FString NewInstanceName = FString());
protected:
virtual void AddInstancedTemplate(UFlowAsset* Template);
virtual void RemoveInstancedTemplate(UFlowAsset* Template);
public:
/* Try to flush (and clear) all Deferred Trigger scopes.
* (can fail to flush all if a FFlowExecutionGate causes a new halt) */
bool TryFlushAllDeferredTriggerScopes() const;
/* Clear (do not trigger) any remaining deferred transitions. (for shutdown cases) */
void ClearAllDeferredTriggerScopes();
public:
/* Returns all assets instanced by object from another system like World Settings */
UFUNCTION(BlueprintPure, Category = "FlowSubsystem")
TMap<UObject*, UFlowAsset*> GetRootInstances() const;
/* Returns asset instanced by specific object */
UFUNCTION(BlueprintPure, Category = "FlowSubsystem")
TSet<UFlowAsset*> GetRootInstancesByOwner(const UObject* Owner) const;
UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeprecatedFunction, DeprecationMessage="Use GetRootInstancesByOwner() instead."))
UFlowAsset* GetRootFlow(const UObject* Owner) const;
/* Returns assets instanced by Sub Graph nodes */
UFUNCTION(BlueprintPure, Category = "FlowSubsystem")
const TMap<UFlowNode_SubGraph*, UFlowAsset*>& GetInstancedSubFlows() const { return ObjectPtrDecay(InstancedSubFlows); }
virtual UWorld* GetWorld() const override;
//////////////////////////////////////////////////////////////////////////
// SaveGame support
UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem")
FSimpleFlowEvent OnSaveGame;
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem")
virtual void OnGameSaved(UFlowSaveGame* SaveGame);
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem")
virtual void OnGameLoaded(UFlowSaveGame* SaveGame);
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem")
virtual void LoadRootFlow(UObject* Owner, UFlowAsset* FlowAsset, const FString& SavedAssetInstanceName, const bool bAllowMultipleInstances);
UFUNCTION(BlueprintCallable, Category = "FlowSubsystem")
virtual void LoadSubFlow(UFlowNode_SubGraph* SubGraphNode, const FString& SavedAssetInstanceName);
UFUNCTION(BlueprintPure, Category = "FlowSubsystem")
UFlowSaveGame* GetLoadedSaveGame() const { return LoadedSaveGame; }
//////////////////////////////////////////////////////////////////////////
// Component Registry
protected:
/* All the Flow Components currently existing in the world */
TMultiMap<FGameplayTag, TWeakObjectPtr<UFlowComponent>> FlowComponentRegistry;
protected:
virtual void RegisterComponent(UFlowComponent* Component);
virtual void OnIdentityTagAdded(UFlowComponent* Component, const FGameplayTag& AddedTag);
virtual void OnIdentityTagsAdded(UFlowComponent* Component, const FGameplayTagContainer& AddedTags);
virtual void UnregisterComponent(UFlowComponent* Component);
virtual void OnIdentityTagRemoved(UFlowComponent* Component, const FGameplayTag& RemovedTag);
virtual void OnIdentityTagsRemoved(UFlowComponent* Component, const FGameplayTagContainer& RemovedTags);
public:
/* Called when actor with Flow Component appears in the world */
UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem")
FSimpleFlowComponentEvent OnComponentRegistered;
/* Called after adding Identity Tags to already registered Flow Component
* This can happen only after Begin Play occured in the component */
UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem")
FTaggedFlowComponentEvent OnComponentTagAdded;
/* Called when actor with Flow Component disappears from the world */
UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem")
FSimpleFlowComponentEvent OnComponentUnregistered;
/* Called after removing Identity Tags from the Flow Component, if component still has some Identity Tags
* This can happen only after Begin Play occured in the component */
UPROPERTY(BlueprintAssignable, Category = "FlowSubsystem")
FTaggedFlowComponentEvent OnComponentTagRemoved;
/**
* Returns all registered Flow Components identified by given tag
*
* @param Tag Tag to check if it matches Identity Tags of registered Flow Components
* @param ComponentClass Only components matching this class we'll be returned
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass"))
TSet<UFlowComponent*> GetFlowComponentsByTag(const FGameplayTag Tag, const TSubclassOf<UFlowComponent> ComponentClass, const bool bExactMatch = true) const;
/**
* Returns all registered Flow Components identified by Any or All provided tags
*
* @param Tags Container to check if it matches Identity Tags of registered Flow Components
* @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags
* @param ComponentClass Only components matching this class we'll be returned
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ComponentClass"))
TSet<UFlowComponent*> GetFlowComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf<UFlowComponent> ComponentClass, const bool bExactMatch = true) const;
/**
* Returns all registered actors with Flow Component identified by given tag
*
* @param Tag Tag to check if it matches Identity Tags of registered Flow Components
* @param ActorClass Only actors matching this class we'll be returned
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass"))
TSet<AActor*> GetFlowActorsByTag(const FGameplayTag Tag, const TSubclassOf<AActor> ActorClass, const bool bExactMatch = true) const;
/**
* Returns all registered actors with Flow Component identified by Any or All provided tags
*
* @param Tags Container to check if it matches Identity Tags of registered Flow Components
* @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags
* @param ActorClass Only actors matching this class we'll be returned
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass"))
TSet<AActor*> GetFlowActorsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf<AActor> ActorClass, const bool bExactMatch = true) const;
/**
* Returns all registered actors as pairs: Actor as key, its Flow Component as value
*
* @param Tag Tag to check if it matches Identity Tags of registered Flow Components
* @param ActorClass Only actors matching this class we'll be returned
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass"))
TMap<AActor*, UFlowComponent*> GetFlowActorsAndComponentsByTag(const FGameplayTag Tag, const TSubclassOf<AActor> ActorClass, const bool bExactMatch = true) const;
/**
* Returns all registered actors as pairs: Actor as key, its Flow Component as value
*
* @param Tags Container to check if it matches Identity Tags of registered Flow Components
* @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags
* @param ActorClass Only actors matching this class we'll be returned
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem", meta = (DeterminesOutputType = "ActorClass"))
TMap<AActor*, UFlowComponent*> GetFlowActorsAndComponentsByTags(const FGameplayTagContainer Tags, const EGameplayContainerMatchType MatchType, const TSubclassOf<AActor> ActorClass, const bool bExactMatch = true) const;
/**
* Returns all registered Flow Components identified by given Identity
*
* @param Identity Identity that describes Component and Actor pair
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem")
TSet<UFlowComponent*> GetFlowComponentsByIdentity(const struct FFlowIdentity& Identity) const;
/**
* Returns all registered actors with Flow Component identified by given Identity
*
* @param Identity Identity that describes Component and Actor pair
*/
UFUNCTION(BlueprintPure, Category = "FlowSubsystem")
TSet<AActor*> GetFlowActorsByIdentity(const FFlowIdentity& Identity) const;
/**
* Returns all registered Flow Components identified by given tag
*
* @tparam T Only components matching this class we'll be returned
* @param Tag Tag to check if it matches Identity Tags of registered Flow Components
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
template <class T>
TSet<TWeakObjectPtr<T>> GetComponents(const FGameplayTag& Tag, const bool bExactMatch = true) const
{
static_assert(TPointerIsConvertibleFromTo<T, const UActorComponent>::Value, "'T' template parameter to GetComponents must be derived from UActorComponent");
TArray<TWeakObjectPtr<UFlowComponent>> FoundComponents;
FindComponents(Tag, bExactMatch, FoundComponents);
TSet<TWeakObjectPtr<T>> Result;
for (const TWeakObjectPtr<UFlowComponent>& Component : FoundComponents)
{
if (Component.IsValid())
{
if (T* ComponentOfClass = Cast<T>(Component))
{
Result.Emplace(ComponentOfClass);
}
}
}
return Result;
}
/**
* Returns all registered Flow Components identified by Any or All provided tags
*
* @tparam T Only components matching this class we'll be returned
* @param Tags Container to check if it matches Identity Tags of registered Flow Components
* @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
template <class T>
TSet<TWeakObjectPtr<T>> GetComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch = true) const
{
static_assert(TPointerIsConvertibleFromTo<T, const UActorComponent>::Value, "'T' template parameter to GetComponents must be derived from UActorComponent");
TSet<TWeakObjectPtr<UFlowComponent>> FoundComponents;
FindComponents(Tags, MatchType, bExactMatch, FoundComponents);
TSet<TWeakObjectPtr<T>> Result;
for (const TWeakObjectPtr<UFlowComponent>& Component : FoundComponents)
{
if (Component.IsValid())
{
if (T* ComponentOfClass = Cast<T>(Component))
{
Result.Emplace(ComponentOfClass);
}
}
}
return Result;
}
/**
* Returns all registered Flow Components identified by given tag
*
* @tparam T Only components matching this class we'll be returned
* @param Tag Tag to check if it matches Identity Tags of registered Flow Components
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
template <class T>
TSet<TWeakObjectPtr<T>> GetActors(const FGameplayTag& Tag, const bool bExactMatch = true) const
{
static_assert(TPointerIsConvertibleFromTo<T, const AActor>::Value, "'T' template parameter to GetActors must be derived from AActor");
TArray<TWeakObjectPtr<UFlowComponent>> FoundComponents;
FindComponents(Tag, bExactMatch, FoundComponents);
TSet<TWeakObjectPtr<T>> Result;
for (const TWeakObjectPtr<UFlowComponent>& Component : FoundComponents)
{
if (Component.IsValid())
{
if (T* ActorOfClass = Cast<T>(Component->GetOwner()))
{
Result.Emplace(ActorOfClass);
}
}
}
return Result;
}
/**
* Returns all registered Flow Components identified by Any or All provided tags
*
* @tparam T Only actors matching this class we'll be returned
* @param Tags Container to check if it matches Identity Tags of registered Flow Components
* @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
template <class T>
TSet<TWeakObjectPtr<T>> GetActors(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch = true) const
{
static_assert(TPointerIsConvertibleFromTo<T, const AActor>::Value, "'T' template parameter to GetActors must be derived from AActor");
TSet<TWeakObjectPtr<UFlowComponent>> FoundComponents;
FindComponents(Tags, MatchType, bExactMatch, FoundComponents);
TSet<TWeakObjectPtr<T>> Result;
for (const TWeakObjectPtr<UFlowComponent>& Component : FoundComponents)
{
if (Component.IsValid())
{
if (T* ActorOfClass = Cast<T>(Component->GetOwner()))
{
Result.Emplace(ActorOfClass);
}
}
}
return Result;
}
/**
* Returns all registered actors with Flow Component identified by given tag
*
* @tparam ActorT Only actors matching this class we'll be returned
* @tparam ComponentT Only components matching this class we'll be returned
* @param Tag Tag to check if it matches Identity Tags of registered Flow Components
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
template <class ActorT, class ComponentT>
TMap<TWeakObjectPtr<ActorT>, TWeakObjectPtr<ComponentT>> GetActorsAndComponents(const FGameplayTag& Tag, const bool bExactMatch = true) const
{
static_assert(TPointerIsConvertibleFromTo<ActorT, const AActor>::Value, "'ActorT' template parameter to GetActorsAndComponents must be derived from AActor");
static_assert(TPointerIsConvertibleFromTo<ComponentT, const UActorComponent>::Value, "'ComponentT' template parameter to GetActorsAndComponents must be derived from UActorComponent");
TArray<TWeakObjectPtr<UFlowComponent>> FoundComponents;
FindComponents(Tag, bExactMatch, FoundComponents);
TMap<TWeakObjectPtr<ActorT>, TWeakObjectPtr<ComponentT>> Result;
for (const TWeakObjectPtr<UFlowComponent>& Component : FoundComponents)
{
if (Component.IsValid())
{
ComponentT* ComponentOfClass = Cast<ComponentT>(Component);
ActorT* ActorOfClass = Cast<ActorT>(Component->GetOwner());
if (ComponentOfClass && ActorOfClass)
{
Result.Emplace(ActorOfClass, ComponentOfClass);
}
}
}
return Result;
}
/**
* Returns all registered actors with Flow Component identified by Any or All provided tags
*
* @tparam ActorT Only actors matching this class we'll be returned
* @tparam ComponentT Only components matching this class we'll be returned
* @param Tags Container to check if it matches Identity Tags of registered Flow Components
* @param MatchType If Any, returned component needs to have only one of given tags. If All, component needs to have all given Identity Tags
* @param bExactMatch If true, the tag has to be exactly present, if false then TagContainer will include it's parent tags while matching. Be careful, using latter option may be very expensive, as the search cost is proportional to the number of registered Gameplay Tags!
*/
template <class ActorT, class ComponentT>
TMap<TWeakObjectPtr<ActorT>, TWeakObjectPtr<ComponentT>> GetActorsAndComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch = true) const
{
static_assert(TPointerIsConvertibleFromTo<ActorT, const AActor>::Value, "'ActorT' template parameter to GetActorsAndComponents must be derived from AActor");
static_assert(TPointerIsConvertibleFromTo<ComponentT, const UActorComponent>::Value, "'ComponentT' template parameter to GetActorsAndComponents must be derived from UActorComponent");
TSet<TWeakObjectPtr<UFlowComponent>> FoundComponents;
FindComponents(Tags, MatchType, bExactMatch, FoundComponents);
TMap<TWeakObjectPtr<ActorT>, TWeakObjectPtr<ComponentT>> Result;
for (const TWeakObjectPtr<UFlowComponent>& Component : FoundComponents)
{
if (Component.IsValid())
{
ComponentT* ComponentOfClass = Cast<ComponentT>(Component);
ActorT* ActorOfClass = Cast<ActorT>(Component->GetOwner());
if (ComponentOfClass && ActorOfClass)
{
Result.Emplace(ActorOfClass, ComponentOfClass);
}
}
}
return Result;
}
private:
void FindComponents(const FGameplayTag& Tag, const bool bExactMatch, TArray<TWeakObjectPtr<UFlowComponent>>& OutComponents) const;
void FindComponents(const FGameplayTagContainer& Tags, const EGameplayContainerMatchType MatchType, const bool bExactMatch, TSet<TWeakObjectPtr<UFlowComponent>>& OutComponents) const;
};