Random Streams Ignore Initial Seed

While working with Blueprints in version 4.5.1 of the engine, I have noticed that random streams initialized with different seeds are generating the same sequence of numbers. For instance, the following output is from two separate streams, one initialized with seed 10, the other with seed 15.

LogBlueprintUserMessages: 10:  0.198346
LogBlueprintUserMessages: 15:  0.198346

LogBlueprintUserMessages: 10:  0.868304
LogBlueprintUserMessages: 15:  0.868304

LogBlueprintUserMessages: 10:  0.103444
LogBlueprintUserMessages: 15:  0.103444

LogBlueprintUserMessages: 10:  0.993975
LogBlueprintUserMessages: 15:  0.993975

Steps to reproduce:

  1. Open the level blueprint
  2. Create two variables of type RandomStream and initialize to two separate Random Streams with different initial seeds.
  3. Generate a sequence of random values from the two streams.

I have noticed this happening in class Blueprints as well.

We are having a similar issue. Waiting for others to respond…

I’ve found what’s causing this.
RandomFloatFromStream uses Stream.FRand() internally.
FRand() in turn calls GetFraction(), which uses MutateSeed() to set the seed to the next value.
MutateSeed does this:

Seed = (Seed * 196314165) + 907633515;

The problem being that the ‘Make RandomStream’ node doesn’t actually set Seed, it just sets InitialSeed (verified via debugger).

This of course means that (Seed * 196314165) becomes 0, so MutateSeed is always setting the seed to 0 + 907633515 , and of course having the same seed means you’re getting the same stream of random numbers.

Bad news is, I can’t directly fix this by altering a constructor or anything like that. The Make RandomStream node is actually a templated node that directly constructs a struct object (specified by the template) by building the instructions in bytecode directly, presumably for performance (take a look at FKCHandler_MakeStruct::Compile if you’re interested). This MakeStruct handler is a generic template, and it is essentially making a dumb assignment of each input pin into a variable of the struct based on pin names, and so I can’t alter it to store InitialSeed into Seed as well, which would fix the issue.

The simplest alternative fix would be to make a custom node which creates a FRandomStream, then either calls Initialize(InitialSeed), or sets InitialSeed directly and then calls Reset(). The issue then becomes how best to hide FRandomStream from the process which is automatically creating the current node. I’ve worked that out, and if I can get it working I will submit a pull request with the changes, but it probably won’t gracefully deprecate the existing faulty automatic node. That’s one I’ll leave for Epic to consider.

Edit: PR is [here][1] , if either of you want to take a look. I ran some fairly thorough tests and it seems to work fine, and the old Make node gives a warning.

TL;DR:
You can work around the issue until Epic decide what they want to do to resolve this, by using ‘Reset Random Stream’ on your random stream before you try to access any random numbers from it.

21592-resetrandom.png

Hey Guys-

We’ve seen’s pull request and it is under consideration. We should have more information on this problem in the near future.

Cheers