As described by the licensee, the const CDO contract is being broken on ChaosWheeledVehicleMovementComponent. The issue the licensee is facing is that by spawning cars with different configurations, they change the CDO of the Wheels that are used by that car, which in turn affects all cars that use that same Wheel. The last spawned car overrides the values previously set and affects other cars.
On ChaosWheeledVehicleMovementComponent.cpp we fecth the CDO:
UChaosVehicleWheel* Wheel = WheelSetups[WheelIdx].WheelClass.GetDefaultObject();
// create Dynamic states passing in pointer to their Static setup data
Chaos::FSimpleWheelSim WheelSim(&Wheel->GetPhysicsWheelConfig());
Then AccessSetup() returns non-const:
FORCEINLINE T& AccessSetup()
When later calling AccessSetup().--- = something we are setting the value on the CDO:
WheelSim.AccessSetup().EngineEnabled = EngineEnable;
...
PWheel.AccessSetup().TorqueRatio = TorqueRatio;
This is particularly visible on the TorqueRatio as it affects the simulation:
PWheel.SetDriveTorque(TorqueMToCm(TransmissionTorque) * PWheel.Setup().TorqueRatio);
To verify this I've created a BlueprintFunctionLibrary UFUNCTION that sets the Torque on a UChaosWheeledVehicleMovementComponent using AccessSetup().TorqueRatio = TorqueRatio;
Create a new project from the VehicleTemplate
Create a BlueprintFunctionLibrary (BFL)
Create a function on the BFL:
UFUNCTION(BlueprintCallable)
static void SetupVehicle(class UChaosWheeledVehicleMovementComponent* MovementComponent, float TorqueRatio);
On SetupVehicle add:
for (int32 WheelIdx = 0; WheelIdx < MovementComponent->WheelSetups.Num(); ++WheelIdx)
{
UChaosVehicleWheel* Wheel = MovementComponent->WheelSetups[WheelIdx].WheelClass.GetDefaultObject();
Chaos::FSimpleWheelSim WheelSim(&Wheel->GetPhysicsWheelConfig());
if (Wheel->GetAxleType() != EAxleType::Undefined)
}
Add the includes:
#include "ChaosWheeledVehicleMovementComponent.h"
#include "WheelSystem.h"
Add the modules to project.Build.cs:
"ChaosVehicles", "ChaosVehiclesCore"
Compile and open the Editor
On the VehicleExampleMap spawn two SportsCar_Pawns
Select SportsCar_Pawn to be the AutoPossessPlayer = Player 0 and select SportsCar_Pawn_2, open the level blueprint, right-click and Create a Reference to SportsCar_Pawn_2
Pull from it and "Get Chaos Wheeled Vehicle Movement Component"
Add a Keyboard Key Event (for instance, bind it to key "1")
I've them added a FlipFlop node and on each end I set the TorqueRatio to a high (1000) and low (0) number to make the distinction noticeable
Play in Editor
Expected results: pressing 1 will change the torque on the SportsCar_Pawn_2 we are not controlling and should not affect the car we are controlling
Actual Results: changing the torque on SportsCar_Pawn_2 will change the torque on the SportsCar_Pawn we are controlling
> UnrealEditor-Case18601032_Car.dll!UMyBlueprintFunctionLibrary::SetupVehicle(UChaosWheeledVehicleMovementComponent * MovementComponent, float TorqueRatio) Line 16 C++
UnrealEditor-Case18601032_Car.dll!UMyBlueprintFunctionLibrary::execSetupVehicle(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 67 C++
UnrealEditor-CoreUObject.dll!UObject::execCallMathFunction(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 1079 C++
[Inline Frame] UnrealEditor-CoreUObject.dll!FFrame::Step(UObject *) Line 482 C++
UnrealEditor-CoreUObject.dll!ProcessLocalScriptFunction(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 1214 C++
UnrealEditor-CoreUObject.dll!ProcessScriptFunction<void (_cdecl*)(UObject *,FFrame &,void *)>(UObject * Context, UFunction * Function, FFrame & Stack, void * const Z_Param_Result, void[Image Removed](UObject *, FFrame &, void *) ExecFtor) Line 1043 C++
UnrealEditor-CoreUObject.dll!ProcessLocalFunction::__l2::<lambda_1>::operator()() Line 1286 C++
UnrealEditor-CoreUObject.dll!ProcessLocalFunction(UObject * Context, UFunction * Fn, FFrame & Stack, void * const Z_Param__Result) Line 1304 C++
[Inline Frame] UnrealEditor-CoreUObject.dll!FFrame::Step(UObject *) Line 482 C++
UnrealEditor-CoreUObject.dll!ProcessLocalScriptFunction(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 1214 C++
UnrealEditor-CoreUObject.dll!UObject::ProcessInternal(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 1336 C++
UnrealEditor-CoreUObject.dll!UFunction::Invoke(UObject * Obj, FFrame & Stack, void * const Z_Param__Result) Line 7192 C++
UnrealEditor-CoreUObject.dll!UObject::ProcessEvent(UFunction * Function, void * Parms) Line 2175 C++
UnrealEditor-Engine.dll!AActor::ProcessEvent(UFunction * Function, void * Parameters) Line 1160 C++
UnrealEditor-Engine.dll!TScriptDelegate<FNotThreadSafeDelegateMode>::ProcessDelegate<UObject>(void * Parameters) Line 449 C++
UnrealEditor-Engine.dll!FInputActionHandlerDynamicSignature_DelegateWrapper(const TScriptDelegate<FNotThreadSafeDelegateMode> & InputActionHandlerDynamicSignature, FKey Key) Line 73 C++
[Inline Frame] UnrealEditor-Engine.dll!FInputActionHandlerDynamicSignature::Execute(FKey) Line 127 C++
UnrealEditor-Engine.dll!FInputActionUnifiedDelegate::Execute(const FKey Key) Line 302 C++
UnrealEditor-Engine.dll!UPlayerInput::EvaluateInputDelegates(const TArray<UInputComponent *,TSizedDefaultAllocator<32>> & InputComponentStack, const float DeltaTime, const bool bGamePaused, const TArray<TTuple<FKey,FKeyState *>,TSizedDefaultAllocator<32>> & KeysWithEvents) Line 1549 C++
UnrealEditor-EnhancedInput.dll!UEnhancedPlayerInput::EvaluateInputDelegates(const TArray<UInputComponent *,TSizedDefaultAllocator<32>> & InputComponentStack, const float DeltaTime, const bool bGamePaused, const TArray<TTuple<FKey,FKeyState *>,TSizedDefaultAllocator<32>> & KeysWithEvents) Line 776 C++
UnrealEditor-Engine.dll!UPlayerInput::ProcessInputStack(const TArray<UInputComponent *,TSizedDefaultAllocator<32>> & InputComponentStack, const float DeltaTime, const bool bGamePaused) Line 1174 C++
UnrealEditor-Engine.dll!APlayerController::ProcessPlayerInput(const float DeltaTime, const bool bGamePaused) Line 2776 C++
UnrealEditor-Engine.dll!APlayerController::TickPlayerInput(const float DeltaSeconds, const bool bGamePaused) Line 5124 C++
UnrealEditor-Engine.dll!APlayerController::PlayerTick(float DeltaTime) Line 2380 C++
UnrealEditor-Engine.dll!APlayerController::TickActor(float DeltaSeconds, ELevelTick TickType, FActorTickFunction & ThisTickFunction) Line 5276 C++
UnrealEditor-Engine.dll!FActorTickFunction::ExecuteTick(float DeltaTime, ELevelTick TickType, ENamedThreads::Type CurrentThread, const TRefCountPtr<FBaseGraphTask> & MyCompletionGraphEvent) Line 284 C++
[Inline Frame] UnrealEditor-Engine.dll!FTickFunctionTask::DoTask(ENamedThreads::Type CurrentThread, const TRefCountPtr<FBaseGraphTask> &) Line 306 C++
UnrealEditor-Engine.dll!TGraphTask<FTickFunctionTask>::ExecuteTask() Line 634 C++
UnrealEditor-Core.dll!UE::Tasks::Private::FTaskBase::TryExecuteTask() Line 504 C++
[Inline Frame] UnrealEditor-Core.dll!FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> &) Line 482 C++
UnrealEditor-Core.dll!FNamedTaskThread::ProcessTasksNamedThread(int QueueIndex, bool bAllowStall) Line 779 C++
UnrealEditor-Core.dll!FNamedTaskThread::ProcessTasksUntilQuit(int QueueIndex) Line 668 C++
[Inline Frame] UnrealEditor-Core.dll!FTaskGraphCompatibilityImplementation::ProcessThreadUntilRequestReturn(ENamedThreads::Type) Line 1453 C++
UnrealEditor-Core.dll!FTaskGraphCompatibilityImplementation::WaitUntilTasksComplete(const TArray<TRefCountPtr<FBaseGraphTask>,TSizedInlineAllocator<4,32,TSizedDefaultAllocator<32>>> & Tasks, ENamedThreads::Type CurrentThreadIfKnown) Line 1526 C++
UnrealEditor-Engine.dll!FTickTaskSequencer::ReleaseTickGroup(ETickingGroup WorldTickGroup, bool bBlockTillComplete) Line 815 C++
UnrealEditor-Engine.dll!FTickTaskManager::RunTickGroup(ETickingGroup Group, bool bBlockTillComplete) Line 1866 C++
UnrealEditor-Engine.dll!UWorld::RunTickGroup(ETickingGroup Group, bool bBlockTillComplete) Line 774 C++
UnrealEditor-Engine.dll!UWorld::Tick(ELevelTick TickType, float DeltaSeconds) Line 1496 C++
UnrealEditor-UnrealEd.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 2140 C++
UnrealEditor-UnrealEd.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode) Line 550 C++
UnrealEditor.exe!FEngineLoop::Tick() Line 5877 C++
[Inline Frame] UnrealEditor.exe!EngineTick() Line 69 C++
UnrealEditor.exe!GuardedMain(const wchar_t * CmdLine) Line 188 C++
UnrealEditor.exe!LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) Line 266 C++
UnrealEditor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) Line 317 C++
[External Code]
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-274631 in the post.