Apparatus Version 1.0.0
ECS-like data-driven workflow for Unreal Engine.
Belt.h
1 /*
2  * ░▒▓ APPARATUS ▓▒░
3  *
4  * File: Belt.cpp
5  * Created: Friday, 23rd October 2020 7:00:48 pm
6  * Author: Vladislav Dmitrievich Turbanov (vladislav@turbanov.ru)
7  * ───────────────────────────────────────────────────────────────────
8  * Last Modified: Saturday, 3rd April 2021 5:21:16 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 "Subjective.h"
24 #include "BeltSlot.h"
25 #include "Components/ActorComponent.h"
26 #include "CoreMinimal.h"
27 #include "Fingerprint.h"
28 #include "Filter.h"
29 #include "UObject/NoExportTypes.h"
30 
31 #include "Belt.generated.h"
32 
33 DECLARE_STATS_GROUP(TEXT("Belt"), STATGROUP_Belt, STATCAT_Advanced);
34 
35 FORCEINLINE uint32 GetTypeHash(const TArray<const UClass*>& Types)
36 {
37  uint32 h = 0;
38  for (auto Type : Types)
39  {
40  h += Type->GetUniqueID();
41  }
42  return h;
43 }
44 
45 FORCEINLINE uint32 GetTypeHash(const TArray<UClass*>& Types)
46 {
47  uint32 h = 0;
48  for (auto Type : Types)
49  {
50  h += Type->GetUniqueID();
51  }
52  return h;
53 }
54 
58 UCLASS(BlueprintType)
59 class APPARATUSRUNTIME_API UBelt : public UObject
60 {
61  GENERATED_BODY()
62 
63 
66  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Belt,
67  Meta = (AllowPrivateAccess = "true"))
68  FFilter Filter;
69 
73  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Transient, Category = Belt,
74  Meta = (AllowPrivateAccess = "true"))
75  int32 Count = 0;
76 
80  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Transient, Category = Belt,
81  Meta = (AllowPrivateAccess = "true"))
82  uint32 bBuffering : 1;
83 
87  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Belt,
88  Meta = (AllowPrivateAccess = "true"))
89  uint32 bSparse : 1;
90 
91  public:
92 
96  static const int32 InvalidSlotIndex = FBeltSlot::InvalidIndex;
97 
101  FORCEINLINE bool IsBuffering() const { return bBuffering; }
102 
106  FORCEINLINE bool IsSparse() const { return bSparse; }
107 
111  FORCEINLINE const FFilter& GetFilter() const
112  {
113  return Filter;
114  }
115 
119  class iterator
120  {
124  UBelt* Owner = nullptr;
125 
129  int32 Index = -1;
130 
131  friend class UBelt;
132 
133  iterator(UBelt* o, int32 i) : Owner(o), Index(i) {}
134 
135  public:
139  FORCEINLINE iterator& operator++()
140  {
141  check(Owner != nullptr);
142  check(Index != -1);
143  Index = Owner->GetNextSlotIndex(Index);
144  return *this;
145  }
146 
150  FORCEINLINE iterator operator++(int)
151  {
152  check(Owner != nullptr);
153  check(Index != -1);
154  const auto IndexSave = Index;
155  Index = Owner->GetNextSlotIndex(Index);
156  return iterator(Owner, IndexSave);
157  }
158 
159  FORCEINLINE bool operator==(const iterator& other) const
160  {
161  check(Owner != nullptr);
162  if (Owner != other.Owner)
163  return false;
164  if (Index == other.Index)
165  return true;
166  if (Index >= Owner->Num() && other.Index == -1)
167  return true;
168  if (other.Index >= other.Owner->Num() && Index == -1)
169  return true;
170  return false;
171  }
172 
173  FORCEINLINE bool operator!=(const iterator& other) const
174  {
175  check(Owner != nullptr);
176  if (Owner != other.Owner)
177  return true;
178  if (Index == other.Index)
179  return false;
180  if (Index >= Owner->Num() && other.Index == -1)
181  return false;
182  if (other.Index >= other.Owner->Num() && Index == -1)
183  return false;
184  return true;
185  }
186 
187  FORCEINLINE FBeltSlot& operator*()
188  {
189  check(Owner != nullptr);
190  check(Index != -1);
191  return Owner->Slots[Index];
192  }
193  }; // class iterator
194 
195  private:
199  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Transient, Category = Belt,
200  Meta = (AllowPrivateAccess = "true"))
201  TArray<FBeltSlot> Slots;
202 
206  FBeltSlot EndSlot;
207 
208  friend struct FBeltSlot;
210  friend class USubjectiveUserWidget;
211  friend class UDetail;
212  friend class UMechanism;
214 
218  UBelt();
219 
223  ~UBelt();
224 
225  const static TArray<UBelt*> NoBelts;
226 
227  public:
234  bool Expand(const FFingerprint& NewFingerprint,
235  const EBootFilter BootFilter = EBootFilter::None);
236 
242  FORCEINLINE int32 Num() const { return Count; }
243 
249  FORCEINLINE int32 GetCount() const { return Count; }
250 
257  FORCEINLINE FBeltSlot& operator[](int32 Index)
258  {
259  return Slots[Index];
260  }
261 
268  FORCEINLINE const FBeltSlot& operator[](int32 Index) const
269  {
270  return Slots[Index];
271  }
272 
278  FORCEINLINE iterator begin()
279  {
280  auto& f = GetFirstSlot();
281  if (!f.IsValid())
282  return end();
283  return iterator(this, f.Index);
284  }
285 
291  FORCEINLINE iterator end() { return iterator(this, -1); }
292 
297  void FetchDetails();
298 
303  UFUNCTION(BlueprintCallable, Category = "Apparatus")
304  void BufferDetailsFromBelt(UBelt* Belt,
305  const FFilter& TargetFilter);
306 
311  UFUNCTION(BlueprintCallable, Category = "Apparatus")
312  void BufferDetailsFromBelts(const TArray<class UBelt*>& Belts,
313  const FFilter& TargetFilter);
314 
320  void Refresh(TScriptInterface<ISubjective> Subjective);
321 
327  void Refresh(TScriptInterface<ISubjective> Subjective,
328  const TArray<class UDetail*>& Details);
329 
333  bool Remove(TScriptInterface<ISubjective> Subjective);
334 
338  static class UBelt* New(UObject* Owner,
339  const FFingerprint& Fingerprint);
340 
344  static class UBelt* New(UObject* Owner,
345  const FName& Name,
346  const FFingerprint& Fingerprint);
347 
351  static class UBelt* New(UObject* Owner,
352  const FName& Name,
353  const FFingerprint& Fingerprint,
354  const EBootFilter BootFilter);
355 
359  static class UBelt* NewBuffering(UObject* Owner);
360 
364  bool Matches(const FFilter& Filter) const;
365 
370  FBeltSlot& Remove(FBeltSlot& slot);
371 
375  UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Apparatus")
376  static UDetail* GetDetailFromSlotByIndex(const FBeltSlot& Slot,
377  const int32 DetailIndex);
378 
382  UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Apparatus",
383  Meta = (DeterminesOutputType = "DetailType", KeyWords = "belt"))
384  static UDetail* GetDetailFromSlot(const FBeltSlot& Slot,
385  const TSubclassOf<UDetail> DetailType);
386 
390  UFUNCTION(BlueprintCallable, Category = "Apparatus",
391  Meta = (DeterminesOutputType = "DetailType"))
392  UDetail* GetDetailFromSlotAtIndex(const int32 SlotIndex,
393  const TSubclassOf<UDetail> DetailType) const;
394 
398  UFUNCTION(BlueprintCallable, Category = "Apparatus",
399  Meta = (DeterminesOutputType = "DetailType",
400  BlueprintInternalUseOnly))
401  UDetail*
402  GetDetailFromSlotAtIndexHinted(const int32 SlotIndex,
403  const TSubclassOf<UDetail> DetailType,
404  const int32 IndexHint);
405 
409  UFUNCTION(BlueprintCallable, Category = "Apparatus")
410  TScriptInterface<ISubjective>
411  GetSubjectFromSlotAtIndex(const int32 SlotIndex);
412 
416  UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Apparatus",
417  Meta = (KeyWords = "belt"))
418  static bool IsEndSlot(const FBeltSlot& Slot);
419 
423  UFUNCTION(BlueprintCallable, Category = "Apparatus")
425 
429  UFUNCTION(BlueprintCallable, Category = "Apparatus",
430  Meta = (KeyWords = "belt"))
431  static FBeltSlot& GetNextSlot(const FBeltSlot& Slot);
432 
436  UFUNCTION(BlueprintCallable, Category = "Apparatus")
437  int32 GetFirstSlotIndex();
438 
442  UFUNCTION(BlueprintCallable, Category = "Apparatus")
443  int32 GetNextSlotIndex(const int32 SlotIndex);
444 
448  UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Apparatus")
450 }; // class UBelt
451 
452 FORCEINLINE FBeltSlot& UBelt::GetEndSlot() { return EndSlot; }
453 
454 FORCEINLINE bool UBelt::IsEndSlot(const FBeltSlot& Slot)
455 {
456  if (Slot.Owner == nullptr)
457  return true;
458  return !Slot.IsValid();
459 }
460 
461 FORCEINLINE bool UBelt::Matches(const FFilter& InFilter) const
462 {
463  if (!bSparse)
464  {
465  return Filter.Matches(InFilter);
466  }
467  // Sparse belts may actually have holes,
468  // so the details <- filter exclusions are tested during the iteration, not here.
469  // Only the belt exclusions -> filter details is tested here.
470  return Filter.GetDetailsMask().Includes(InFilter.GetDetailsMask()) &&
472 }
473 
475  const int32 DetailIndex)
476 {
477  return Slot.GetDetail(DetailIndex);
478 }
479 
480 FORCEINLINE UDetail*
482  const TSubclassOf<UDetail> DetailType)
483 {
484  return Slot.GetDetail(DetailType);
485 }
486 
487 FORCEINLINE UDetail*
488 UBelt::GetDetailFromSlotAtIndex(const int32 SlotIndex,
489  const TSubclassOf<UDetail> DetailType) const
490 {
491  const FBeltSlot& Slot = Slots[SlotIndex];
492  return Slot.GetDetail(DetailType);
493 }
494 
495 FORCEINLINE UDetail*
497  const TSubclassOf<UDetail> DetailType,
498  const int32 IndexHint)
499 {
500  const FBeltSlot& Slot = Slots[SlotIndex];
501  UDetail* rDetail = Slot.GetDetail(IndexHint);
502  checkfSlow(rDetail->IsA(DetailType),
503  TEXT("The hinted type is not the same."));
504  return rDetail;
505 }
506 
507 FORCEINLINE TScriptInterface<ISubjective>
508 UBelt::GetSubjectFromSlotAtIndex(const int32 SlotIndex)
509 {
510  const FBeltSlot& Slot = Slots[SlotIndex];
511  return Slot.GetSubjective();
512 }
513 
514 FORCEINLINE int32
516 {
517  if (Count == 0)
518  {
519  return InvalidSlotIndex;
520  }
521  const FBeltSlot& Slot = GetFirstSlot();
522  if (Slot.IsValid())
523  {
524  return Slot.GetIndex();
525  }
526  // No valid slot was found.
527  return InvalidSlotIndex;
528 }
529 
530 FORCEINLINE int32
531 UBelt::GetNextSlotIndex(const int32 SlotIndex)
532 {
533  if (SlotIndex >= Count)
534  return InvalidSlotIndex;
535  if (SlotIndex < 0)
536  return InvalidSlotIndex;
537  FBeltSlot& Slot = Slots[SlotIndex];
538  FBeltSlot& Next = Slot.GetNext();
539  if (Next.IsValid())
540  {
541  return Next.GetIndex();
542  }
543  return InvalidSlotIndex;
544 }
545 
546 FORCEINLINE FBeltSlot&
548 {
549  return ((FBeltSlot&)Slot).GetNext();
550 }
551 
552 // BEGIN - Belt slot inlines.
553 
554 FORCEINLINE FBeltSlot::FBeltSlot(class UBelt* Belt) : Owner(Belt)
555 {
556  Index = Belt->Slots.Num();
557 }
558 
559 FORCEINLINE bool FBeltSlot::IsValid() const
560 {
561  return Subjective != nullptr && Owner != nullptr && Index >= 0 &&
562  Index < Owner->Num();
563 }
564 
565 FORCEINLINE bool FBeltSlot::IsBuffering() const
566 {
567  return GetOwner()->IsBuffering();
568 }
569 
570 FORCEINLINE const FFilter& FBeltSlot::GetFilter() const
571 {
572  return GetOwner()->GetFilter();
573 }
574 
575 // END - Belt slot inlines.
Definition: ApparatusRuntime.h:28
An interface for all sorts of subjects.
Definition: Subjective.h:42
The iterator for the belt.
Definition: Belt.h:120
bool operator==(const iterator &other) const
Definition: Belt.h:159
iterator operator++(int)
Get the next iterator.
Definition: Belt.h:150
FBeltSlot & operator*()
Definition: Belt.h:187
iterator & operator++()
Get the next iterator.
Definition: Belt.h:139
bool operator!=(const iterator &other) const
Definition: Belt.h:173
The conveyor belt consisting of subjects.
Definition: Belt.h:60
void BufferDetailsFromBelts(const TArray< class UBelt * > &Belts, const FFilter &TargetFilter)
Fetch the details from other belts, using the specified filter.
Definition: Belt.cpp:314
int32 Num() const
The number of slots currently in the belt.
Definition: Belt.h:242
static UDetail * GetDetailFromSlot(const FBeltSlot &Slot, const TSubclassOf< UDetail > DetailType)
Get a detail from a slot using a detail type.
Definition: Belt.h:481
int32 GetCount() const
Get the number of slots currently in the belt.
Definition: Belt.h:249
static FBeltSlot & GetNextSlot(const FBeltSlot &Slot)
Get the next iteratable slot.
Definition: Belt.h:547
static class UBelt * New(UObject *Owner, const FFingerprint &Fingerprint)
Create a new belt instance.
Definition: Belt.cpp:56
TScriptInterface< ISubjective > GetSubjectFromSlotAtIndex(const int32 SlotIndex)
Get the subject from a slot at specified index.
Definition: Belt.h:508
void FetchDetails()
Fetch all of the current active details in this belt.
Definition: Belt.cpp:267
iterator begin()
Get the first slot for iteration.
Definition: Belt.h:278
FBeltSlot & GetFirstSlot()
Get the first iteratable slot.
Definition: Belt.cpp:109
int32 GetNextSlotIndex(const int32 SlotIndex)
Get the next iteratable slot index.
Definition: Belt.h:531
static const int32 InvalidSlotIndex
Is this a special buffering belt?
Definition: Belt.h:96
static bool IsEndSlot(const FBeltSlot &Slot)
Get a detail from a slot using a detail type.
Definition: Belt.h:454
bool Expand(const FFingerprint &NewFingerprint, const EBootFilter BootFilter=EBootFilter::None)
Expand a belt to accommodate the new fingerprint.
Definition: Belt.cpp:87
int32 GetFirstSlotIndex()
Get the first iteratable slot.
Definition: Belt.h:515
FBeltSlot & GetEndSlot()
Get the ending iteratable slot.
Definition: Belt.h:452
iterator end()
The ending iterator.
Definition: Belt.h:291
bool Remove(TScriptInterface< ISubjective > Subjective)
Remove a subject from the belt.
Definition: Belt.cpp:144
UDetail * GetDetailFromSlotAtIndexHinted(const int32 SlotIndex, const TSubclassOf< UDetail > DetailType, const int32 IndexHint)
Get the detail from a slot at specified index with a hint.
Definition: Belt.h:496
void BufferDetailsFromBelt(UBelt *Belt, const FFilter &TargetFilter)
Fetch the details from another belt, using the specified filter.
Definition: Belt.cpp:288
bool IsBuffering() const
Is this a special belt, used for buffering other belts?
Definition: Belt.h:101
bool Matches(const FFilter &Filter) const
Check if the belt matches a filter.
Definition: Belt.h:461
static class UBelt * NewBuffering(UObject *Owner)
Create a new buffering belt instance.
Definition: Belt.cpp:80
const FFilter & GetFilter() const
The active filter of the belt.
Definition: Belt.h:111
static UDetail * GetDetailFromSlotByIndex(const FBeltSlot &Slot, const int32 DetailIndex)
Get a detail from a slot using an index.
Definition: Belt.h:474
FBeltSlot & operator[](int32 Index)
Get a belt slot by its index.
Definition: Belt.h:257
void Refresh(TScriptInterface< ISubjective > Subjective)
Refresh a subjective within the belt.
Definition: Belt.cpp:164
const FBeltSlot & operator[](int32 Index) const
Get a belt slot by its index.
Definition: Belt.h:268
bool IsSparse() const
Is this a sparse belt allowing some empty detail spaces?
Definition: Belt.h:106
UDetail * GetDetailFromSlotAtIndex(const int32 SlotIndex, const TSubclassOf< UDetail > DetailType) const
Get the detail from a slot at specified index.
Definition: Belt.h:488
The base subject detail (component) class.
Definition: Detail.h:35
The main Mechanism function library.
Definition: Mechanism.h:63
Definition: SubjectiveActorComponent.h:39
A UI widget subject functionality.
Definition: SubjectiveUserWidget.h:36
The belt slot, containing the cached details.
Definition: BeltSlot.h:40
class UBelt * GetOwner() const
Get the owning belt of the slot.
Definition: BeltSlot.h:96
UDetail * GetDetail(const int32 DetailIndex) const
Get the detail by its index.
Definition: BeltSlot.cpp:389
static const int32 InvalidIndex
Invalid belt index.
Definition: BeltSlot.h:48
TScriptInterface< class ISubjective > GetSubjective() const
Get the subjective of the slot.
Definition: BeltSlot.h:290
int32 GetIndex() const
Get the index of the slot in the belt.
Definition: BeltSlot.h:108
const FFilter & GetFilter() const
The active filter of the slot, which is the same as its owning belt's.
Definition: Belt.h:570
bool IsBuffering() const
Check if this is a buffering slot, part of the buffering belt.
Definition: Belt.h:565
FBeltSlot()
The default slot constructor.
Definition: BeltSlot.h:135
FBeltSlot & GetNext()
The next slot used for iteration.
Definition: BeltSlot.cpp:57
bool IsValid() const
Is this slot actually valid?
Definition: Belt.h:559
bool IncludesPartially(const FBitMask &BitMask) const
Check if the mask has any of the bits set in the supplied mask.
Definition: BitMask.h:260
bool Includes(const FBitMask &BitMask) const
Does the mask has all of the bits set in the supplied mask.
Definition: BitMask.h:241
The details filter specification.
Definition: Filter.h:44
const FBitMask & GetExcludedDetailsMask() const
Get the excluded details mask of the filter.
Definition: Filter.h:135
const FBitMask & GetDetailsMask() const
Get the included details mask of the filter.
Definition: Filter.h:130
bool Matches(const FFilter &Filter) const
Check if the filter matches an another filter.
Definition: Filter.h:640
The details fingerprint.
Definition: Fingerprint.h:117