Apparatus Version 1.0.0
ECS-like data-driven workflow for Unreal Engine.
Subjective.h
1 /*
2  * ░▒▓ APPARATUS ▓▒░
3  *
4  * File: Subjective.h
5  * Created: Friday, 23rd October 2020 7:00:48 pm
6  * Author: Vladislav Dmitrievich Turbanov (vladislav@turbanov.ru)
7  * ───────────────────────────────────────────────────────────────────
8  * Last Modified: Tuesday, 6th April 2021 1:37:06 pm
9  * Modified By: Vladislav Dmitrievich Turbanov (vladislav@turbanov.ru)
10  * ───────────────────────────────────────────────────────────────────
11  *
12  * The Apparatus source code is for your internal usage only.
13  * Redistribution of this file is strictly prohibited.
14  *
15  * Community forums: https://talk.turbanov.ru
16  *
17  * Copyright 2020 - 2021, SP Vladislav Dmitrievich Turbanov
18  * Made in Russia, Moscow City, Chekhov City
19  */
20 
21 #pragma once
22 
23 #include "CoreMinimal.h"
24 #include "UObject/Interface.h"
25 
26 #include "BeltSlot.h"
27 #include "Detail.h"
28 #include "Fingerprint.h"
29 
30 #include "Subjective.generated.h"
31 
32 UINTERFACE(MinimalAPI, BlueprintType)
33 class USubjective : public UInterface
34 {
35  GENERATED_BODY()
36 };
37 
41 class APPARATUSRUNTIME_API ISubjective
42 {
43  GENERATED_BODY()
44 
45  friend struct FFingerprint;
46  friend struct FBeltSlot;
47  friend class UDetail;
48  friend class UBelt;
49  friend class UMechanism;
51 
52  static TArray<UDetail*> EmptyDetails;
53 
54  protected:
55 
59  void MarkBooted();
60 
67  FORCEINLINE virtual void TakeBeltSlot(class UBelt* InBelt, int32 InSlotIndex)
68  {
69  unimplemented();
70  }
71 
75  FORCEINLINE virtual TArray<UDetail*>& GetDetailsRef()
76  {
77  EmptyDetails.Reset();
78  return EmptyDetails;
79  }
80 
84  FORCEINLINE virtual const TArray<UDetail*>& GetDetailsRef() const
85  {
86  EmptyDetails.Reset();
87  return EmptyDetails;
88  }
89 
94  {
95  static FFingerprint Tmp;
96  Tmp.Reset();
97  return Tmp;
98  }
99 
100  public:
101 
105  static const int32 InvalidSlotIndex = FBeltSlot::InvalidIndex;
106 
110  virtual const FFingerprint& GetFingerprint() const
111  {
112  return FFingerprint::ZERO;
113  }
114 
118  FORCEINLINE bool Matches(const FFilter& Filter) const
119  {
120  return GetFingerprint().Matches(Filter);
121  }
122 
126  void GetDetails(const bool bIncludeDisabled,
127  TArray<UDetail*>& OutDetails) const;
128 
132  UDetail*
133  FindDetail(TSubclassOf<UDetail> DetailType,
134  const bool bIncludeDisabled = false) const;
135 
139  void
140  FindDetails(TSubclassOf<UDetail> DetailType,
141  TArray<UDetail*>& OutDetails,
142  const bool bIncludeDisabled = false) const;
143 
148  bool
149  HasDetail(TSubclassOf<UDetail> DetailType,
150  const bool bIncludeDisabled = false) const;
151 
155  FORCEINLINE virtual class UBelt* GetPreferredBelt() const
156  {
157  return nullptr;
158  }
159 
164  class UDetail*
165  EnableDetail(TSubclassOf<UDetail> DetailType);
166 
170  class UDetail*
171  AddDetail(TSubclassOf<UDetail> DetailType,
172  const bool bReuseInactive = false);
173 
179  bool DisableDetail(TSubclassOf<UDetail> DetailType, const bool bDisableMultiple = false);
180 
187  FORCEINLINE virtual struct FBeltSlot* GetSlot() const { return nullptr; }
188 
195  FORCEINLINE bool IsBooted() const
196  {
197  return GetFingerprint().IsBooted();
198  }
199 
203  FORCEINLINE virtual uint32 GetHash() const
204  {
205  return (uint32)((uint64)this % (uint64)TNumericLimits<uint32>::Max());
206  }
207 }; // class ISubjective
208 
209 FORCEINLINE uint32 GetTypeHash(const TWeakInterfacePtr<ISubjective>& Subjective)
210 {
211  return Subjective->GetHash();
212 }
213 
214 FORCEINLINE void ISubjective::MarkBooted()
215 {
217 }
218 
219 inline void ISubjective::GetDetails(const bool bIncludeDisabled,
220  TArray<UDetail*>& OutDetails) const
221 {
222  OutDetails.Reset();
223  if (bIncludeDisabled)
224  {
225  OutDetails.Append(GetDetailsRef());
226  }
227  else
228  {
229  for (auto Detail : GetDetailsRef())
230  {
231  if (Detail == nullptr)
232  continue;
233  if (!Detail->IsEnabled())
234  continue;
235 
236  OutDetails.Add(Detail);
237  }
238  }
239 }
240 
241 inline bool ISubjective::HasDetail(const TSubclassOf<UDetail> Type,
242  const bool bIncludeDisabled) const
243 {
244  check(Type);
245 
246  if (GetFingerprint().ContainsDetail(Type))
247  {
248  return true;
249  }
250 
251  if (!bIncludeDisabled)
252  {
253  return false;
254  }
255 
256  // In the UDetail case we can skip the IsA checks for a slight performance
257  // benefit.
258  if (UNLIKELY(Type == UDetail::StaticClass()))
259  {
260  for (auto Detail : GetDetailsRef())
261  {
262  if (!Detail)
263  {
264  continue;
265  }
266  return true;
267  }
268  }
269  else
270  {
271  for (auto Detail : GetDetailsRef())
272  {
273  if (!Detail)
274  {
275  continue;
276  }
277  if (Detail->IsA(Type))
278  {
279  return true;
280  }
281  }
282  }
283  return false;
284 }
285 
286 inline UDetail* ISubjective::FindDetail(TSubclassOf<UDetail> Type,
287  const bool bIncludeDisabled) const
288 {
289  check(Type);
290 
291  // In the UDetail case we can skip the IsA checks for a slight performance
292  // benefit.
293  if (UNLIKELY(Type == UDetail::StaticClass()))
294  {
295  for (UDetail* Detail : GetDetailsRef())
296  {
297  if (!Detail)
298  continue;
299  if (!bIncludeDisabled && !Detail->IsEnabled())
300  continue;
301  return Detail;
302  }
303  }
304  else
305  {
306  for (UDetail* Detail : GetDetailsRef())
307  {
308  if (!Detail)
309  continue;
310  if (!bIncludeDisabled && !Detail->IsEnabled())
311  continue;
312  if (Detail->IsA(Type))
313  {
314  return Detail;
315  }
316  }
317  }
318  return nullptr;
319 }
320 
321 inline void ISubjective::FindDetails(const TSubclassOf<UDetail> DetailType,
322  TArray<UDetail*>& DetailsOut,
323  const bool bIncludeDisabled) const
324 {
325  check(DetailType);
326  DetailsOut.Reset();
327 
328  const TArray<UDetail*>& Details = GetDetailsRef();
329 
330  // In the UDetail case we can skip the IsA checks for a slight
331  // performance benefit
332  if (UNLIKELY(DetailType == UDetail::StaticClass()))
333  {
334  if (UNLIKELY(bIncludeDisabled))
335  {
336  DetailsOut.Reserve(Details.Num());
337  for (UDetail* Detail : Details)
338  {
339  if (!Detail)
340  continue;
341  DetailsOut.Add(Detail);
342  }
343  }
344  else
345  {
346  for (UDetail* Detail : Details)
347  {
348  if (!Detail)
349  continue;
350  if (!Detail->IsEnabled())
351  continue;
352  DetailsOut.Add(Detail);
353  }
354  }
355  }
356  else
357  {
358  for (UDetail* Detail : Details)
359  {
360  if (!Detail)
361  continue;
362  if (!bIncludeDisabled && !Detail->IsEnabled())
363  continue;
364  if (Detail->IsA(DetailType))
365  {
366  DetailsOut.Add(Detail);
367  }
368  }
369  }
370 }
371 
372 inline bool ISubjective::DisableDetail(TSubclassOf<UDetail> DetailType,
373  const bool bDisableMultiple)
374 {
375  checkf(DetailType != nullptr,
376  TEXT("The detail type must be provided to be disabled on %s"),
377  *this->_getUObject()->GetName());
378  // Check if the detail is in a current fingerprint first.
379  if (!GetFingerprint().ContainsDetail(DetailType))
380  {
381  return false;
382  }
383 
384  checkSlow(FindDetail(DetailType) != nullptr);
385 
386  for (auto Detail : GetDetailsRef())
387  {
388  if (!Detail)
389  continue;
390  if (!Detail->IsEnabled())
391  continue;
392  if (Detail->IsA(DetailType))
393  {
394  // The following detail method will handle the
395  // fingerprint and the slot change,
396  // and the event calling.
397  Detail->SetEnabled(false);
398  if (!bDisableMultiple)
399  {
400  return true;
401  }
402  }
403  }
404  return true;
405 }
An interface for all sorts of subjects.
Definition: Subjective.h:42
virtual class UBelt * GetPreferredBelt() const
Get the preferred belt of the subjective (if any).
Definition: Subjective.h:155
virtual uint32 GetHash() const
Get the hash of the subjective.
Definition: Subjective.h:203
virtual const TArray< UDetail * > & GetDetailsRef() const
Direct access for the internal details array.
Definition: Subjective.h:84
virtual TArray< UDetail * > & GetDetailsRef()
Direct access for the internal details array.
Definition: Subjective.h:75
bool HasDetail(TSubclassOf< UDetail > DetailType, const bool bIncludeDisabled=false) const
Check if there is a detail of specific class in the subjective.
Definition: Subjective.h:241
void FindDetails(TSubclassOf< UDetail > DetailType, TArray< UDetail * > &OutDetails, const bool bIncludeDisabled=false) const
Find the details by their type.
Definition: Subjective.h:321
void GetDetails(const bool bIncludeDisabled, TArray< UDetail * > &OutDetails) const
Get the details of the subjective.
Definition: Subjective.h:219
virtual FFingerprint & GetFingerprint()
Get the internal fingerprint of the subjective.
Definition: Subjective.h:93
void MarkBooted()
Set the subjective as booted.
Definition: Subjective.h:214
virtual const FFingerprint & GetFingerprint() const
Get the active fingerprint of the subjective.
Definition: Subjective.h:110
UDetail * FindDetail(TSubclassOf< UDetail > DetailType, const bool bIncludeDisabled=false) const
Find the detail by a type.
Definition: Subjective.h:286
bool IsBooted() const
Check if the subject is booted.
Definition: Subjective.h:195
bool DisableDetail(TSubclassOf< UDetail > DetailType, const bool bDisableMultiple=false)
Disable a certain detail(s) by type.
Definition: Subjective.h:372
bool Matches(const FFilter &Filter) const
Check if the subjective matches a supplied filter.
Definition: Subjective.h:118
virtual struct FBeltSlot * GetSlot() const
Get the current belt slot of the subjective (if any).
Definition: Subjective.h:187
The main Apparatus function library.
Definition: ApparatusFunctionLibrary.h:45
The conveyor belt consisting of subjects.
Definition: Belt.h:60
The base subject detail (component) class.
Definition: Detail.h:35
The main Mechanism function library.
Definition: Mechanism.h:63
Definition: Subjective.h:34
The belt slot, containing the cached details.
Definition: BeltSlot.h:40
static const int32 InvalidIndex
Invalid belt index.
Definition: BeltSlot.h:48
The details filter specification.
Definition: Filter.h:44
The details fingerprint.
Definition: Fingerprint.h:117
void Reset()
Clear the fingerprint without any deallocations.
Definition: Fingerprint.h:756
static const struct FFingerprint ZERO
Definition: Fingerprint.h:768
bool SetBooted(bool bState=true)
Set the new active boot state.
Definition: Fingerprint.h:239