Randomize Array of FTransform and compare if the elements are duplicated C++?

I found the cause of the crash, I am not doing this correctly in C++

if (UDataTable *GetByAllRowNames = LoadObject<UDataTable>(GetWorld(), TEXT("/Game/DataTables/ItemsGeneration/Locationtesting")))
	{
		for (auto& Array : GetByAllRowNames->GetRowNames())
		{
			if (const UDataTable * FindInRows{ LoadObject<UDataTable>(GetWorld(), TEXT("/Game/DataTables/ItemsGeneration/Locationtesting")) })
			{
				if (const FST_ItemGroupLocation * OutRows{ FindInRows->FindRow<FST_ItemGroupLocation>(FName(Array), "") })
				{
					SpawnTransform = FTransform(OutRows->Location);

					FActorSpawnParameters SpawnInfo;
					SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
					TSubclassOf<AActor> AItemGroup = AActor::StaticClass();
					AActor* AActor_Ref = GetWorld()->SpawnActor<AActor>(AItemGroup, SpawnTransform, SpawnInfo);
				}
			}
		}
	}
}

getting wrong locations, don’t know from where, but these are not the locations stored in my data table.

DataTable
image_2022-08-16_192940937

this is how it is done in native code

AItemGroup* ItemGroupRef;
FVector OutRowLocations(EForceInit::ForceInit);
FTransform MakeTransform_Ret{};
AActor* BeginSpawnClass{};
AItemGroup* FinishSpawnClass{};

MakeTransform_Ret = UKismetMathLibrary::MakeTransform(OutRowLocations, FRotator(0.000000, 0.000000, 0.000000), FVector(1.000000, 1.000000, 1.000000));
BeginSpawnClass = UGameplayStatics::BeginDeferredActorSpawnFromClass(this, AItemGroup::StaticClass(), MakeTransform_Ret, ESpawnActorCollisionHandlingMethod::Undefined, ((AActor*)nullptr));
MakeTransform_Ret = UKismetMathLibrary::MakeTransform(OutRowLocations, FRotator(0.000000, 0.000000, 0.000000), FVector(1.000000, 1.000000, 1.000000));
FinishSpawnClass = CastChecked<AItemGroup>(UGameplayStatics::FinishSpawningActor(BeginSpawnClass, MakeTransform_Ret), ECastCheckedType::NullAllowed);
ItemGroupRef = FinishSpawnClass;

Thank You very much solving this Issue, already 3 days I were trying to solve this, Thank You very very much.
Finally I got randomized locations from the 5 rows of the data table and duplicated are automatically deleted. Amazing.

if (ItemGroupRef)
{ 
	for (auto& SpawnArrayElements : ItemsIDArr)
	{
	SpawnType = SpawnArrayElements.Type;
	SpawnID = SpawnArrayElements.ID; 
	
	ItemGroupRef->GetAllTransforms(Available);
	RandomLocation(Available, Location);
	
	if (UsedLocations.ContainsByPredicate([Location](const FTransform Transform)
	{
		return Transform.GetLocation() == Location.GetLocation()
			&& Transform.GetRotation() == Location.GetRotation()
			&& Transform.GetScale3D() == Location.GetScale3D();
	}))
	{
		RandomLocation(Available, Location);
	}
	else
	{
		SpawnLocation = Location;
		UsedLocations.Add(SpawnLocation);
	}
	//2
	FString SpawnLoc = SpawnLocation.ToString();
	printf100s("Spawn Location: %s", *SpawnLoc);
	}
	ItemsIDArr.Empty();
	print100s("---------------------------------------");
}

@zeaf your solution somehow works but it crash the engine on the second play.
Issue link

BTW, you can use Last Index instead of Length -1.

1 Like

What’s the crash stack

1 Like


image_2022-08-17_195400315

interesting what magic is used by blueprint library to do this comparison? I generated the native code for this function and it is using simple method.

case 87:
	{
		if(::IsValid(ItemGroupRef))
		{
			ItemGroupRef->GetAllTransforms(/*out*/ Available);
		}
		RandomLocation(/*out*/ Available, /*out*/ Location);
	}
case 88:
	{
		int Int_ArrayFind_Return = FCustomThunkTemplates::Array_Find(UsedLocations, Location);
		bool bIntEqualEqual_Ret = UKismetMathLibrary::EqualEqual_IntInt(Int_ArrayFind_Return, -1);
		if (!bIntEqualEqual_Ret)
		{
			__CurrentState = 87;
			break;
		}
	}

They are comparing memory as far as I can tell. Your code will still not do what you initially wanted it to do, not without a loop. Also, from what I see you are only using the location of the components, so your issues could be solved by just having an array of FVector that would have the locations from the transforms. But yeah, like I said, it’s very easy to do in blueprint using shuffle. If you switch to an array of FVector you can also write a simple shuffle function to solve basically all your issues and make the code a lot more readable

1 Like


my whole logic is depending on FTransform array

It’s just that from what I’ve seen you only use the location part of the Transforms, so you could ignore the rest and just store the location in the array

You mean return Transform.GetLocation() == Location.GetLocation(); in the solution you recently provided?

I mean instead of having an array of FTransform, have an array of FVector, and in your get all transforms function just do GetComponentLocation instead of GetComponentToWorld. If you’re not planning to use the rotations or scales of the components then you don’t need the transform really, location should be fine

FVector does have the == operator overloaded as well, so Contains will work out of the box, and you can easily write a shuffle function after that, similar to this post. Once you have the shuffled locations, then you just iterate through them using a for loop and spawn what you want to spawn

To be honest I don’t see why the shuffle method wouldn’t work on the FTransform array as well.

I will try for the next 24/hr if I can make the FTransform Array work, and if not the next hope I only have is the FVector Array.

yeah I tried the Shuffle on FTransform array and it works fine but it just randomizing the existing arrays, and not setting the range I think

Sir I finally fixed it, now it works perfectly as expected, Thank You once again , this is actually I solved by your help :slightly_smiling_face: , I am still using your solution but just getting Locations and commented Rotation/Scale

every random item has its own non-duplicated location. wow

You were absolutely right , it freezes the game if the location data table grows, I mean if I add more spawn locations to it.