UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SimCallbackObject.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2#pragma once
3
5#include "Chaos/Defines.h"
9#include "ChaosStats.h"
10#include "Chaos/PhysicsObject.h"
11
12// Enable through build or just here in code to cause an untracked callback to fail to compile
13// Untracked callbacks will show up a such in profiling sessions and this can help track them down
14#ifndef UE_CHAOS_UNTRACKED_CALLBACK_IS_ERROR
15#define UE_CHAOS_UNTRACKED_CALLBACK_IS_ERROR 0
16#endif
17
18namespace Chaos
19{
20class FPhysicsSolverBase;
21class FMidPhaseModifierAccessor;
22class FCCDModifierAccessor;
23class FStrainModifierAccessor;
24class FCollisionContactModifier;
25class FSingleParticlePhysicsProxy;
26
27namespace Utilities
28{
29 CHAOS_API FReal GetSolverPhysicsResultsTime(const FPhysicsSolverBase*);
30}
31
33{
34 None = 0,
35 Presimulate = 1 << 0,
36 MidPhaseModification = 1 << 1,
37 CCDModification = 1 << 2,
38 ContactModification = 1 << 3,
39 StrainModification = 1 << 5,
40 ParticleRegister = 1 << 6,
41 ParticleUnregister = 1 << 7,
42 RunOnFrozenGameThread = 1 << 8,
43 Rewind = 1 << 9,
45 PreIntegrate = 1 << 11,
46 PostIntegrate = 1 << 12,
47 PreSolve = 1 << 13,
48 PostSolve = 1 << 14,
49};
51
52
68{
69public:
70
71 //Destructor called on internal thread.
72 virtual ~ISimCallbackObject() = default;
73 ISimCallbackObject(const ISimCallbackObject&) = delete; //not copyable
74
76 FReal GetSimTime_Internal() const { return SimTime_Internal; }
77
79 FReal GetDeltaTime_Internal() const { return DeltaTime_Internal; }
80
81 virtual bool IsFAsyncObjectManagerCallback() const { return false;}
82
84 {
85 OnPostInitialize_Internal();
86 }
87
89 {
90 OnPreSimulate_Internal();
91 }
92
94 {
95 OnPreIntegrate_Internal();
96 }
97
99 {
100 OnPostIntegrate_Internal();
101 }
102
104 {
105 OnMidPhaseModification_Internal(Modifier);
106 }
107
109 {
110 OnCCDModification_Internal(Modifier);
111 }
112
114 {
115 OnStrainModification_Internal(Modifier);
116 }
117
119 {
120 OnContactModification_Internal(Modifier);
121 }
122
124 {
125 OnPreSolve_Internal();
126 }
127
129 {
130 OnPostSolve_Internal();
131 }
132
134 {
135 if(CurrentOutput_Internal)
136 {
137 OnFinalizeOutputData_Internal(CurrentOutput_Internal);
138 CurrentOutput_Internal = nullptr;
139 }
140 }
141
147
153
154#if STATS
158 TStatId GetStatId() const
159 {
160 static TStatId StatId = FDynamicStats::CreateStatId<FStatGroup_STATGROUP_Chaos>(GetFNameForStatId());
161 return StatId;
162 };
163#endif
164
168#if UE_CHAOS_UNTRACKED_CALLBACK_IS_ERROR
169 virtual FName GetFNameForStatId() const = 0;
170#else
171 virtual FName GetFNameForStatId() const
172 {
173 const static FLazyName StaticName("Untracked Physics Callback");
174 return StaticName;
175 }
176#endif
177
179 {
180 return Solver;
181 }
182
184 {
185 return Solver;
186 }
187
188 UE_DEPRECATED(5.5, "This callback was never called. Instead look at either ISimCallbackObject::ProcessInputs_External or FNetworkPhysicsCallback::InjectInputsExternal.")
189 virtual void InjectInputs_External(int32 PhysicsStep, int32 NumSteps) {}
190
193 virtual void ProcessInputs_Internal(int32 PhysicsStep) {}
194
197 virtual void ProcessInputs_External(int32 PhysicsStep) {}
198
203
205 {
206 ensure(false);
207 }
208
209 virtual void FirstPreResimStep_Internal(int32 PhysicsStep)
210 {}
211
213 {
214 return (Options & Option) == Option;
215 }
216
217 UE_DEPRECATED(5.1, "Use HasOption(ESimCallbackOptions::RunOnFrozenGameThread) instead.")
222
223protected:
224
226 : bPendingDelete(false)
227 , bPendingDelete_External(false)
228 , CurrentExternalInput_External(nullptr)
229 , Solver(nullptr)
230 , CurrentOutput_Internal(nullptr)
231 , CurrentInput_Internal(nullptr)
232 , Options(InOptions)
233 { }
234
235
236
240 CHAOS_API FSimCallbackInput* GetProducerInputData_External();
241
243 {
244 CurrentInput_Internal = NewInput;
245 }
246
248 {
249 SimTime_Internal = InSimTime;
250 DeltaTime_Internal = InDeltaTime;
251 }
252
253private:
254
260 virtual FSimCallbackInput* AllocateInputData_External() = 0;
261
265 virtual void OnPostInitialize_Internal() { }
266
270 virtual void OnPreSimulate_Internal()
271 {
272 check(false);
273 }
274
280 virtual void OnPreIntegrate_Internal()
281 {
282 check(false);
283 }
284
290 virtual void OnPostIntegrate_Internal()
291 {
292 check(false);
293 }
294
300 virtual void OnMidPhaseModification_Internal(FMidPhaseModifierAccessor& Modifier)
301 {
302 check(false);
303 }
304
310 virtual void OnCCDModification_Internal(FCCDModifierAccessor& Modifier)
311 {
312 check(false);
313 }
314
315 virtual void OnStrainModification_Internal(FStrainModifierAccessor& Modifier)
316 {
317 check(false);
318 }
319
325 virtual void OnContactModification_Internal(FCollisionContactModifier& Modifier)
326 {
327 //registered for contact modification, but implementation is missing
328 check(false);
329 }
330
336 virtual void OnPreSolve_Internal()
337 {
338 check(false);
339 }
340
346 virtual void OnPostSolve_Internal()
347 {
348 check(false);
349 }
350
355 virtual void OnParticlesRegistered_Internal(TArray<FSingleParticlePhysicsProxy*>& RegisteredProxies)
356 {
357 check(false);
358 }
359
364 virtual void OnParticleUnregistered_Internal(TArray<TTuple<Chaos::FUniqueIdx, FSingleParticlePhysicsProxy*>>& UnregisteredProxies)
365 {
366 check(false);
367 }
368
370 virtual void OnPhysicsObjectUnregistered_Internal(FConstPhysicsObjectHandle PhysicsObject)
371 {
372 check(false);
373 }
374
376 virtual void OnFinalizeOutputData_Internal(FSimCallbackOutput* CurOutput)
377 {
378 check(false); //wrote to output but not finalizing it. Typically this is pushed into some kind of thread safe queue
379 }
380
381 friend class FPBDRigidsSolver;
382 friend class FPhysicsSolverBase;
384 friend struct FPushPhysicsData;
385
386 bool bPendingDelete; //used internally for more efficient deletion. Callbacks do not need to check this
387 bool bPendingDelete_External; //used for efficient deletion. Callbacks do not need to check this
388
389 FSimCallbackInput* CurrentExternalInput_External; //the input currently being filled out by external thread
390 FPhysicsSolverBase* Solver;
391
392 //putting this here so that user classes don't have to bother with non-default constructor
393 void SetSolver_External(FPhysicsSolverBase* InSolver)
394 {
395 Solver = InSolver;
396 }
397
398 UE_DEPRECATED(5.1, "Do not change options after creation of the callback object - instead, specify them using the TOptions template parameter.")
399 void SetContactModification(bool InContactModification)
400 {
402 }
403
404protected:
405 FSimCallbackOutput* CurrentOutput_Internal; //the output currently being written to in this sim step
406
408 {
409 return CurrentInput_Internal;
410 }
411
412private:
413 FSimCallbackInput* CurrentInput_Internal; //the input associated with the step we are executing.
414
415 FReal SimTime_Internal;
416 FReal DeltaTime_Internal;
417
418 // TODO: Make this const and remove the "friend class FPhysicsSolverBase"
419 // once FPhysicsSolverBase::CreateAndRegisterSimCallbackObject_External(bool, bool)
420 // has been deprecated.
421 ESimCallbackOptions Options;
422 friend class FPhysicsSolverBase;
423};
424
427{
428public:
430 : Func(MoveTemp(InFunc))
431 , Func2(nullptr)
432 , bFuncHasTimeParameters(false)
433 , ExecuteOnStep(Step)
434 {
435 ensureMsgf(Func, TEXT("Created a sim callback object with an unbound function. This command will not be executed."));
436 }
437
439 : Func(nullptr)
440 , Func2(MoveTemp(InFunc))
441 , bFuncHasTimeParameters(true)
442 , ExecuteOnStep(Step)
443 {
444 ensureMsgf(Func2, TEXT("Created a sim callback object with an unbound function. This command will not be executed."));
445 }
446
448 {
449 //data management handled by command passed in (data should be copied by value as commands run async and memory lifetime is hard to predict)
450 check(false);
451 }
452
453 virtual FName GetFNameForStatId() const override
454 {
455 const static FLazyName StaticName("FSimCallbackCommandObject");
456 return StaticName;
457 }
458
459 const bool ShouldExecute(const int32 Step, const bool bIsResim) const
460 {
461 return bIsResim ? ExecuteOnStep == Step : ExecuteOnStep <= Step;
462 }
463
464 const bool ShouldDelay(const int32 Step, const bool bIsResim) const
465 {
466 return !bIsResim && ExecuteOnStep > Step;
467 }
468
470 {
471 return ExecuteOnStep;
472 }
473
474private:
475
476 virtual FSimCallbackInput* AllocateInputData_External()
477 {
478 //data management handled by command passed in (data should be copied by value as commands run async and memory lifetime is hard to predict)
479 check(false);
480 return nullptr;
481 }
482
483 virtual void FreeInputData_Internal(FSimCallbackInput* Input)
484 {
485 //data management handled by command passed in (data should be copied by value as commands run async and memory lifetime is hard to predict)
486 check(false);
487 }
488
489 virtual void OnPreSimulate_Internal() override
490 {
491 if (!bFuncHasTimeParameters)
492 {
493 if (ensureMsgf(Func, TEXT("The function of this sim callback object became unbound. This should not happen. This command will not be executed.")))
494 {
495 Func();
496 }
497 }
498 else
499 {
500 if (ensureMsgf(Func2, TEXT("The function of this sim callback object became unbound. This should not happen. This command will not be executed.")))
501 {
503 }
504 }
505
506 }
507
508 // Those two function could be in an union
509 TUniqueFunction<void()> Func;
511
512 bool bFuncHasTimeParameters;
513 int32 ExecuteOnStep;
514
515 friend struct FSimCallbackInput;
516};
517
519template <typename TInputType = FSimCallbackNoInput, typename TOutputType = FSimCallbackNoOutput, ESimCallbackOptions TOptions = ESimCallbackOptions::Presimulate>
521{
522public:
523
526 , CurrentOutput_External(nullptr)
527 { }
528
529 UE_DEPRECATED(5.1, "Use default constructor instead and specify RunFrozenOnGameThread using TOptions template parameter.")
534
536 {
537 auto Concrete = static_cast<TOutputType*>(Output);
538 Concrete->Reset();
539 OutputPool.Enqueue(Concrete);
540 }
541
549
554 {
555 return static_cast<const TInputType*>(GetCurrentInput_Internal());
556 }
557
563 {
565 if(!CurrentOutput_External)
566 {
567 OutputQueue.Dequeue(CurrentOutput_External);
568 }
569
570 if(CurrentOutput_External && CurrentOutput_External->InternalTime <= ResultsTime)
571 {
572 TOutputType* Output = CurrentOutput_External;
573 CurrentOutput_External = nullptr;
575 }
576 else
577 {
579 }
580 }
581
592 {
593 if (!CurrentOutput_External)
594 {
595 OutputQueue.Dequeue(CurrentOutput_External);
596 }
597
598 TOutputType* Output = CurrentOutput_External;
599 CurrentOutput_External = nullptr;
601 }
602
608 {
609 return OutputQueue.IsEmpty();
610 }
611
617 {
619 {
620 CurrentOutput_Internal = NewOutputData_Internal(GetSimTime_Internal());
621 }
622
623 return static_cast<TOutputType&>(*CurrentOutput_Internal);
624 }
625
626private:
627
628 TOutputType* NewOutputData_Internal(const FReal InternalTime)
629 {
630 auto NewOutput = NewDataHelper(OutputBacking, OutputPool);
631 NewOutput->InternalTime = InternalTime;
632 return NewOutput;
633 }
634
635 template <typename T>
637 {
638 T* Result;
639 if (!Queue.Dequeue(Result))
640 {
641 Backing.Emplace(new T());
642 Result = Backing.Last().Get();
643 }
644
645 return Result;
646 }
647
648 virtual void FreeInputData_Internal(FSimCallbackInput* Input) override
649 {
650 auto Concrete = static_cast<TInputType*>(Input);
651 Concrete->Reset();
652 InputPool.Enqueue(Concrete);
653 }
654
655 TInputType* NewInputData_External()
656 {
657 return NewDataHelper(InputBacking, InputPool);
658 }
659
660 virtual FSimCallbackInput* AllocateInputData_External() override
661 {
662 return NewInputData_External();
663 }
664
665 void OnFinalizeOutputData_Internal(FSimCallbackOutput* BaseOutput) override
666 {
667 OutputQueue.Enqueue(static_cast<TOutputType*>(BaseOutput));
668 }
669
671 TArray<TUniquePtr<TInputType>> InputBacking;
672
674 TArray<TUniquePtr<TOutputType>> OutputBacking;
675 TTransactionallySafeSpscQueue<TOutputType*> OutputQueue; //holds the outputs in order
676
677 TOutputType* CurrentOutput_External; //the earliest output we can consume
678};
679
685
686inline void FSimCallbackInput::Release_Internal(ISimCallbackObject& CallbackObj)
687{
688 //free once all steps are done with this input
689 ensure(NumSteps);
690 if(--NumSteps == 0)
691 {
692 CallbackObj.FreeInputData_Internal(this);
693 }
694}
695
696inline void FSimCallbackOutputHandle::Free_External()
697{
698 if (SimCallbackOutput)
699 {
700 SimCallbackObject->FreeOutputData_External(SimCallbackOutput);
701 }
702}
703
704}; // namespace Chaos
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define check(expr)
Definition AssertionMacros.h:314
#define ensureMsgf( InExpression, InFormat,...)
Definition AssertionMacros.h:465
#define ensure( InExpression)
Definition AssertionMacros.h:464
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define ENUM_CLASS_FLAGS(Enum)
Definition EnumClassFlags.h:6
return true
Definition ExternalRpcRegistry.cpp:601
const bool
Definition NetworkReplayStreaming.h:178
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint16_t uint16
Definition binka_ue_file_header.h:7
Definition CCDModification.h:181
Definition ChaosMarshallingManager.h:314
Definition ContactModification.h:512
Definition MidPhaseModification.h:157
Definition PBDRigidsSolver.h:84
Definition PhysicsSolverBase.h:313
Definition SimCallbackObject.h:427
FSimCallbackCommandObject(TUniqueFunction< void()> &&InFunc, int32 Step=INDEX_NONE)
Definition SimCallbackObject.h:429
const bool ShouldExecute(const int32 Step, const bool bIsResim) const
Definition SimCallbackObject.h:459
virtual void FreeOutputData_External(FSimCallbackOutput *Output)
Definition SimCallbackObject.h:447
const bool ShouldDelay(const int32 Step, const bool bIsResim) const
Definition SimCallbackObject.h:464
const int32 GetExecuteOnStep() const
Definition SimCallbackObject.h:469
virtual FName GetFNameForStatId() const override
Definition SimCallbackObject.h:453
FSimCallbackCommandObject(TUniqueFunction< void(FReal DeltaTime, FReal SimTime)> &&InFunc, int32 Step=INDEX_NONE)
Definition SimCallbackObject.h:438
friend struct FSimCallbackInput
Definition SimCallbackObject.h:515
Definition StrainModification.h:180
Definition SimCallbackObject.h:68
virtual FName GetFNameForStatId() const
Definition SimCallbackObject.h:171
bool RunOnFrozenGameThread() const
Definition SimCallbackObject.h:218
virtual void FreeOutputData_External(FSimCallbackOutput *Output)=0
FReal GetSimTime_Internal() const
Definition SimCallbackObject.h:76
virtual void FreeInputData_Internal(FSimCallbackInput *Input)=0
ISimCallbackObject(const ESimCallbackOptions InOptions=ESimCallbackOptions::Presimulate)
Definition SimCallbackObject.h:225
void MidPhaseModification_Internal(FMidPhaseModifierAccessor &Modifier)
Definition SimCallbackObject.h:103
void StrainModification_Internal(FStrainModifierAccessor &Modifier)
Definition SimCallbackObject.h:113
const FSimCallbackInput * GetCurrentInput_Internal() const
Definition SimCallbackObject.h:407
void FinalizeOutputData_Internal()
Definition SimCallbackObject.h:133
CHAOS_API FSimCallbackInput * GetProducerInputData_External()
Definition ChaosMarshallingManager.cpp:354
void CCDModification_Internal(FCCDModifierAccessor &Modifier)
Definition SimCallbackObject.h:108
void PostIntegrate_Internal()
Definition SimCallbackObject.h:98
void SetSimAndDeltaTime_Internal(const FReal InSimTime, const FReal InDeltaTime)
Definition SimCallbackObject.h:247
FPhysicsSolverBase * GetSolver()
Definition SimCallbackObject.h:178
const FPhysicsSolverBase * GetSolver() const
Definition SimCallbackObject.h:183
virtual void ApplyCorrections_Internal(int32 PhysicsStep, FSimCallbackInput *Input)
Definition SimCallbackObject.h:204
virtual void ProcessInputs_Internal(int32 PhysicsStep)
Definition SimCallbackObject.h:193
FReal GetDeltaTime_Internal() const
Definition SimCallbackObject.h:79
FSimCallbackOutput * CurrentOutput_Internal
Definition SimCallbackObject.h:405
void SetCurrentInput_Internal(FSimCallbackInput *NewInput)
Definition SimCallbackObject.h:242
bool HasOption(const ESimCallbackOptions Option) const
Definition SimCallbackObject.h:212
ISimCallbackObject(const ISimCallbackObject &)=delete
void PreIntegrate_Internal()
Definition SimCallbackObject.h:93
void PostSolve_Internal()
Definition SimCallbackObject.h:128
void PostInitialize_Internal()
Definition SimCallbackObject.h:83
void ContactModification_Internal(FCollisionContactModifier &Modifier)
Definition SimCallbackObject.h:118
virtual void FirstPreResimStep_Internal(int32 PhysicsStep)
Definition SimCallbackObject.h:209
virtual bool IsFAsyncObjectManagerCallback() const
Definition SimCallbackObject.h:81
void PreSimulate_Internal()
Definition SimCallbackObject.h:88
virtual ~ISimCallbackObject()=default
virtual void ProcessInputs_External(int32 PhysicsStep)
Definition SimCallbackObject.h:197
virtual int32 TriggerRewindIfNeeded_Internal(int32 LastCompletedStep)
Definition SimCallbackObject.h:199
void PreSolve_Internal()
Definition SimCallbackObject.h:123
Definition SimCallbackObject.h:521
bool IsOutputQueueEmpty_External() const
Definition SimCallbackObject.h:607
TSimCallbackObject()
Definition SimCallbackObject.h:524
TOutputType & GetProducerOutputData_Internal()
Definition SimCallbackObject.h:616
virtual void FreeOutputData_External(FSimCallbackOutput *Output) override
Definition SimCallbackObject.h:535
TInputType * GetProducerInputData_External()
Definition SimCallbackObject.h:545
TSimCallbackOutputHandle< TOutputType > PopFutureOutputData_External()
Definition SimCallbackObject.h:591
const TInputType * GetConsumerInput_Internal() const
Definition SimCallbackObject.h:553
TSimCallbackOutputHandle< TOutputType > PopOutputData_External()
Definition SimCallbackObject.h:562
Definition SimCallbackInput.h:141
Definition NameTypes.h:1680
Definition NameTypes.h:617
Definition Array.h:670
Definition TransactionallySafeSpscQueue.h:30
TOptional< ElementType > Dequeue()
Definition TransactionallySafeSpscQueue.h:84
Definition FunctionFwd.h:19
Definition UniquePtr.h:107
FReal GetSolverPhysicsResultsTime(const FPhysicsSolverBase *Solver)
Definition Utilities.cpp:18
Definition SkeletalMeshComponent.h:307
ESimCallbackOptions
Definition SimCallbackObject.h:33
FRealDouble FReal
Definition Real.h:22
const FPhysicsObject * FConstPhysicsObjectHandle
Definition PhysicsObject.h:19
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
@ false
Definition radaudio_common.h:23
Definition ChaosMarshallingManager.h:286
Definition SimCallbackObject.h:681
ISimCallbackObject * CallbackObject
Definition SimCallbackObject.h:682
FSimCallbackInput * Input
Definition SimCallbackObject.h:683
Definition SimCallbackInput.h:34
Definition SimCallbackInput.h:18
Definition LightweightStats.h:416
Definition Tuple.h:652