Apparatus Version 1.0.0
ECS-like data-driven workflow for Unreal Engine.
Mechanical.h
1 /*
2  * ░▒▓ APPARATUS ▓▒░
3  *
4  * File: Mechanical.h
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:35:57 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 2021 - 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 #include "ApparatusRuntime.h"
30 
31 #include "Mechanical.generated.h"
32 
33 UINTERFACE(MinimalAPI, BlueprintType)
34 class UMechanical : public UInterface
35 {
36  GENERATED_BODY()
37 };
38 
42 class APPARATUSRUNTIME_API IMechanical
43 {
44  GENERATED_BODY()
45 
46  friend class UMechanism;
47 
48 protected:
49 
53  uint32 bInsideTick : 1;
54 
58  uint32 bInsideSteadyTick : 1;
59 
63  uint32 bInsidePresentationTick : 1;
64 
68  float PrevTime = NAN;
69 
73  int32 SteadyFrame = 0;
74 
78  int32 ProcessedSteadyFrame = -1;
79 
83  virtual UBelt* GetBufferingBelt() const
84  {
85  unimplemented();
86  return nullptr;
87  }
88 
95  virtual void DoTick(float NewTime,
96  float DeltaTime,
97  float SteadyDeltaTime);
98 
99  FORCEINLINE float
100  DoGetProcessedSteadyTime(float SteadyDeltaTime) const
101  {
102  if (ProcessedSteadyFrame == -1)
103  return NAN;
104  return ProcessedSteadyFrame * SteadyDeltaTime;
105  }
106 
107  virtual FORCEINLINE float
108  DoCalcSteadyFrameRatio(const float Time,
109  const float SteadyDeltaTime) const
110  {
111  if (!bInsidePresentationTick)
112  {
113  UE_LOG(LogApparatus, Error, TEXT("Steady Frame Ratio is only available during a presentation tick handling. "
114  "Are you using it within Steady ticking?"));
115  return 0;
116  }
117  check(ProcessedSteadyFrame != -1);
118  const float ProcessedSteadyTime = ProcessedSteadyFrame * SteadyDeltaTime;
119  if (Time >= ProcessedSteadyTime + SteadyDeltaTime)
120  return 1;
121  if (Time <= ProcessedSteadyTime)
122  return 0;
123  return (Time - ProcessedSteadyTime) / SteadyDeltaTime;
124  }
125 
126  virtual FORCEINLINE float
127  DoCalcSteadyFutureFactor(const float Time,
128  const float SteadyDeltaTime) const
129  {
130  if (!bInsidePresentationTick)
131  {
132  UE_LOG(LogApparatus, Error, TEXT("Steady Future Factor is only available during a presentation tick handling. "
133  "Are you using it within Steady ticking?"));
134  return 0;
135  }
136  if (!FMath::IsFinite(PrevTime))
137  {
138  return 0;
139  }
140  const float FutureSteadyTime = (ProcessedSteadyFrame + 1) * SteadyDeltaTime;
141  if (Time >= FutureSteadyTime)
142  return 1;
143  if (Time <= PrevTime)
144  return 0;
145  return (Time - PrevTime) / (FutureSteadyTime - PrevTime);
146  }
147 
148 public:
149 
153  UFUNCTION(BlueprintCallable, BlueprintNativeEvent,
154  Meta = (DisplayName = "Boot"),
155  Category = "Apparatus|Mechanism")
156  void ReceiveBoot();
157 
161  UFUNCTION(BlueprintCallable, BlueprintNativeEvent,
162  Meta = (DisplayName = "Input Tick"),
163  Category = "Apparatus|Mechanism")
164  void ReceiveInputTick();
165 
169  UFUNCTION(BlueprintCallable, BlueprintNativeEvent,
170  Meta = (DisplayName = "Steady Tick"),
171  Category = "Apparatus|Mechanism")
172  void ReceiveSteadyTick(float DeltaSeconds);
173 
181  UFUNCTION(BlueprintCallable, BlueprintNativeEvent,
182  Meta = (DisplayName = "Presentation Tick"),
183  Category = "Apparatus|Mechanism")
184  void ReceivePresentationTick(float DeltaSeconds, float FrameRatio, float FutureFactor);
185 
189  virtual FORCEINLINE void Boot()
190  {
191  Execute_ReceiveBoot(this->_getUObject());
192  }
193 
197  virtual FORCEINLINE void InputTick()
198  {
199  Execute_ReceiveInputTick(this->_getUObject());
200  }
201 
205  virtual FORCEINLINE void SteadyTick(float DeltaTime)
206  {
207  Execute_ReceiveSteadyTick(this->_getUObject(), DeltaTime);
208  }
209 
217  virtual void PresentationTick(float DeltaSeconds, float FrameRatio, float FutureFactor)
218  {
219  Execute_ReceivePresentationTick(this->_getUObject(), DeltaSeconds, FrameRatio, FutureFactor);
220  }
221 
222  FORCEINLINE IMechanical()
223  {
224  bInsideTick = false;
225  bInsideSteadyTick = false;
226  bInsidePresentationTick = false;
227  }
228 }; // class IMechanical
229 
230 inline void IMechanical::DoTick(float NewTime,
231  float DeltaTime,
232  float SteadyDeltaTime)
233 {
234  bInsideTick = true;
235  {
236  InputTick();
237  }
238 
239  const int32 NeededSteadyFrame = int32(NewTime / SteadyDeltaTime);
240 
241  if (ProcessedSteadyFrame != NeededSteadyFrame)
242  {
243  while (ProcessedSteadyFrame < NeededSteadyFrame)
244  {
245  if (ProcessedSteadyFrame == TNumericLimits<int32>::Max())
246  {
247  UE_LOG(LogApparatus, Fatal, TEXT("Steady frame count overflow detected. "
248  "Was your game session running for too long?"));
249  }
250 
252 
253  bInsideSteadyTick = true;
254  SteadyTick(SteadyDeltaTime);
255  bInsideSteadyTick = false;
256 
258  }
259  }
260 
262  AActor* Actor = Cast<AActor>(this);
263  if (Actor)
264  {
265  Actor->AActor::Tick(DeltaTime);
266  }
267 
268  {
269  PresentationTick(DeltaTime,
270  DoCalcSteadyFrameRatio(NewTime, SteadyDeltaTime),
271  DoCalcSteadyFutureFactor(NewTime, SteadyDeltaTime));
272  }
273  bInsidePresentationTick = false;
274 
275  PrevTime = NewTime;
276  bInsideTick = false;
277 }
A common interface for all mechanisms.
Definition: Mechanical.h:43
IMechanical()
Definition: Mechanical.h:222
int32 ProcessedSteadyFrame
The last, actually processed steady frame.
Definition: Mechanical.h:78
int32 SteadyFrame
The steady frame we are currently part of.
Definition: Mechanical.h:73
virtual void DoTick(float NewTime, float DeltaTime, float SteadyDeltaTime)
Perform a standard ticking routine.
Definition: Mechanical.h:230
virtual void InputTick()
Process a pre-steady input tick.
Definition: Mechanical.h:197
uint32 bInsidePresentationTick
Is this mechanism currently in the process of presentation ticking?
Definition: Mechanical.h:63
virtual void SteadyTick(float DeltaTime)
Process a fixed-rate steady tick.
Definition: Mechanical.h:205
float PrevTime
The game time of the previous tick.
Definition: Mechanical.h:68
virtual float DoCalcSteadyFutureFactor(const float Time, const float SteadyDeltaTime) const
Definition: Mechanical.h:127
uint32 bInsideSteadyTick
Is this mechanism currently in the process of steady ticking?
Definition: Mechanical.h:58
uint32 bInsideTick
Is this mechanism currently updating?
Definition: Mechanical.h:53
virtual void PresentationTick(float DeltaSeconds, float FrameRatio, float FutureFactor)
Process a past-steady presentation tick.
Definition: Mechanical.h:217
virtual float DoCalcSteadyFrameRatio(const float Time, const float SteadyDeltaTime) const
Definition: Mechanical.h:108
float DoGetProcessedSteadyTime(float SteadyDeltaTime) const
Definition: Mechanical.h:100
The conveyor belt consisting of subjects.
Definition: Belt.h:60
Definition: Mechanical.h:35
The main Mechanism function library.
Definition: Mechanism.h:63