Download

[Tutorial] Shuffle TArray with RandomStream (generic blueprint node)

Hi all, I recently had the need to be able to shuffle an arbitrary array with FRandomStream to get deterministic ordering, however I couldn’t find a pre-built solution. So I spent a few hours studying the built-in array shuffle implementation and managed to create a blueprint node which takes a generic array as input. Throughout it I learned quite the bit about custom thunks and whatnot and I want to share this with everyone else in case you need to do something similar :).

I did a blog post detailing it and I want to avoid double posting so I’ll just paste the link here: http://masterkenth.com/ue4-shuffle-array-by-randomstream-c/.

For completeness sake though, here is the final code:

Header file


#pragma once
 
#include "Kismet/BlueprintFunctionLibrary.h"
#include "CppToBPFunctionLibrary.generated.h"
 
UCLASS()
class PROJECTSVS_API UCppToBPFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
	
	private:
 
		static void ShuffleArrayWithStream_impl(void* TargetArray, const UArrayProperty* ArrayProperty, const FRandomStream& Stream); // Real implementation
 
 
	public:
 
		UFUNCTION(BlueprintCallable, CustomThunk, meta = (DisplayName = "Shuffle by Stream", CompactNodeTitle = "SHUFFLESTREAM", ArrayParm = "TargetArray|ArrayProperty"), Category = "Utility")
		static void ShuffleArrayWithStream(const TArray<int32>& TargetArray, const UArrayProperty* ArrayProperty, const FRandomStream& Stream); // Stub function
 
		DECLARE_FUNCTION(execShuffleArrayWithStream)
		{
			Stack.StepCompiledIn<UArrayProperty>(NULL);
			void* ArrayAddr = Stack.MostRecentPropertyAddress;
 
			P_GET_OBJECT(UArrayProperty, ArrayProperty);
			P_GET_STRUCT_REF(FRandomStream, Stream);
			P_FINISH;
 
			ShuffleArrayWithStream_impl(ArrayAddr, ArrayProperty, Stream);
		}
};

Cpp file


#include "ProjectSVS.h"
#include "CppToBPFunctionLibrary.h"

void UCppToBPFunctionLibrary::ShuffleArrayWithStream(const TArray<int32>& TargetArray, const UArrayProperty* ArrayProperty, const FRandomStream& Stream)
{
	UE_LOG(LogTemp, Error, TEXT("Stub shuffle func called - should not happen"));
	check(0);
}

void UCppToBPFunctionLibrary::ShuffleArrayWithStream_impl(void* TargetArray, const UArrayProperty* ArrayProperty, const FRandomStream& Stream)
{
	FScriptArrayHelper ArrayHelper(ArrayProperty, TargetArray);
	int32 LastIndex = ArrayHelper.Num() - 1;

	for (int32 i = 0; i < LastIndex; ++i)
	{
		int32 Index = Stream.RandRange(0, LastIndex);
		if (i != Index)
		{
			ArrayHelper.SwapValues(i, Index);
		}
	}
}

I needed same thing…Just stumbled across this…

Thanks for sharing