Why is the if statement failed? C++

I am trying to translate this working BP script to C++.

Translation

RandomItemType(ItemType); //Randomize items by type
if (ItemsTypeArr.Find(ItemType) == -1) //check for duplicates
	{
		ItemsTypeArr.Add(ItemType); // add all items to array if not duplicated
	}
else if (ItemsTypeArr.Find(ItemType) != -1)//check for duplicates
	{
		RandomItemType(ItemType);//Re-randomize items to avoid any duplicate
	}

the goal is I have 20 groups of items, and the item should not be duplicated in its own group randomly.
the problem is executing this statement logs Array is out of range but in blueprints working fine.
Please correct me if I am not doing the logic correctly, thanks

You can use something like this, I used ECollisionChannel as my enum example
Be careful with this though because you might end up with an infinite loop, check first if your array can still take extra values otherwise the loop with always fail because the array is already filled with all possible options.

ECollisionChannel ItemType;
	do 
	{
		ItemType = RandomItemType();
	}while(ItemsTypeArr.Contains(ItemType));

	ItemsTypeArr.Add(ItemType); //Add the item
2 Likes

Imo the out of range error might be from RandomItemType(ItemType);.

1 Like

Thank you for reply, RandomItemType() is a return type function and returning the EItemType
and I need an extra local variable for it?

You need to store the returned value , if you call it again it will get you a new random type.

1 Like

yep , I am doing something wrong in this function itself , and I now believe that if statement has nothing to do with it… I will update the thread once I figure out the place of the bug

Ok, Thank you for pointing this out

1 Like


got engine crash on clicking play button, but the code compiles fine in VS

Can you show your RandomItemType() function ?

1 Like
void AMyGameMode::RandomItemType(EItemType& ItemType)
{
	TArray<EItemType> Arr{};
	TArray<FName> OutRowNames{};

	if (const UDataTable* DT_ItemTypeProbability = LoadObject<UDataTable>(NULL, TEXT("/Game/DataTables/DT_ItemTypeProbability")))
	{
		OutRowNames = DT_ItemTypeProbability->GetRowNames();
		for (auto& Array : OutRowNames)
		{
			if (const UDataTable* DT_ItemTypeProbability{ LoadObject<UDataTable>(GetWorld(), TEXT("/Game/DataTables/DT_ItemTypeProbability")) })
			{
				if (const FST_ItemTypeProbability * OutRow{ DT_ItemTypeProbability->FindRow<FST_ItemTypeProbability>(FName(Array), "") })
				{
					if (OutRow)
					{
						TypeProbabilityDatas = *OutRow;
						for (int32 i = 1; i < TypeProbabilityDatas.Percent; i++)
						{
							Arr.Add(TypeProbabilityDatas.Type);
						}
					}
				}
			}
		}
		FCustomThunkTemplates::Array_Shuffle(Arr);
		ItemType = Arr[FMath::RandRange(0, 99)];
	}
}

bp version in case if you want to see it visually

I see the random integer from 0 to 99 however you can’t guarantee that the array has a valid index, for this I would suggest doing something like to ensure the index is valid:
ItemType = Arr[FMath::RandRange(0, Arr.Num() - 1)];

This will limit the random integer to within range and should fix your out of bound issue.

Edit: changed my example to be similar to your Arr array.

1 Like

yes this out of bound issue is gone but crash on beginplay is still here :tired_face: don’t know what is wrong with my logics

Did you add the Do while example I provided ? it could be that infinite loop I was talking about.

no, I called this function alone and it works fine, when I call it in the main funciton GenerateItems(); the editor crashes

Let’s take a look at GenerateItems(); if you don’t mind.

1 Like
void AMyGameMode::GenerateItems()
{
	EItemType LocItemType{};
	int32 LocNumbers{};
	TArray<FName> OutRowNames{};
	TArray<EItemType> ItemsTypeArr{};
	(OutRowNames).Reset();

	if (UDataTable *DT_SpawnLocationLobby = LoadObject<UDataTable>(NULL, TEXT("/Game/DataTables/DT_ItemGroupSpawnLocationLobby")))
	{
		OutRowNames = DT_SpawnLocationLobby->GetRowNames();

		for (auto& Array : OutRowNames)
		{
			if (const UDataTable* DT_SpawnLocationLobby{ LoadObject<UDataTable>(GetWorld(), TEXT("/Game/DataTablesDT_ItemGroupSpawnLocationLobby")) })
			{
				if (const FST_ItemGroupLocation* OutRow{ DT_SpawnLocationLobby->FindRow<FST_ItemGroupLocation>(FName(Array), "") })
				{
					if (OutRow)
					{
						FVector Scale = FVector(1.000000, 1.000000, 1.000000);
						// SpawnTransform is the location + rotation + scale (absolute) of the spawn
						FTransform SpawnTransform = FTransform(GroupLocationDatas.Location);
						// SpawnInfo contains the Collision Handling Override
						FActorSpawnParameters SpawnInfo;
						SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
						// Spawn the actor
						TSubclassOf<AActor> AItemGroup = AActor::StaticClass();
						AActor* ItemGroupRef = GetWorld()->SpawnActor<AActor>(AItemGroup, SpawnTransform, SpawnInfo);
						RandomItemNumber(LocNumbers);
						for (auto i = 1; i <= LocNumbers; i++);
						//Randomizing the item types
						RandomItemType(LocItemType); //Randomize items by type
						if (ItemsTypeArr.Find(LocItemType) == -1) //check for duplicates
							{
								ItemsTypeArr.Add(LocItemType); // add all items to array if not duplicated
							}
						else if (ItemsTypeArr.Find(LocItemType) != -1)//check for duplicates
							{
								RandomItemType(LocItemType);//Re-randomize items to avoid any duplicate
							}

					}
				}
			}
		}

	}
}

I can show you the blueprint version if you want

Try adding a breakpoint in this function and see what triggers the crash. Does your blueprint work as intended ? share it as well why not.

1 Like

yes the blueprint works fine , and yes I will be debugging the code with breakpoints